From 18336c2b8e7e0a5e4685e18edb30683aa44fe8a7 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Tue, 20 Dec 2022 11:17:45 +0000 Subject: [PATCH 1/7] Update to dotnet 7. Change net461 to net462. Remove netcoreapp3.1 --- .github/workflows/dotnetcore.yml | 2 +- Directory.Build.props | 14 +++++++++ build/build.csproj | 6 ++-- global.json | 4 +-- src/SharpCompress/SharpCompress.csproj | 31 +++++++------------ .../SharpCompress.Test.csproj | 17 +++++----- 6 files changed, 40 insertions(+), 34 deletions(-) create mode 100644 Directory.Build.props diff --git a/.github/workflows/dotnetcore.yml b/.github/workflows/dotnetcore.yml index b29f37e7..6875f3ce 100644 --- a/.github/workflows/dotnetcore.yml +++ b/.github/workflows/dotnetcore.yml @@ -12,7 +12,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-dotnet@v3 with: - dotnet-version: 6.0.x + dotnet-version: 7.0.x - run: dotnet run -p build/build.csproj - uses: actions/upload-artifact@v3 with: diff --git a/Directory.Build.props b/Directory.Build.props new file mode 100644 index 00000000..4b343bf8 --- /dev/null +++ b/Directory.Build.props @@ -0,0 +1,14 @@ + + + latest + enable + Recommended + true + true + true + true + true + False + False + + diff --git a/build/build.csproj b/build/build.csproj index 792624f2..66d55099 100644 --- a/build/build.csproj +++ b/build/build.csproj @@ -2,13 +2,13 @@ Exe - net6.0 + net7.0 - + - + diff --git a/global.json b/global.json index a3bb3f5e..e6e67e4e 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "6.0.200", + "version": "7.0.101", "rollForward": "latestFeature" } -} \ No newline at end of file +} diff --git a/src/SharpCompress/SharpCompress.csproj b/src/SharpCompress/SharpCompress.csproj index 7be35930..c6c2f918 100644 --- a/src/SharpCompress/SharpCompress.csproj +++ b/src/SharpCompress/SharpCompress.csproj @@ -1,14 +1,12 @@ - + SharpCompress - Pure C# Decompression/Compression en-US - 0.32.2 - 0.32.2 - 0.32.2 + 0.33.0 + 0.33.0 + 0.33.0 Adam Hathcock - net461;netstandard2.0;netstandard2.1;netcoreapp3.1;net6.0 - true - false + net462;netstandard2.0;netstandard2.1;net6.0;net7.0 SharpCompress ../../SharpCompress.snk true @@ -19,30 +17,25 @@ Copyright (c) 2014 Adam Hathcock false false - SharpCompress is a compression library for NET Standard 2.0/2.1/NET 5.0 that can unrar, decompress 7zip, decompress xz, zip/unzip, tar/untar lzip/unlzip, bzip2/unbzip2 and gzip/ungzip with forward-only reading and file random access APIs. Write support for zip/tar/bzip2/gzip is implemented. - latest - enable - true + SharpCompress is a compression library for NET Standard 2.0/2.1/NET 6.0/NET 7.0 that can unrar, decompress 7zip, decompress xz, zip/unzip, tar/untar lzip/unlzip, bzip2/unbzip2 and gzip/ungzip with forward-only reading and file random access APIs. Write support for zip/tar/bzip2/gzip is implemented. true true snupkg true - False - False - + - + - - + + - - + + diff --git a/tests/SharpCompress.Test/SharpCompress.Test.csproj b/tests/SharpCompress.Test/SharpCompress.Test.csproj index a182e0a4..cbc76254 100644 --- a/tests/SharpCompress.Test/SharpCompress.Test.csproj +++ b/tests/SharpCompress.Test/SharpCompress.Test.csproj @@ -1,21 +1,20 @@  - net6.0;net461 + net7.0;net462 SharpCompress.Test - ../../SharpCompress.snk - true - true SharpCompress.Test - true - - - - + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + From d6ac9a03634905fc9d1cd214e489903a2ccff1a2 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Tue, 20 Dec 2022 13:09:16 +0000 Subject: [PATCH 2/7] Fix build --- .editorconfig | 44 ++++++++++++------- src/SharpCompress/AssemblyInfo.cs | 21 --------- .../Common/IExtractionListener.cs | 4 +- src/SharpCompress/Common/Rar/Headers/Flags.cs | 4 +- .../Common/Rar/Headers/IRarHeader.cs | 4 +- .../Common/Rar/Headers/RarHeaderFactory.cs | 14 +++--- .../Common/Zip/WinzipAesEncryptionData.cs | 4 ++ .../Compressors/Deflate/CRC32.cs | 5 ++- .../LZMA/Utilites/CrcCheckStream.cs | 3 +- .../Compressors/Rar/UnpackV2017/unpack_hpp.cs | 4 +- .../Compressors/Xz/BinaryUtils.cs | 3 +- src/SharpCompress/Compressors/Xz/Crc32.cs | 3 +- src/SharpCompress/Compressors/Xz/Crc64.cs | 3 +- .../Compressors/Xz/Filters/ArmFilter.cs | 2 +- .../Compressors/Xz/Filters/ArmThumbFilter.cs | 2 +- .../Compressors/Xz/Filters/BlockFilter.cs | 4 +- .../Compressors/Xz/Filters/IA64Filter.cs | 2 +- .../Compressors/Xz/Filters/Lzma2Filter.cs | 3 +- .../Compressors/Xz/Filters/PowerPCFilter.cs | 2 +- .../Compressors/Xz/Filters/SparcFilter.cs | 2 +- .../Compressors/Xz/Filters/X86Filter.cs | 2 +- src/SharpCompress/Compressors/Xz/XZBlock.cs | 4 +- src/SharpCompress/Crypto/Crc32Stream.cs | 3 +- src/SharpCompress/IO/RewindableStream.cs | 2 +- src/SharpCompress/IO/StreamingMode.cs | 4 +- src/SharpCompress/ReadOnlyCollection.cs | 4 +- .../Readers/IReaderExtractionListener.cs | 4 +- src/SharpCompress/Utility.cs | 3 +- tests/SharpCompress.Test/ADCTest.cs | 4 +- tests/SharpCompress.Test/ArchiveTests.cs | 28 ++++++------ .../SharpCompress.Test/Rar/RarArchiveTests.cs | 2 +- .../SharpCompress.Test/Rar/RarReaderTests.cs | 5 ++- tests/SharpCompress.Test/ReaderTests.cs | 2 +- .../SharpCompress.Test/Tar/TarReaderTests.cs | 5 ++- tests/SharpCompress.Test/TestBase.cs | 5 ++- tests/SharpCompress.Test/WriterTests.cs | 2 +- tests/SharpCompress.Test/Xz/XZBlockTests.cs | 2 +- tests/SharpCompress.Test/Xz/XZHeaderTests.cs | 6 +-- tests/SharpCompress.Test/Zip/Zip64Tests.cs | 2 +- .../SharpCompress.Test/Zip/ZipArchiveTests.cs | 6 +-- 40 files changed, 119 insertions(+), 109 deletions(-) diff --git a/.editorconfig b/.editorconfig index 28ede258..be296daf 100644 --- a/.editorconfig +++ b/.editorconfig @@ -195,8 +195,6 @@ csharp_prefer_static_local_function = true:warning csharp_prefer_simple_using_statement = true:suggestion dotnet_diagnostic.IDE0063.severity = suggestion -csharp_style_namespace_declarations = file_scoped - ########################################## # .NET Formatting Conventions # https://docs.microsoft.com/visualstudio/ide/editorconfig-code-style-settings-reference#formatting-conventions @@ -251,6 +249,8 @@ csharp_space_between_square_brackets = false csharp_preserve_single_line_statements = false csharp_preserve_single_line_blocks = true +csharp_style_namespace_declarations = file_scoped + ########################################## # .NET Naming Conventions # https://docs.microsoft.com/visualstudio/ide/editorconfig-naming-conventions @@ -260,11 +260,13 @@ csharp_preserve_single_line_blocks = true dotnet_diagnostic.CA1000.severity = suggestion dotnet_diagnostic.CA1001.severity = error dotnet_diagnostic.CA1018.severity = error +dotnet_diagnostic.CA1036.severity = silent dotnet_diagnostic.CA1051.severity = suggestion dotnet_diagnostic.CA1068.severity = error dotnet_diagnostic.CA1069.severity = error dotnet_diagnostic.CA1304.severity = error dotnet_diagnostic.CA1305.severity = suggestion +dotnet_diagnostic.CA1307.severity = suggestion dotnet_diagnostic.CA1309.severity = suggestion dotnet_diagnostic.CA1310.severity = error dotnet_diagnostic.CA1707.severity = suggestion @@ -283,6 +285,7 @@ dotnet_diagnostic.CA1829.severity = suggestion dotnet_diagnostic.CA1834.severity = error dotnet_diagnostic.CA1845.severity = suggestion dotnet_diagnostic.CA1848.severity = suggestion +dotnet_diagnostic.CA1852.severity = suggestion dotnet_diagnostic.CA2016.severity = suggestion dotnet_diagnostic.CA2201.severity = error dotnet_diagnostic.CA2206.severity = error @@ -295,6 +298,7 @@ dotnet_diagnostic.CA2254.severity = suggestion dotnet_diagnostic.CS0169.severity = error dotnet_diagnostic.CS0219.severity = error +dotnet_diagnostic.CS0649.severity = suggestion dotnet_diagnostic.CS1998.severity = error dotnet_diagnostic.CS8602.severity = error dotnet_diagnostic.CS8604.severity = error @@ -305,43 +309,53 @@ 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 dotnet_diagnostic.MVC1000.severity = suggestion -dotnet_diagnostic.IDE0055.severity = suggestion # Fix formatting -dotnet_diagnostic.IDE0023.severity = suggestion # use expression body for operators -dotnet_diagnostic.IDE0025.severity = suggestion # use expression body for properties -dotnet_diagnostic.IDE1006.severity = suggestion # Naming rule violation: These words cannot contain lower case characters -dotnet_diagnostic.IDE0072.severity = suggestion # Populate switch - forces population of all cases even when default specified -dotnet_diagnostic.IDE0027.severity = suggestion # Use expression body for accessors -dotnet_diagnostic.IDE0032.severity = suggestion # Use auto property -dotnet_diagnostic.IDE0007.severity = error # Use var -dotnet_diagnostic.IDE0160.severity = suggestion # Use block scoped -dotnet_diagnostic.IDE0011.severity = error # Use braces on if statements -dotnet_diagnostic.IDE0057.severity = suggestion # substring can be simplified +dotnet_diagnostic.RZ10012.severity = error + dotnet_diagnostic.IDE0004.severity = error # redundant cast +dotnet_diagnostic.IDE0005.severity = error +dotnet_diagnostic.IDE0007.severity = error # Use var +dotnet_diagnostic.IDE0011.severity = error # Use braces on if statements dotnet_diagnostic.IDE0010.severity = silent # populate switch +dotnet_diagnostic.IDE0017.severity = suggestion # initialization can be simplified dotnet_diagnostic.IDE0021.severity = silent # expression body for constructors dotnet_diagnostic.IDE0022.severity = silent # expression body for methods +dotnet_diagnostic.IDE0023.severity = suggestion # use expression body for operators 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.IDE0032.severity = suggestion # Use auto property dotnet_diagnostic.IDE0033.severity = error # prefer tuple name +dotnet_diagnostic.IDE0037.severity = suggestion # simplify anonymous type dotnet_diagnostic.IDE0040.severity = error # modifiers required dotnet_diagnostic.IDE0041.severity = error # simplify null dotnet_diagnostic.IDE0042.severity = error # deconstruct variable -dotnet_diagnostic.IDE0044.severity = error # make field only when possible +dotnet_diagnostic.IDE0044.severity = suggestion # make field only when possible dotnet_diagnostic.IDE0047.severity = suggestion # paratemeter name dotnet_diagnostic.IDE0051.severity = error # unused field dotnet_diagnostic.IDE0052.severity = error # unused member +dotnet_diagnostic.IDE0053.severity = suggestion # lambda not needed +dotnet_diagnostic.IDE0055.severity = suggestion # Fix formatting +dotnet_diagnostic.IDE0057.severity = suggestion # substring can be simplified dotnet_diagnostic.IDE0060.severity = suggestion # unused parameters +dotnet_diagnostic.IDE0061.severity = suggestion # local expression body +dotnet_diagnostic.IDE0062.severity = suggestion # local to static +dotnet_diagnostic.IDE0063.severity = error # simplify using 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 = suggestion # namespace folder structure dotnet_diagnostic.IDE0160.severity = silent # Use block namespaces ARE NOT required -dotnet_diagnostic.IDE0161.severity = suggestion # Please use file namespaces +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 ########################################## # Styles diff --git a/src/SharpCompress/AssemblyInfo.cs b/src/SharpCompress/AssemblyInfo.cs index 086b9adc..8c114539 100644 --- a/src/SharpCompress/AssemblyInfo.cs +++ b/src/SharpCompress/AssemblyInfo.cs @@ -1,24 +1,3 @@ using System; -using System.Reflection; -using System.Runtime.CompilerServices; -[assembly: AssemblyTitle("SharpCompress")] -[assembly: AssemblyProduct("SharpCompress")] -[assembly: InternalsVisibleTo("SharpCompress.Test" + SharpCompress.AssemblyInfo.PublicKeySuffix)] [assembly: CLSCompliant(true)] - -namespace SharpCompress -{ - /// - /// Just a static class to house the public key, to avoid repetition. - /// - internal static class AssemblyInfo - { - internal const string PublicKeySuffix = - ",PublicKey=002400000480000094000000060200000024000052534131000400000100010059acfa17d26c44" + - "7a4d03f16eaa72c9187c04f16e6569dd168b080e39a6f5c9fd00f28c768cd8e9a089d5a0e1b34c" + - "cd971488e7afe030ce5ce8df2053cf12ec89f6d38065c434c09ee6af3ee284c5dc08f44774b679" + - "bf39298e57efe30d4b00aecf9e4f6f8448b2cb0146d8956dfcab606cc64a0ac38c60a7d78b0d65" + - "d3b98dc0"; - } -} diff --git a/src/SharpCompress/Common/IExtractionListener.cs b/src/SharpCompress/Common/IExtractionListener.cs index b6fb50fc..3ec0abfb 100644 --- a/src/SharpCompress/Common/IExtractionListener.cs +++ b/src/SharpCompress/Common/IExtractionListener.cs @@ -1,8 +1,8 @@ namespace SharpCompress.Common { - internal interface IExtractionListener + public interface IExtractionListener { void FireFilePartExtractionBegin(string name, long size, long compressedSize); void FireCompressedBytesRead(long currentPartCompressedBytes, long compressedReadBytes); } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/Rar/Headers/Flags.cs b/src/SharpCompress/Common/Rar/Headers/Flags.cs index b6457661..7925ca5f 100644 --- a/src/SharpCompress/Common/Rar/Headers/Flags.cs +++ b/src/SharpCompress/Common/Rar/Headers/Flags.cs @@ -1,6 +1,6 @@ namespace SharpCompress.Common.Rar.Headers { - internal enum HeaderType : byte + public enum HeaderType : byte { Null, Mark, @@ -146,4 +146,4 @@ namespace SharpCompress.Common.Rar.Headers { public const ushort HAS_NEXT_VOLUME = 0x0001; } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/Rar/Headers/IRarHeader.cs b/src/SharpCompress/Common/Rar/Headers/IRarHeader.cs index 5d3433b7..a168690c 100644 --- a/src/SharpCompress/Common/Rar/Headers/IRarHeader.cs +++ b/src/SharpCompress/Common/Rar/Headers/IRarHeader.cs @@ -1,7 +1,7 @@ namespace SharpCompress.Common.Rar.Headers { - internal interface IRarHeader + public interface IRarHeader { HeaderType HeaderType { get; } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/Rar/Headers/RarHeaderFactory.cs b/src/SharpCompress/Common/Rar/Headers/RarHeaderFactory.cs index 6c8d5686..4ac686a2 100644 --- a/src/SharpCompress/Common/Rar/Headers/RarHeaderFactory.cs +++ b/src/SharpCompress/Common/Rar/Headers/RarHeaderFactory.cs @@ -5,21 +5,21 @@ using SharpCompress.Readers; namespace SharpCompress.Common.Rar.Headers { - internal class RarHeaderFactory + public class RarHeaderFactory { private bool _isRar5; - internal RarHeaderFactory(StreamingMode mode, ReaderOptions options) + public RarHeaderFactory(StreamingMode mode, ReaderOptions options) { StreamingMode = mode; Options = options; } - private ReaderOptions Options { get; } - internal StreamingMode StreamingMode { get; } - internal bool IsEncrypted { get; private set; } + public ReaderOptions Options { get; } + public StreamingMode StreamingMode { get; } + public bool IsEncrypted { get; private set; } - internal IEnumerable ReadHeaders(Stream stream) + public IEnumerable ReadHeaders(Stream stream) { var markHeader = MarkHeader.Read(stream, Options.LeaveStreamOpen, Options.LookForHeader); _isRar5 = markHeader.IsRar5; @@ -185,4 +185,4 @@ namespace SharpCompress.Common.Rar.Headers } } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/Zip/WinzipAesEncryptionData.cs b/src/SharpCompress/Common/Zip/WinzipAesEncryptionData.cs index e893adde..81c78503 100644 --- a/src/SharpCompress/Common/Zip/WinzipAesEncryptionData.cs +++ b/src/SharpCompress/Common/Zip/WinzipAesEncryptionData.cs @@ -52,7 +52,11 @@ namespace SharpCompress.Common.Zip 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); diff --git a/src/SharpCompress/Compressors/Deflate/CRC32.cs b/src/SharpCompress/Compressors/Deflate/CRC32.cs index d5e650c0..ac73e843 100644 --- a/src/SharpCompress/Compressors/Deflate/CRC32.cs +++ b/src/SharpCompress/Compressors/Deflate/CRC32.cs @@ -43,7 +43,8 @@ namespace SharpCompress.Compressors.Deflate /// directly by applications wishing to create, read, or manipulate zip archive /// files. /// - internal class CRC32 + [CLSCompliant(false)] + public class CRC32 { private const int BUFFER_SIZE = 8192; private static readonly UInt32[] crc32Table; @@ -290,4 +291,4 @@ namespace SharpCompress.Compressors.Deflate // private member vars } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/LZMA/Utilites/CrcCheckStream.cs b/src/SharpCompress/Compressors/LZMA/Utilites/CrcCheckStream.cs index d5e54728..9a59e26b 100644 --- a/src/SharpCompress/Compressors/LZMA/Utilites/CrcCheckStream.cs +++ b/src/SharpCompress/Compressors/LZMA/Utilites/CrcCheckStream.cs @@ -4,7 +4,8 @@ using System.IO; namespace SharpCompress.Compressors.LZMA.Utilites { - internal class CrcCheckStream : Stream + [CLSCompliant(false)] + public class CrcCheckStream : Stream { private readonly uint _mExpectedCrc; private uint _mCurrentCrc; diff --git a/src/SharpCompress/Compressors/Rar/UnpackV2017/unpack_hpp.cs b/src/SharpCompress/Compressors/Rar/UnpackV2017/unpack_hpp.cs index e28720d6..a0905ff4 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV2017/unpack_hpp.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV2017/unpack_hpp.cs @@ -57,7 +57,7 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 // Real size of DecodeNum table. public uint MaxNum; - // Left aligned start and upper limit codes defining code space + // Left aligned start and upper limit codes defining code space // ranges for bit lengths. DecodeLen[BitLength-1] defines the start of // range for bit length and DecodeLen[BitLength] defines next code // after the end of range or in other words the upper limit code @@ -65,7 +65,7 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 public readonly uint[] DecodeLen = new uint[16]; // Every item of this array contains the sum of all preceding items. - // So it contains the start position in code list for every bit length. + // So it contains the start position in code list for every bit length. public readonly uint[] DecodePos = new uint[16]; // Number of compressed bits processed in quick mode. diff --git a/src/SharpCompress/Compressors/Xz/BinaryUtils.cs b/src/SharpCompress/Compressors/Xz/BinaryUtils.cs index 12f34bf7..05f66c46 100644 --- a/src/SharpCompress/Compressors/Xz/BinaryUtils.cs +++ b/src/SharpCompress/Compressors/Xz/BinaryUtils.cs @@ -4,6 +4,7 @@ using System.IO; namespace SharpCompress.Compressors.Xz { + [CLSCompliant(false)] public static class BinaryUtils { public static int ReadLittleEndianInt32(this BinaryReader reader) @@ -44,7 +45,7 @@ namespace SharpCompress.Compressors.Xz return result; } - internal static byte[] ToLittleEndianBytes(this uint uint32) + public static byte[] ToLittleEndianBytes(this uint uint32) { var result = BitConverter.GetBytes(uint32); diff --git a/src/SharpCompress/Compressors/Xz/Crc32.cs b/src/SharpCompress/Compressors/Xz/Crc32.cs index 01a90791..51b4c7bf 100644 --- a/src/SharpCompress/Compressors/Xz/Crc32.cs +++ b/src/SharpCompress/Compressors/Xz/Crc32.cs @@ -4,7 +4,8 @@ using System; namespace SharpCompress.Compressors.Xz { - internal static class Crc32 + [CLSCompliant(false)] + public static class Crc32 { public const UInt32 DefaultPolynomial = 0xedb88320u; public const UInt32 DefaultSeed = 0xffffffffu; diff --git a/src/SharpCompress/Compressors/Xz/Crc64.cs b/src/SharpCompress/Compressors/Xz/Crc64.cs index 1cc9e1b3..1bea4a23 100644 --- a/src/SharpCompress/Compressors/Xz/Crc64.cs +++ b/src/SharpCompress/Compressors/Xz/Crc64.cs @@ -5,7 +5,8 @@ using System.Collections.Generic; namespace SharpCompress.Compressors.Xz { - internal static class Crc64 + [CLSCompliant(false)] + public static class Crc64 { public const UInt64 DefaultSeed = 0x0; diff --git a/src/SharpCompress/Compressors/Xz/Filters/ArmFilter.cs b/src/SharpCompress/Compressors/Xz/Filters/ArmFilter.cs index 9f8b5ad7..dac51743 100644 --- a/src/SharpCompress/Compressors/Xz/Filters/ArmFilter.cs +++ b/src/SharpCompress/Compressors/Xz/Filters/ArmFilter.cs @@ -14,7 +14,7 @@ using SharpCompress.Compressors.Filters; namespace SharpCompress.Compressors.Xz.Filters { - internal class ArmFilter : BlockFilter + public class ArmFilter : BlockFilter { public override bool AllowAsLast => false; diff --git a/src/SharpCompress/Compressors/Xz/Filters/ArmThumbFilter.cs b/src/SharpCompress/Compressors/Xz/Filters/ArmThumbFilter.cs index db79e5e9..2d6a87cd 100644 --- a/src/SharpCompress/Compressors/Xz/Filters/ArmThumbFilter.cs +++ b/src/SharpCompress/Compressors/Xz/Filters/ArmThumbFilter.cs @@ -14,7 +14,7 @@ using SharpCompress.Compressors.Filters; namespace SharpCompress.Compressors.Xz.Filters { - internal class ArmThumbFilter : BlockFilter + public class ArmThumbFilter : BlockFilter { public override bool AllowAsLast => false; diff --git a/src/SharpCompress/Compressors/Xz/Filters/BlockFilter.cs b/src/SharpCompress/Compressors/Xz/Filters/BlockFilter.cs index 2f7e2769..3cfdc6d6 100644 --- a/src/SharpCompress/Compressors/Xz/Filters/BlockFilter.cs +++ b/src/SharpCompress/Compressors/Xz/Filters/BlockFilter.cs @@ -4,8 +4,9 @@ using System.IO; namespace SharpCompress.Compressors.Xz.Filters { - internal abstract class BlockFilter : ReadOnlyStream + public abstract class BlockFilter : ReadOnlyStream { + [CLSCompliant(false)] public enum FilterTypes : ulong { DELTA = 0x03, @@ -36,7 +37,6 @@ namespace SharpCompress.Compressors.Xz.Filters public abstract void Init(byte[] properties); public abstract void ValidateFilter(); - public FilterTypes FilterType { get; set; } public static BlockFilter Read(BinaryReader reader) { var filterType = (FilterTypes)reader.ReadXZInteger(); diff --git a/src/SharpCompress/Compressors/Xz/Filters/IA64Filter.cs b/src/SharpCompress/Compressors/Xz/Filters/IA64Filter.cs index a4fb9f1f..5fb8b7d1 100644 --- a/src/SharpCompress/Compressors/Xz/Filters/IA64Filter.cs +++ b/src/SharpCompress/Compressors/Xz/Filters/IA64Filter.cs @@ -14,7 +14,7 @@ using SharpCompress.Compressors.Filters; namespace SharpCompress.Compressors.Xz.Filters { - internal class IA64Filter : BlockFilter + public class IA64Filter : BlockFilter { public override bool AllowAsLast => false; diff --git a/src/SharpCompress/Compressors/Xz/Filters/Lzma2Filter.cs b/src/SharpCompress/Compressors/Xz/Filters/Lzma2Filter.cs index 0a842f68..7e35187d 100644 --- a/src/SharpCompress/Compressors/Xz/Filters/Lzma2Filter.cs +++ b/src/SharpCompress/Compressors/Xz/Filters/Lzma2Filter.cs @@ -4,7 +4,8 @@ using SharpCompress.Compressors.LZMA; namespace SharpCompress.Compressors.Xz.Filters { - internal class Lzma2Filter : BlockFilter + [CLSCompliant(false)] + public class Lzma2Filter : BlockFilter { public override bool AllowAsLast => true; public override bool AllowAsNonLast => false; diff --git a/src/SharpCompress/Compressors/Xz/Filters/PowerPCFilter.cs b/src/SharpCompress/Compressors/Xz/Filters/PowerPCFilter.cs index 9c072521..3dfaed6d 100644 --- a/src/SharpCompress/Compressors/Xz/Filters/PowerPCFilter.cs +++ b/src/SharpCompress/Compressors/Xz/Filters/PowerPCFilter.cs @@ -14,7 +14,7 @@ using SharpCompress.Compressors.Filters; namespace SharpCompress.Compressors.Xz.Filters { - internal class PowerPCFilter : BlockFilter + public class PowerPCFilter : BlockFilter { public override bool AllowAsLast => false; diff --git a/src/SharpCompress/Compressors/Xz/Filters/SparcFilter.cs b/src/SharpCompress/Compressors/Xz/Filters/SparcFilter.cs index eb031e97..4f5e925d 100644 --- a/src/SharpCompress/Compressors/Xz/Filters/SparcFilter.cs +++ b/src/SharpCompress/Compressors/Xz/Filters/SparcFilter.cs @@ -14,7 +14,7 @@ using SharpCompress.Compressors.Filters; namespace SharpCompress.Compressors.Xz.Filters { - internal class SparcFilter : BlockFilter + public class SparcFilter : BlockFilter { public override bool AllowAsLast => false; diff --git a/src/SharpCompress/Compressors/Xz/Filters/X86Filter.cs b/src/SharpCompress/Compressors/Xz/Filters/X86Filter.cs index 43115e42..f5fcf924 100644 --- a/src/SharpCompress/Compressors/Xz/Filters/X86Filter.cs +++ b/src/SharpCompress/Compressors/Xz/Filters/X86Filter.cs @@ -14,7 +14,7 @@ using SharpCompress.Compressors.Filters; namespace SharpCompress.Compressors.Xz.Filters { - internal class X86Filter : BlockFilter + public class X86Filter : BlockFilter { public override bool AllowAsLast => false; diff --git a/src/SharpCompress/Compressors/Xz/XZBlock.cs b/src/SharpCompress/Compressors/Xz/XZBlock.cs index 6827093b..dc3a010d 100644 --- a/src/SharpCompress/Compressors/Xz/XZBlock.cs +++ b/src/SharpCompress/Compressors/Xz/XZBlock.cs @@ -1,5 +1,6 @@ #nullable disable +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -7,7 +8,8 @@ using SharpCompress.Compressors.Xz.Filters; namespace SharpCompress.Compressors.Xz { - internal sealed class XZBlock : XZReadOnlyStream + [CLSCompliant(false)] + public sealed class XZBlock : XZReadOnlyStream { public int BlockHeaderSize => (_blockHeaderSizeByte + 1) * 4; public ulong? CompressedSize { get; private set; } diff --git a/src/SharpCompress/Crypto/Crc32Stream.cs b/src/SharpCompress/Crypto/Crc32Stream.cs index 2651bfbb..635c4677 100644 --- a/src/SharpCompress/Crypto/Crc32Stream.cs +++ b/src/SharpCompress/Crypto/Crc32Stream.cs @@ -5,7 +5,8 @@ using System.IO; namespace SharpCompress.Crypto { - internal sealed class Crc32Stream : Stream + [CLSCompliant(false)] + public sealed class Crc32Stream : Stream { public const uint DefaultPolynomial = 0xedb88320u; public const uint DefaultSeed = 0xffffffffu; diff --git a/src/SharpCompress/IO/RewindableStream.cs b/src/SharpCompress/IO/RewindableStream.cs index fc430aae..c30efeb0 100644 --- a/src/SharpCompress/IO/RewindableStream.cs +++ b/src/SharpCompress/IO/RewindableStream.cs @@ -3,7 +3,7 @@ using System.IO; namespace SharpCompress.IO { - internal class RewindableStream : Stream + public class RewindableStream : Stream { private readonly Stream stream; private MemoryStream bufferStream = new MemoryStream(); diff --git a/src/SharpCompress/IO/StreamingMode.cs b/src/SharpCompress/IO/StreamingMode.cs index 29d3a147..d2a8a823 100644 --- a/src/SharpCompress/IO/StreamingMode.cs +++ b/src/SharpCompress/IO/StreamingMode.cs @@ -1,8 +1,8 @@ namespace SharpCompress.IO { - internal enum StreamingMode + public enum StreamingMode { Streaming, Seekable } -} \ No newline at end of file +} diff --git a/src/SharpCompress/ReadOnlyCollection.cs b/src/SharpCompress/ReadOnlyCollection.cs index 32c2abc8..a116a056 100644 --- a/src/SharpCompress/ReadOnlyCollection.cs +++ b/src/SharpCompress/ReadOnlyCollection.cs @@ -4,7 +4,7 @@ using System.Collections.Generic; namespace SharpCompress { - internal class ReadOnlyCollection : ICollection + public class ReadOnlyCollection : ICollection { private readonly ICollection collection; @@ -52,4 +52,4 @@ namespace SharpCompress throw new NotSupportedException(); } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Readers/IReaderExtractionListener.cs b/src/SharpCompress/Readers/IReaderExtractionListener.cs index 4a4adc4e..2edbef17 100644 --- a/src/SharpCompress/Readers/IReaderExtractionListener.cs +++ b/src/SharpCompress/Readers/IReaderExtractionListener.cs @@ -2,8 +2,8 @@ namespace SharpCompress.Readers { - internal interface IReaderExtractionListener : IExtractionListener + public interface IReaderExtractionListener : IExtractionListener { void FireEntryExtractionProgress(Entry entry, long sizeTransferred, int iterations); } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Utility.cs b/src/SharpCompress/Utility.cs index cbdb1ecb..3d6f3c58 100644 --- a/src/SharpCompress/Utility.cs +++ b/src/SharpCompress/Utility.cs @@ -6,7 +6,8 @@ using SharpCompress.Readers; namespace SharpCompress { - internal static class Utility + [CLSCompliant(false)] + public static class Utility { public static ReadOnlyCollection ToReadOnly(this ICollection items) { diff --git a/tests/SharpCompress.Test/ADCTest.cs b/tests/SharpCompress.Test/ADCTest.cs index 26ea2699..039260c4 100644 --- a/tests/SharpCompress.Test/ADCTest.cs +++ b/tests/SharpCompress.Test/ADCTest.cs @@ -46,7 +46,7 @@ namespace SharpCompress.Test { byte[] compressed = new byte[cmpFs.Length]; cmpFs.Read(compressed, 0, compressed.Length); - byte[] test; + byte[]? test; ADCBase.Decompress(compressed, out test); @@ -65,7 +65,7 @@ namespace SharpCompress.Test using (FileStream cmpFs = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "adc_compressed.bin"))) { - byte[] test; + byte[]? test; ADCBase.Decompress(cmpFs, out test); diff --git a/tests/SharpCompress.Test/ArchiveTests.cs b/tests/SharpCompress.Test/ArchiveTests.cs index 5c103b78..d93455c0 100644 --- a/tests/SharpCompress.Test/ArchiveTests.cs +++ b/tests/SharpCompress.Test/ArchiveTests.cs @@ -24,7 +24,7 @@ namespace SharpCompress.Test protected void ArchiveStreamReadExtractAll(string testArchive, CompressionType compression) { testArchive = Path.Combine(TEST_ARCHIVES_PATH, testArchive); - ArchiveStreamReadExtractAll(testArchive.AsEnumerable(), compression); + ArchiveStreamReadExtractAll(new[] { testArchive }, compression); } @@ -73,18 +73,18 @@ namespace SharpCompress.Test } } - protected void ArchiveStreamRead(string testArchive, ReaderOptions readerOptions = null) + protected void ArchiveStreamRead(string testArchive, ReaderOptions? readerOptions = null) { testArchive = Path.Combine(TEST_ARCHIVES_PATH, testArchive); - ArchiveStreamRead(readerOptions, testArchive.AsEnumerable()); + ArchiveStreamRead(readerOptions, testArchive); } - protected void ArchiveStreamRead(ReaderOptions readerOptions = null, params string[] testArchives) + protected void ArchiveStreamRead(ReaderOptions? readerOptions = null, params string[] testArchives) { ArchiveStreamRead(readerOptions, testArchives.Select(x => Path.Combine(TEST_ARCHIVES_PATH, x))); } - protected void ArchiveStreamRead(ReaderOptions readerOptions, IEnumerable testArchives) + protected void ArchiveStreamRead(ReaderOptions? readerOptions, IEnumerable testArchives) { foreach (var path in testArchives) { @@ -115,12 +115,12 @@ namespace SharpCompress.Test } } - protected void ArchiveStreamMultiRead(ReaderOptions readerOptions = null, params string[] testArchives) + protected void ArchiveStreamMultiRead(ReaderOptions? readerOptions = null, params string[] testArchives) { ArchiveStreamMultiRead(readerOptions, testArchives.Select(x => Path.Combine(TEST_ARCHIVES_PATH, x))); } - protected void ArchiveStreamMultiRead(ReaderOptions readerOptions, IEnumerable testArchives) + protected void ArchiveStreamMultiRead(ReaderOptions? readerOptions, IEnumerable testArchives) { using (var archive = ArchiveFactory.Open(testArchives.Select(a => new FileInfo(a)), readerOptions)) { @@ -144,14 +144,14 @@ namespace SharpCompress.Test VerifyFiles(); } - protected void ArchiveOpenStreamRead(ReaderOptions readerOptions = null, params string[] testArchives) + protected void ArchiveOpenStreamRead(ReaderOptions? readerOptions = null, params string[] testArchives) { ArchiveOpenStreamRead(readerOptions, testArchives.Select(x => Path.Combine(TEST_ARCHIVES_PATH, x))); } - protected void ArchiveOpenStreamRead(ReaderOptions readerOptions, IEnumerable testArchives) + protected void ArchiveOpenStreamRead(ReaderOptions? readerOptions, IEnumerable testArchives) { - using (var archive = ArchiveFactory.Open(testArchives.Select(f => new FileInfo(f)), null)) + using (var archive = ArchiveFactory.Open(testArchives.Select(f => new FileInfo(f)), readerOptions)) { try { @@ -173,16 +173,16 @@ namespace SharpCompress.Test VerifyFiles(); } - protected void ArchiveOpenEntryVolumeIndexTest(int[][] results, ReaderOptions readerOptions = null, params string[] testArchives) + protected void ArchiveOpenEntryVolumeIndexTest(int[][] results, ReaderOptions? readerOptions = null, params string[] testArchives) { ArchiveOpenEntryVolumeIndexTest(results, readerOptions, testArchives.Select(x => Path.Combine(TEST_ARCHIVES_PATH, x))); } - protected void ArchiveOpenEntryVolumeIndexTest(int[][] results, ReaderOptions readerOptions, IEnumerable testArchives) + protected void ArchiveOpenEntryVolumeIndexTest(int[][] results, ReaderOptions? readerOptions, IEnumerable testArchives) { string[] src = testArchives.ToArray(); - using (var archive = ArchiveFactory.Open(testArchives.Select(f => new FileInfo(f)), null)) + using (var archive = ArchiveFactory.Open(testArchives.Select(f => new FileInfo(f)), readerOptions)) { try { @@ -206,7 +206,7 @@ namespace SharpCompress.Test - protected void ArchiveFileRead(string testArchive, ReaderOptions readerOptions = null) + protected void ArchiveFileRead(string testArchive, ReaderOptions? readerOptions = null) { testArchive = Path.Combine(TEST_ARCHIVES_PATH, testArchive); using (var archive = ArchiveFactory.Open(testArchive, readerOptions)) diff --git a/tests/SharpCompress.Test/Rar/RarArchiveTests.cs b/tests/SharpCompress.Test/Rar/RarArchiveTests.cs index 3580aba3..3adf92ea 100644 --- a/tests/SharpCompress.Test/Rar/RarArchiveTests.cs +++ b/tests/SharpCompress.Test/Rar/RarArchiveTests.cs @@ -59,7 +59,7 @@ namespace SharpCompress.Test.Rar ReadRarPassword("Rar5.encrypted_filesAndHeader.rar", "test"); }*/ - private void ReadRarPassword(string testArchive, string password) + private void ReadRarPassword(string testArchive, string? password) { using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, testArchive))) using (var archive = RarArchive.Open(stream, new ReaderOptions() diff --git a/tests/SharpCompress.Test/Rar/RarReaderTests.cs b/tests/SharpCompress.Test/Rar/RarReaderTests.cs index 6affbc7b..0ac4e667 100644 --- a/tests/SharpCompress.Test/Rar/RarReaderTests.cs +++ b/tests/SharpCompress.Test/Rar/RarReaderTests.cs @@ -1,4 +1,5 @@ -using System.IO; +using System; +using System.IO; using System.Linq; using SharpCompress.Common; using SharpCompress.Readers; @@ -232,7 +233,7 @@ namespace SharpCompress.Test.Rar using (var entryStream = reader.OpenEntryStream()) { string file = Path.GetFileName(reader.Entry.Key); - string folder = Path.GetDirectoryName(reader.Entry.Key); + string folder = Path.GetDirectoryName(reader.Entry.Key) ?? throw new ArgumentNullException(); string destdir = Path.Combine(SCRATCH_FILES_PATH, folder); if (!Directory.Exists(destdir)) { diff --git a/tests/SharpCompress.Test/ReaderTests.cs b/tests/SharpCompress.Test/ReaderTests.cs index d5cfd9dd..4d230a20 100644 --- a/tests/SharpCompress.Test/ReaderTests.cs +++ b/tests/SharpCompress.Test/ReaderTests.cs @@ -9,7 +9,7 @@ namespace SharpCompress.Test { public abstract class ReaderTests : TestBase { - protected void Read(string testArchive, CompressionType expectedCompression, ReaderOptions options = null) + protected void Read(string testArchive, CompressionType expectedCompression, ReaderOptions? options = null) { testArchive = Path.Combine(TEST_ARCHIVES_PATH, testArchive); diff --git a/tests/SharpCompress.Test/Tar/TarReaderTests.cs b/tests/SharpCompress.Test/Tar/TarReaderTests.cs index 26e7b127..4e299dd2 100644 --- a/tests/SharpCompress.Test/Tar/TarReaderTests.cs +++ b/tests/SharpCompress.Test/Tar/TarReaderTests.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.IO; using SharpCompress.Common; using SharpCompress.Readers; @@ -85,7 +86,7 @@ namespace SharpCompress.Test.Tar using (var entryStream = reader.OpenEntryStream()) { string file = Path.GetFileName(reader.Entry.Key); - string folder = Path.GetDirectoryName(reader.Entry.Key); + string folder = Path.GetDirectoryName(reader.Entry.Key) ?? throw new ArgumentNullException(); string destdir = Path.Combine(SCRATCH_FILES_PATH, folder); if (!Directory.Exists(destdir)) { diff --git a/tests/SharpCompress.Test/TestBase.cs b/tests/SharpCompress.Test/TestBase.cs index 76a85c49..1ec9a376 100644 --- a/tests/SharpCompress.Test/TestBase.cs +++ b/tests/SharpCompress.Test/TestBase.cs @@ -21,7 +21,8 @@ namespace SharpCompress.Test public TestBase() { var index = AppDomain.CurrentDomain.BaseDirectory.IndexOf("SharpCompress.Test", StringComparison.OrdinalIgnoreCase); - SOLUTION_BASE_PATH = Path.GetDirectoryName(AppDomain.CurrentDomain.BaseDirectory.Substring(0, index)); + var path = AppDomain.CurrentDomain.BaseDirectory.Substring(0, index); + SOLUTION_BASE_PATH = Path.GetDirectoryName(path) ?? throw new ArgumentNullException(); TEST_ARCHIVES_PATH = Path.Combine(SOLUTION_BASE_PATH, "TestArchives", "Archives"); ORIGINAL_FILES_PATH = Path.Combine(SOLUTION_BASE_PATH, "TestArchives", "Original"); @@ -188,7 +189,7 @@ namespace SharpCompress.Test Assert.Equal(fi1.Attributes, fi2.Attributes); } - protected void CompareArchivesByPath(string file1, string file2, Encoding encoding = null) + protected void CompareArchivesByPath(string file1, string file2, Encoding? encoding = null) { ReaderOptions readerOptions = new ReaderOptions { LeaveStreamOpen = false }; readerOptions.ArchiveEncoding.Default = encoding ?? Encoding.Default; diff --git a/tests/SharpCompress.Test/WriterTests.cs b/tests/SharpCompress.Test/WriterTests.cs index 53c66307..c38fed29 100644 --- a/tests/SharpCompress.Test/WriterTests.cs +++ b/tests/SharpCompress.Test/WriterTests.cs @@ -16,7 +16,7 @@ namespace SharpCompress.Test this.type = type; } - protected void Write(CompressionType compressionType, string archive, string archiveToVerifyAgainst, Encoding encoding = null) + protected void Write(CompressionType compressionType, string archive, string archiveToVerifyAgainst, Encoding? encoding = null) { using (Stream stream = File.OpenWrite(Path.Combine(SCRATCH2_FILES_PATH, archive))) { diff --git a/tests/SharpCompress.Test/Xz/XZBlockTests.cs b/tests/SharpCompress.Test/Xz/XZBlockTests.cs index 50ac0cb1..97e2f704 100644 --- a/tests/SharpCompress.Test/Xz/XZBlockTests.cs +++ b/tests/SharpCompress.Test/Xz/XZBlockTests.cs @@ -43,7 +43,7 @@ namespace SharpCompress.Test.Xz [Fact] public void CrcIncorrectThrows() { - var bytes = Compressed.Clone() as byte[]; + var bytes = (byte[])Compressed.Clone(); bytes[20]++; using (Stream badCrcStream = new MemoryStream(bytes)) { diff --git a/tests/SharpCompress.Test/Xz/XZHeaderTests.cs b/tests/SharpCompress.Test/Xz/XZHeaderTests.cs index 1fa2a8b5..026c0c17 100644 --- a/tests/SharpCompress.Test/Xz/XZHeaderTests.cs +++ b/tests/SharpCompress.Test/Xz/XZHeaderTests.cs @@ -9,7 +9,7 @@ namespace SharpCompress.Test.Xz [Fact] public void ChecksMagicNumber() { - var bytes = Compressed.Clone() as byte[]; + var bytes = (byte[])Compressed.Clone(); bytes[3]++; using (Stream badMagicNumberStream = new MemoryStream(bytes)) { @@ -23,7 +23,7 @@ namespace SharpCompress.Test.Xz [Fact] public void CorruptHeaderThrows() { - var bytes = Compressed.Clone() as byte[]; + var bytes = (byte[])Compressed.Clone(); bytes[8]++; using (Stream badCrcStream = new MemoryStream(bytes)) { @@ -37,7 +37,7 @@ namespace SharpCompress.Test.Xz [Fact] public void BadVersionIfCrcOkButStreamFlagUnknown() { - var bytes = Compressed.Clone() as byte[]; + var bytes = (byte[])Compressed.Clone(); byte[] streamFlags = { 0x00, 0xF4 }; byte[] crc = Crc32.Compute(streamFlags).ToLittleEndianBytes(); streamFlags.CopyTo(bytes, 6); diff --git a/tests/SharpCompress.Test/Zip/Zip64Tests.cs b/tests/SharpCompress.Test/Zip/Zip64Tests.cs index 9a5210e5..8e683f9e 100644 --- a/tests/SharpCompress.Test/Zip/Zip64Tests.cs +++ b/tests/SharpCompress.Test/Zip/Zip64Tests.cs @@ -171,7 +171,7 @@ namespace SharpCompress.Test.Zip { long count = 0; long size = 0; - Common.Zip.ZipEntry prev = null; + Common.Zip.ZipEntry? prev = null; using (var fs = File.OpenRead(filename)) using (var rd = ZipReader.Open(fs, new ReaderOptions() { LookForHeader = false })) { diff --git a/tests/SharpCompress.Test/Zip/ZipArchiveTests.cs b/tests/SharpCompress.Test/Zip/ZipArchiveTests.cs index 4ad7e7db..07f158b1 100644 --- a/tests/SharpCompress.Test/Zip/ZipArchiveTests.cs +++ b/tests/SharpCompress.Test/Zip/ZipArchiveTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; using System.Linq; using System.Text; @@ -363,7 +363,7 @@ namespace SharpCompress.Test.Zip newFileName = newFileName.Substring(1); } newFileName = Path.Combine(SCRATCH_FILES_PATH, newFileName); - var newDir = Path.GetDirectoryName(newFileName); + var newDir = Path.GetDirectoryName(newFileName) ?? throw new ArgumentNullException(); if (!Directory.Exists(newDir)) { Directory.CreateDirectory(newDir); @@ -419,7 +419,7 @@ namespace SharpCompress.Test.Zip newFileName = newFileName.Substring(1); } newFileName = Path.Combine(SCRATCH_FILES_PATH, newFileName); - var newDir = Path.GetDirectoryName(newFileName); + var newDir = Path.GetDirectoryName(newFileName) ?? throw new ArgumentNullException(); if (!Directory.Exists(newDir)) { Directory.CreateDirectory(newDir); From 2dae2b798449b8c2506b1041e1e1a9b5d25c2200 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Tue, 20 Dec 2022 13:40:33 +0000 Subject: [PATCH 3/7] update build targets and CI --- .github/workflows/dotnetcore.yml | 7 ++++++- build/Program.cs | 6 +++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/.github/workflows/dotnetcore.yml b/.github/workflows/dotnetcore.yml index 6875f3ce..53aa0a9a 100644 --- a/.github/workflows/dotnetcore.yml +++ b/.github/workflows/dotnetcore.yml @@ -1,5 +1,10 @@ name: SharpCompress -on: [push, pull_request] +on: + push: + branches: + - 'master' + pull_request: + types: [ opened, synchronize, reopened, ready_for_review ] jobs: build: diff --git a/build/Program.cs b/build/Program.cs index f5c91cbe..f5a31098 100644 --- a/build/Program.cs +++ b/build/Program.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.Runtime.InteropServices; @@ -52,7 +52,7 @@ Target(Build, Target(Test, DependsOn(Build), - ForEach("net6.0", "net461"), + ForEach("net7.0", "net462"), framework => { IEnumerable GetFiles(string d) @@ -60,7 +60,7 @@ Target(Test, return Glob.Files(".", d); } - if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && framework == "net461") + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && framework == "net462") { return; } From 970e31a1b12e575fa3ef5f9fdaaaad9d640bd417 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Tue, 20 Dec 2022 13:45:47 +0000 Subject: [PATCH 4/7] cleanup and run csharpier --- .config/dotnet-tools.json | 6 +- .github/workflows/dotnetcore.yml | 2 +- build/Program.cs | 119 +- src/SharpCompress/Algorithms/Adler32.cs | 107 +- src/SharpCompress/Archives/AbstractArchive.cs | 47 +- .../Archives/AbstractWritableArchive.cs | 72 +- src/SharpCompress/Archives/ArchiveFactory.cs | 34 +- .../Archives/ArchiveVolumeFactory.cs | 11 +- .../Archives/GZip/GZipArchive.cs | 88 +- .../Archives/GZip/GZipArchiveEntry.cs | 5 +- .../Archives/GZip/GZipWritableArchiveEntry.cs | 11 +- src/SharpCompress/Archives/IArchive.cs | 4 +- src/SharpCompress/Archives/IArchiveEntry.cs | 2 +- .../Archives/IArchiveEntryExtensions.cs | 52 +- .../Archives/IArchiveExtensions.cs | 9 +- .../Archives/IArchiveExtractionListener.cs | 2 +- src/SharpCompress/Archives/IArchiveFactory.cs | 4 +- .../Archives/IMultiArchiveFactory.cs | 9 +- .../Archives/IWritableArchive.cs | 10 +- .../Archives/IWritableArchiveEntry.cs | 2 +- .../Archives/IWritableArchiveExtensions.cs | 63 +- .../Archives/Rar/FileInfoRarArchiveVolume.cs | 8 +- .../Archives/Rar/FileInfoRarFilePart.cs | 15 +- .../Archives/Rar/RarArchive.Extensions.cs | 2 +- src/SharpCompress/Archives/Rar/RarArchive.cs | 66 +- .../Archives/Rar/RarArchiveEntry.cs | 22 +- .../Archives/Rar/RarArchiveEntryFactory.cs | 14 +- .../Archives/Rar/RarArchiveVolumeFactory.cs | 30 +- .../Archives/Rar/SeekableFilePart.cs | 12 +- .../Archives/Rar/StreamRarArchiveVolume.cs | 12 +- .../Archives/SevenZip/SevenZipArchive.cs | 84 +- .../Archives/SevenZip/SevenZipArchiveEntry.cs | 5 +- src/SharpCompress/Archives/Tar/TarArchive.cs | 114 +- .../Archives/Tar/TarArchiveEntry.cs | 9 +- .../Archives/Tar/TarWritableArchiveEntry.cs | 12 +- src/SharpCompress/Archives/Zip/ZipArchive.cs | 129 +- .../Archives/Zip/ZipArchiveEntry.cs | 5 +- .../Archives/Zip/ZipArchiveVolumeFactory.cs | 18 +- .../Archives/Zip/ZipWritableArchiveEntry.cs | 11 +- src/SharpCompress/Common/ArchiveEncoding.cs | 9 +- src/SharpCompress/Common/ArchiveException.cs | 7 +- .../Common/ArchiveExtractionEventArgs.cs | 2 +- src/SharpCompress/Common/ArchiveType.cs | 2 +- .../Common/CompressedBytesReadEventArgs.cs | 7 +- src/SharpCompress/Common/CompressionType.cs | 2 +- .../Common/CryptographicException.cs | 7 +- src/SharpCompress/Common/Entry.cs | 5 +- src/SharpCompress/Common/EntryStream.cs | 12 +- .../Common/ExtractionException.cs | 12 +- src/SharpCompress/Common/ExtractionMethods.cs | 64 +- src/SharpCompress/Common/ExtractionOptions.cs | 13 +- .../FilePartExtractionBeginEventArgs.cs | 2 +- src/SharpCompress/Common/FlagUtility.cs | 24 +- src/SharpCompress/Common/GZip/GZipEntry.cs | 2 +- src/SharpCompress/Common/GZip/GZipFilePart.cs | 3 +- src/SharpCompress/Common/GZip/GZipVolume.cs | 4 +- src/SharpCompress/Common/IEntry.Extensions.cs | 10 +- .../Common/IncompleteArchiveException.cs | 7 +- .../Common/InvalidFormatException.cs | 12 +- .../Common/MultiVolumeExtractionException.cs | 11 +- .../MultipartStreamRequiredException.cs | 7 +- src/SharpCompress/Common/OptionsBase.cs | 5 +- .../Common/PasswordProtectedException.cs | 13 +- .../Common/Rar/Headers/AVHeader.cs | 2 +- .../Common/Rar/Headers/ArchiveCryptHeader.cs | 14 +- .../Common/Rar/Headers/ArchiveHeader.cs | 9 +- .../Common/Rar/Headers/CommentHeader.cs | 2 +- .../Common/Rar/Headers/EndArchiveHeader.cs | 6 +- .../Common/Rar/Headers/FileHeader.cs | 52 +- .../Common/Rar/Headers/FileNameDecoder.cs | 14 +- src/SharpCompress/Common/Rar/Headers/Flags.cs | 2 +- .../Common/Rar/Headers/MarkHeader.cs | 37 +- .../Common/Rar/Headers/NewSubHeaderType.cs | 2 +- .../Common/Rar/Headers/ProtectHeader.cs | 2 +- .../Common/Rar/Headers/RarHeader.cs | 8 +- .../Common/Rar/Headers/RarHeaderFactory.cs | 177 +- .../Common/Rar/Headers/SignHeader.cs | 2 +- .../Common/Rar/RarCrcBinaryReader.cs | 7 +- .../Common/Rar/RarCryptoBinaryReader.cs | 5 +- src/SharpCompress/Common/Rar/RarEntry.cs | 17 +- src/SharpCompress/Common/Rar/RarFilePart.cs | 3 +- src/SharpCompress/Common/Rar/RarRijndael.cs | 26 +- src/SharpCompress/Common/Rar/RarVolume.cs | 37 +- .../Common/ReaderExtractionEventArgs.cs | 2 +- .../Common/SevenZip/ArchiveDatabase.cs | 16 +- .../Common/SevenZip/ArchiveReader.cs | 316 ++- .../Common/SevenZip/CBindPair.cs | 2 +- .../Common/SevenZip/CCoderInfo.cs | 2 +- .../Common/SevenZip/CFileItem.cs | 2 +- .../Common/SevenZip/CMethodId.cs | 2 +- .../Common/SevenZip/CStreamSwitch.cs | 2 +- .../Common/SevenZip/DataReader.cs | 22 +- .../Common/SevenZip/SevenZipEntry.cs | 5 +- .../Common/SevenZip/SevenZipFilePart.cs | 40 +- .../Common/SevenZip/SevenZipVolume.cs | 4 +- .../Common/Tar/Headers/EntryType.cs | 2 +- .../Common/Tar/Headers/TarHeader.cs | 38 +- src/SharpCompress/Common/Tar/TarEntry.cs | 12 +- src/SharpCompress/Common/Tar/TarFilePart.cs | 5 +- .../Common/Tar/TarHeaderFactory.cs | 16 +- .../Common/Tar/TarReadOnlySubStream.cs | 12 +- src/SharpCompress/Common/Tar/TarVolume.cs | 4 +- src/SharpCompress/Common/Volume.cs | 5 +- .../Common/Zip/Headers/DirectoryEndHeader.cs | 14 +- .../Zip/Headers/DirectoryEntryHeader.cs | 21 +- .../Common/Zip/Headers/HeaderFlags.cs | 5 +- .../Common/Zip/Headers/IgnoreHeader.cs | 11 +- .../Common/Zip/Headers/LocalEntryHeader.cs | 14 +- .../Headers/LocalEntryHeaderExtraFactory.cs | 49 +- .../Common/Zip/Headers/SplitHeader.cs | 7 +- .../Zip/Headers/Zip64DirectoryEndHeader.cs | 14 +- .../Headers/Zip64DirectoryEndLocatorHeader.cs | 7 +- .../Common/Zip/Headers/ZipFileEntry.cs | 15 +- .../Common/Zip/Headers/ZipHeader.cs | 2 +- .../Common/Zip/Headers/ZipHeaderType.cs | 2 +- .../Zip/PkwareTraditionalCryptoStream.cs | 14 +- .../Zip/PkwareTraditionalEncryptionData.cs | 21 +- .../Common/Zip/SeekableZipFilePart.cs | 15 +- .../Common/Zip/SeekableZipHeaderFactory.cs | 22 +- .../Common/Zip/StreamingZipFilePart.cs | 18 +- .../Common/Zip/StreamingZipHeaderFactory.cs | 24 +- .../Common/Zip/WinzipAesCryptoStream.cs | 29 +- .../Common/Zip/WinzipAesEncryptionData.cs | 26 +- .../Common/Zip/WinzipAesKeySize.cs | 2 +- .../Common/Zip/ZipCompressionMethod.cs | 2 +- src/SharpCompress/Common/Zip/ZipEntry.cs | 53 +- src/SharpCompress/Common/Zip/ZipFilePart.cs | 180 +- .../Common/Zip/ZipHeaderFactory.cs | 146 +- src/SharpCompress/Common/Zip/ZipVolume.cs | 4 +- .../Compressors/ADC/ADCStream.cs | 15 +- .../Compressors/BZip2/BZip2Constants.cs | 566 ++++- .../Compressors/BZip2/BZip2Stream.cs | 14 +- .../Compressors/BZip2/CBZip2InputStream.cs | 156 +- .../Compressors/BZip2/CBZip2OutputStream.cs | 216 +- src/SharpCompress/Compressors/BZip2/CRC.cs | 258 ++- .../Compressors/CompressionMode.cs | 2 +- .../Compressors/Deflate/CRC32.cs | 12 +- .../Compressors/Deflate/DeflateManager.cs | 326 ++- .../Compressors/Deflate/DeflateStream.cs | 35 +- .../Compressors/Deflate/FlushType.cs | 6 +- .../Compressors/Deflate/GZipStream.cs | 41 +- .../Compressors/Deflate/InfTree.cs | 1934 +++++++++++++++-- .../Compressors/Deflate/Inflate.cs | 202 +- src/SharpCompress/Compressors/Deflate/Tree.cs | 995 +++++++-- src/SharpCompress/Compressors/Deflate/Zlib.cs | 800 ++++++- .../Compressors/Deflate/ZlibBaseStream.cs | 113 +- .../Compressors/Deflate/ZlibCodec.cs | 183 +- .../Compressors/Deflate/ZlibConstants.cs | 28 +- .../Compressors/Deflate/ZlibStream.cs | 26 +- .../Compressors/Deflate64/Deflate64Stream.cs | 28 +- .../Compressors/Deflate64/DeflateInput.cs | 3 +- .../Deflate64/FastEncoderStatus.cs | 941 +++++++- .../Compressors/Deflate64/HuffmanTree.cs | 26 +- .../Compressors/Deflate64/InflaterManaged.cs | 204 +- .../Compressors/Deflate64/InflaterState.cs | 28 +- .../Compressors/Deflate64/InputBuffer.cs | 15 +- .../Compressors/Deflate64/OutputWindow.cs | 12 +- .../Compressors/Filters/BCJ2Filter.cs | 31 +- .../Compressors/Filters/BCJFilter.cs | 32 +- .../Compressors/Filters/BranchExecFilter.cs | 94 +- .../Compressors/Filters/Filter.cs | 8 +- .../Compressors/LZMA/AesDecoderStream.cs | 10 +- .../Compressors/LZMA/Bcj2DecoderStream.cs | 8 +- .../Compressors/LZMA/BitVector.cs | 5 +- src/SharpCompress/Compressors/LZMA/CRC.cs | 8 +- .../Compressors/LZMA/DecoderStream.cs | 93 +- src/SharpCompress/Compressors/LZMA/ICoder.cs | 23 +- .../Compressors/LZMA/LZ/LzBinTree.cs | 55 +- .../Compressors/LZMA/LZ/LzInWindow.cs | 9 +- .../Compressors/LZMA/LZ/LzOutWindow.cs | 2 +- .../Compressors/LZMA/LZipStream.cs | 40 +- src/SharpCompress/Compressors/LZMA/Log.cs | 2 +- .../Compressors/LZMA/LzmaBase.cs | 6 +- .../Compressors/LZMA/LzmaDecoder.cs | 107 +- .../Compressors/LZMA/LzmaEncoder.cs | 603 +++-- .../Compressors/LZMA/LzmaEncoderProperties.cs | 57 +- .../Compressors/LZMA/LzmaStream.cs | 53 +- .../Compressors/LZMA/RangeCoder/RangeCoder.cs | 5 +- .../LZMA/RangeCoder/RangeCoderBit.cs | 22 +- .../LZMA/RangeCoder/RangeCoderBitTree.cs | 31 +- .../Compressors/LZMA/Registry.cs | 11 +- .../LZMA/Utilites/CrcBuilderStream.cs | 12 +- .../LZMA/Utilites/CrcCheckStream.cs | 10 +- .../LZMA/Utilites/IPasswordProvider.cs | 2 +- .../Compressors/PPMd/H/FreqData.cs | 5 +- .../Compressors/PPMd/H/ModelPPM.cs | 174 +- .../Compressors/PPMd/H/PPMContext.cs | 71 +- .../Compressors/PPMd/H/Pointer.cs | 5 +- .../Compressors/PPMd/H/RangeCoder.cs | 26 +- .../Compressors/PPMd/H/RarMemBlock.cs | 15 +- .../Compressors/PPMd/H/RarNode.cs | 5 +- .../Compressors/PPMd/H/SEE2Context.cs | 20 +- src/SharpCompress/Compressors/PPMd/H/State.cs | 18 +- .../Compressors/PPMd/H/StateRef.cs | 14 +- .../Compressors/PPMd/H/SubAllocator.cs | 46 +- .../Compressors/PPMd/I1/Allocator.cs | 35 +- .../Compressors/PPMd/I1/Coder.cs | 16 +- .../Compressors/PPMd/I1/MemoryNode.cs | 27 +- .../Compressors/PPMd/I1/Model.cs | 154 +- .../PPMd/I1/ModelRestorationMethod.cs | 2 +- .../Compressors/PPMd/I1/Pointer.cs | 48 +- .../Compressors/PPMd/I1/PpmContext.cs | 187 +- .../Compressors/PPMd/I1/PpmState.cs | 25 +- .../Compressors/PPMd/I1/See2Context.cs | 2 +- .../Compressors/PPMd/PpmdProperties.cs | 27 +- .../Compressors/PPMd/PpmdStream.cs | 12 +- .../Compressors/PPMd/PpmdVersion.cs | 2 +- .../Rar/MultiVolumeReadOnlyStream.cs | 40 +- src/SharpCompress/Compressors/Rar/RarCRC.cs | 2 +- .../Compressors/Rar/RarCrcStream.cs | 9 +- .../Compressors/Rar/RarStream.cs | 17 +- .../Rar/UnpackV1/Decode/AudioVariables.cs | 2 +- .../Rar/UnpackV1/Decode/BitDecode.cs | 7 +- .../Rar/UnpackV1/Decode/CodeType.cs | 2 +- .../Compressors/Rar/UnpackV1/Decode/Decode.cs | 7 +- .../Rar/UnpackV1/Decode/DistDecode.cs | 7 +- .../Rar/UnpackV1/Decode/FilterType.cs | 13 +- .../Rar/UnpackV1/Decode/LitDecode.cs | 7 +- .../Rar/UnpackV1/Decode/LowDistDecode.cs | 7 +- .../Rar/UnpackV1/Decode/MultDecode.cs | 7 +- .../Rar/UnpackV1/Decode/PackDef.cs | 3 +- .../Rar/UnpackV1/Decode/RepDecode.cs | 7 +- .../Rar/UnpackV1/PPM/BlockTypes.cs | 2 +- .../Compressors/Rar/UnpackV1/Unpack.cs | 115 +- .../Compressors/Rar/UnpackV1/Unpack15.cs | 216 +- .../Compressors/Rar/UnpackV1/Unpack20.cs | 190 +- .../Compressors/Rar/UnpackV1/Unpack50.cs | 112 +- .../Compressors/Rar/UnpackV1/UnpackFilter.cs | 14 +- .../Compressors/Rar/UnpackV1/UnpackInline.cs | 3 +- .../Compressors/Rar/UnpackV1/UnpackUtility.cs | 20 +- .../Rar/UnpackV2017/BitInput.getbits_cpp.cs | 9 +- .../Rar/UnpackV2017/BitInput.getbits_hpp.cs | 7 +- .../FragmentedWindow.unpack50frag_cpp.cs | 21 +- .../Rar/UnpackV2017/PackDef.compress_hpp.cs | 2 - .../Compressors/Rar/UnpackV2017/Unpack.cs | 14 +- .../Rar/UnpackV2017/Unpack.rawint_hpp.cs | 5 +- .../Rar/UnpackV2017/Unpack.unpack15_cpp.cs | 232 +- .../Rar/UnpackV2017/Unpack.unpack20_cpp.cs | 189 +- .../Rar/UnpackV2017/Unpack.unpack30_cpp.cs | 8 +- .../Rar/UnpackV2017/Unpack.unpack50_cpp.cs | 122 +- .../Rar/UnpackV2017/Unpack.unpack_cpp.cs | 67 +- .../UnpackV2017/Unpack.unpackinline_cpp.cs | 6 +- .../Compressors/Rar/VM/BitInput.cs | 34 +- src/SharpCompress/Compressors/Rar/VM/RarVM.cs | 458 ++-- .../Compressors/Rar/VM/VMCmdFlags.cs | 31 +- .../Compressors/Rar/VM/VMCommands.cs | 23 +- .../Compressors/Rar/VM/VMFlags.cs | 2 +- .../Compressors/Rar/VM/VMOpType.cs | 2 +- .../Compressors/Rar/VM/VMPreparedCommand.cs | 2 +- .../Compressors/Rar/VM/VMPreparedOperand.cs | 2 +- .../Compressors/Rar/VM/VMPreparedProgram.cs | 2 +- .../Rar/VM/VMStandardFilterSignature.cs | 2 +- .../Compressors/Rar/VM/VMStandardFilters.cs | 2 +- .../Compressors/Xz/BinaryUtils.cs | 1 + src/SharpCompress/Compressors/Xz/CheckType.cs | 2 +- src/SharpCompress/Compressors/Xz/Crc64.cs | 1 - .../Compressors/Xz/Filters/ArmFilter.cs | 5 +- .../Compressors/Xz/Filters/ArmThumbFilter.cs | 6 +- .../Compressors/Xz/Filters/BlockFilter.cs | 25 +- .../Compressors/Xz/Filters/IA64Filter.cs | 6 +- .../Compressors/Xz/Filters/Lzma2Filter.cs | 4 +- .../Compressors/Xz/Filters/PowerPCFilter.cs | 1 - .../Compressors/Xz/Filters/SparcFilter.cs | 14 +- .../Compressors/Xz/Filters/X86Filter.cs | 5 +- src/SharpCompress/Compressors/Xz/XZBlock.cs | 21 +- src/SharpCompress/Compressors/Xz/XZFooter.cs | 4 +- src/SharpCompress/Compressors/Xz/XZHeader.cs | 4 +- src/SharpCompress/Compressors/Xz/XZIndex.cs | 5 +- .../Xz/XZIndexMarkerReachedException.cs | 4 +- src/SharpCompress/Compressors/Xz/XZStream.cs | 9 +- src/SharpCompress/Crypto/Crc32Stream.cs | 17 +- src/SharpCompress/Crypto/CryptoException.cs | 22 +- .../Crypto/DataLengthException.cs | 23 +- src/SharpCompress/Crypto/IBlockCipher.cs | 2 +- src/SharpCompress/Crypto/ICipherParameters.cs | 6 +- src/SharpCompress/Crypto/KeyParameter.cs | 13 +- src/SharpCompress/Crypto/RijndaelEngine.cs | 1530 +++++++++++-- src/SharpCompress/Factories/Factory.cs | 12 +- src/SharpCompress/Factories/GZipFactory.cs | 27 +- src/SharpCompress/Factories/IFactory.cs | 3 +- src/SharpCompress/Factories/RarFactory.cs | 9 +- .../Factories/SevenZipFactory.cs | 16 +- src/SharpCompress/Factories/TarFactory.cs | 33 +- src/SharpCompress/Factories/ZipFactory.cs | 21 +- src/SharpCompress/IO/BufferedSubStream.cs | 11 +- .../IO/CountingWritableSubStream.cs | 12 +- src/SharpCompress/IO/ListeningStream.cs | 18 +- src/SharpCompress/IO/MarkingBinaryReader.cs | 13 +- src/SharpCompress/IO/NonDisposingStream.cs | 15 +- src/SharpCompress/IO/ReadOnlySubStream.cs | 14 +- src/SharpCompress/IO/RewindableStream.cs | 1 - src/SharpCompress/IO/SourceStream.cs | 44 +- src/SharpCompress/Lazy.cs | 2 +- .../Polyfills/StringExtensions.cs | 2 +- src/SharpCompress/Readers/AbstractReader.cs | 73 +- src/SharpCompress/Readers/GZip/GZipReader.cs | 3 +- src/SharpCompress/Readers/IReader.cs | 2 +- .../Readers/IReaderExtensions.cs | 52 +- src/SharpCompress/Readers/IReaderFactory.cs | 1 - .../Readers/Rar/MultiVolumeRarReader.cs | 29 +- .../Readers/Rar/NonSeekableStreamFilePart.cs | 7 +- src/SharpCompress/Readers/Rar/RarReader.cs | 20 +- .../Readers/Rar/RarReaderEntry.cs | 2 +- .../Readers/Rar/RarReaderVolume.cs | 4 +- .../Readers/Rar/SingleVolumeRarReader.cs | 8 +- src/SharpCompress/Readers/ReaderFactory.cs | 19 +- src/SharpCompress/Readers/ReaderOptions.cs | 2 +- src/SharpCompress/Readers/ReaderProgress.cs | 4 +- src/SharpCompress/Readers/Tar/TarReader.cs | 59 +- src/SharpCompress/Readers/Zip/ZipReader.cs | 19 +- src/SharpCompress/Utility.cs | 57 +- src/SharpCompress/Writers/AbstractWriter.cs | 2 +- src/SharpCompress/Writers/GZip/GZipWriter.cs | 11 +- .../Writers/GZip/GZipWriterOptions.cs | 10 +- src/SharpCompress/Writers/IWriter.cs | 2 +- .../Writers/IWriterExtensions.cs | 25 +- src/SharpCompress/Writers/Tar/TarWriter.cs | 27 +- .../Writers/Tar/TarWriterOptions.cs | 2 +- src/SharpCompress/Writers/WriterFactory.cs | 9 +- src/SharpCompress/Writers/WriterOptions.cs | 3 +- .../Writers/Zip/ZipCentralDirectoryEntry.cs | 33 +- src/SharpCompress/Writers/Zip/ZipWriter.cs | 224 +- .../Writers/Zip/ZipWriterEntryOptions.cs | 9 +- .../Writers/Zip/ZipWriterOptions.cs | 21 +- tests/SharpCompress.Test/ADCTest.cs | 51 +- tests/SharpCompress.Test/ArchiveTests.cs | 203 +- .../Filters/BranchExecTests.cs | 1232 ++++++++++- .../GZip/GZipArchiveTests.cs | 18 +- .../GZip/GZipReaderTests.cs | 7 +- .../GZip/GZipWriterTests.cs | 55 +- .../Mocks/FlushOnDisposeStream.cs | 6 +- .../Mocks/ForwardOnlyStream.cs | 2 +- tests/SharpCompress.Test/Mocks/TestStream.cs | 5 +- .../SharpCompress.Test/Rar/RarArchiveTests.cs | 384 ++-- .../Rar/RarHeaderFactoryTest.cs | 16 +- .../SharpCompress.Test/Rar/RarReaderTests.cs | 257 ++- tests/SharpCompress.Test/ReaderTests.cs | 36 +- .../SevenZip/SevenZipArchiveTests.cs | 65 +- .../Streams/LzmaStreamTests.cs | 528 ++++- .../Streams/ZlibBaseStreamTests.cs | 43 +- .../SharpCompress.Test/Tar/TarArchiveTests.cs | 66 +- .../SharpCompress.Test/Tar/TarReaderTests.cs | 98 +- .../SharpCompress.Test/Tar/TarWriterTests.cs | 48 +- tests/SharpCompress.Test/TestBase.cs | 44 +- tests/SharpCompress.Test/WriterTests.cs | 28 +- tests/SharpCompress.Test/Xz/Crc32Tests.cs | 4 +- tests/SharpCompress.Test/Xz/Crc64Tests.cs | 4 +- .../SharpCompress.Test/Xz/Filters/BCJTests.cs | 1 + tests/SharpCompress.Test/Xz/XZBlockTests.cs | 10 +- tests/SharpCompress.Test/Xz/XZHeaderTests.cs | 15 +- tests/SharpCompress.Test/Xz/XZIndexTests.cs | 21 +- tests/SharpCompress.Test/Xz/XZTestsBase.cs | 1185 +++++++++- tests/SharpCompress.Test/Zip/Zip64Tests.cs | 69 +- .../SharpCompress.Test/Zip/ZipArchiveTests.cs | 292 ++- .../SharpCompress.Test/Zip/ZipReaderTests.cs | 197 +- .../SharpCompress.Test/Zip/ZipWriterTests.cs | 51 +- 356 files changed, 17199 insertions(+), 5194 deletions(-) diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 034cae45..d1ac7eef 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -2,10 +2,10 @@ "version": 1, "isRoot": true, "tools": { - "dotnet-format": { - "version": "4.1.131201", + "csharpier": { + "version": "0.21.0", "commands": [ - "dotnet-format" + "dotnet-csharpier" ] } } diff --git a/.github/workflows/dotnetcore.yml b/.github/workflows/dotnetcore.yml index 53aa0a9a..530ec766 100644 --- a/.github/workflows/dotnetcore.yml +++ b/.github/workflows/dotnetcore.yml @@ -18,7 +18,7 @@ jobs: - uses: actions/setup-dotnet@v3 with: dotnet-version: 7.0.x - - run: dotnet run -p build/build.csproj + - run: dotnet run --project build/build.csproj - uses: actions/upload-artifact@v3 with: name: ${{ matrix.os }}-sharpcompress.nupkg diff --git a/build/Program.cs b/build/Program.cs index f5a31098..358082aa 100644 --- a/build/Program.cs +++ b/build/Program.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.Runtime.InteropServices; @@ -7,76 +7,75 @@ using static Bullseye.Targets; using static SimpleExec.Command; const string Clean = "clean"; -const string Format = "format"; const string Build = "build"; const string Test = "test"; const string Publish = "publish"; -Target(Clean, - ForEach("**/bin", "**/obj"), - dir => - { - IEnumerable GetDirectories(string d) - { - return Glob.Directories(".", d); - } +Target( + Clean, + ForEach("**/bin", "**/obj"), + dir => + { + IEnumerable GetDirectories(string d) + { + return Glob.Directories(".", d); + } - void RemoveDirectory(string d) - { - if (Directory.Exists(d)) - { - Console.WriteLine(d); - Directory.Delete(d, true); - } - } + void RemoveDirectory(string d) + { + if (Directory.Exists(d)) + { + Console.WriteLine(d); + Directory.Delete(d, true); + } + } - foreach (var d in GetDirectories(dir)) - { - RemoveDirectory(d); - } - }); + foreach (var d in GetDirectories(dir)) + { + RemoveDirectory(d); + } + } +); -Target(Format, - () => - { - Run("dotnet", "tool restore"); - Run("dotnet", "format --check"); - }); +Target( + Build, + () => + { + Run("dotnet", "build src/SharpCompress/SharpCompress.csproj -c Release"); + } +); -Target(Build, - DependsOn(Format), - framework => - { - Run("dotnet", "build src/SharpCompress/SharpCompress.csproj -c Release"); - }); +Target( + Test, + DependsOn(Build), + ForEach("net7.0", "net462"), + framework => + { + IEnumerable GetFiles(string d) + { + return Glob.Files(".", d); + } -Target(Test, - DependsOn(Build), - ForEach("net7.0", "net462"), - framework => - { - IEnumerable GetFiles(string d) - { - return Glob.Files(".", d); - } + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && framework == "net462") + { + return; + } - if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && framework == "net462") - { - return; - } + foreach (var file in GetFiles("**/*.Test.csproj")) + { + Run("dotnet", $"test {file} -c Release -f {framework}"); + } + } +); - foreach (var file in GetFiles("**/*.Test.csproj")) - { - Run("dotnet", $"test {file} -c Release -f {framework}"); - } - }); - -Target(Publish, - DependsOn(Test), - () => - { - Run("dotnet", "pack src/SharpCompress/SharpCompress.csproj -c Release -o artifacts/"); - }); +Target( + Publish, + DependsOn(Test), + () => + { + Run("dotnet", "pack src/SharpCompress/SharpCompress.csproj -c Release -o artifacts/"); + } +); Target("default", DependsOn(Publish), () => Console.WriteLine("Done!")); diff --git a/src/SharpCompress/Algorithms/Adler32.cs b/src/SharpCompress/Algorithms/Adler32.cs index e98c864e..0d4de7fa 100644 --- a/src/SharpCompress/Algorithms/Adler32.cs +++ b/src/SharpCompress/Algorithms/Adler32.cs @@ -82,7 +82,7 @@ namespace SharpCompress.Algorithms public static int EvenReduceSum(Vector256 accumulator) { Vector128 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 + 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 return Sse2.ConvertToInt32(vsum); @@ -107,11 +107,42 @@ namespace SharpCompress.Algorithms private const int BlockSize = 1 << 5; // The C# compiler emits this as a compile-time constant embedded in the PE file. - private static ReadOnlySpan Tap1Tap2 => new byte[] - { - 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, // tap1 - 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 // tap2 - }; + private static ReadOnlySpan Tap1Tap2 => + new byte[] + { + 32, + 31, + 30, + 29, + 28, + 27, + 26, + 25, + 24, + 23, + 22, + 21, + 20, + 19, + 18, + 17, // tap1 + 16, + 15, + 14, + 13, + 12, + 11, + 10, + 9, + 8, + 7, + 6, + 5, + 4, + 3, + 2, + 1 // tap2 + }; #endif /// @@ -120,8 +151,7 @@ namespace SharpCompress.Algorithms /// The readonly span of bytes. /// The . [MethodImpl(InliningOptions.ShortMethod)] - public static uint Calculate(ReadOnlySpan buffer) - => Calculate(SeedValue, buffer); + public static uint Calculate(ReadOnlySpan buffer) => Calculate(SeedValue, buffer); /// /// Calculates the Adler32 checksum with the bytes taken from the span and seed. @@ -181,7 +211,7 @@ namespace SharpCompress.Algorithms while (blocks > 0) { - uint n = NMAX / BlockSize; /* The NMAX constraint. */ + uint n = NMAX / BlockSize; /* The NMAX constraint. */ if (n > blocks) { n = blocks; @@ -206,23 +236,28 @@ namespace SharpCompress.Algorithms // 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()); + v_s1 = Sse2.Add( + v_s1, + Sse2.SumAbsoluteDifferences(bytes1, zero).AsUInt32() + ); Vector128 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()); + v_s1 = Sse2.Add( + v_s1, + Sse2.SumAbsoluteDifferences(bytes2, zero).AsUInt32() + ); Vector128 mad2 = Ssse3.MultiplyAddAdjacent(bytes2, tap2); v_s2 = Sse2.Add(v_s2, Sse2.MultiplyAddAdjacent(mad2, ones).AsUInt32()); localBufferPtr += BlockSize; - } - while (--n > 0); + } while (--n > 0); v_s2 = Sse2.Add(v_s2, Sse2.ShiftLeftLogical(v_ps, 5)); // Sum epi32 ints v_s1(s2) and accumulate in s1(s2). - const byte S2301 = 0b1011_0001; // A B C D -> B A D C - const byte S1032 = 0b0100_1110; // A B C D -> C D A B + const byte S2301 = 0b1011_0001; // A B C D -> B A D C + const byte S1032 = 0b0100_1110; // A B C D -> C D A B v_s1 = Sse2.Add(v_s1, Sse2.Shuffle(v_s1, S1032)); @@ -262,7 +297,40 @@ namespace SharpCompress.Algorithms Vector256 zero = Vector256.Zero; var dot3v = Vector256.Create((short)1); - var dot2v = Vector256.Create(32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1); + var dot2v = Vector256.Create( + 32, + 31, + 30, + 29, + 28, + 27, + 26, + 25, + 24, + 23, + 22, + 21, + 20, + 19, + 18, + 17, + 16, + 15, + 14, + 13, + 12, + 11, + 10, + 9, + 8, + 7, + 6, + 5, + 4, + 3, + 2, + 1 + ); // Process n blocks of data. At most NMAX data bytes can be // processed before s2 must be reduced modulo BASE. @@ -325,7 +393,12 @@ namespace SharpCompress.Algorithms } } - private static unsafe void HandleLeftOver(byte* localBufferPtr, uint length, ref uint s1, ref uint s2) + private static unsafe void HandleLeftOver( + byte* localBufferPtr, + uint length, + ref uint s1, + ref uint s2 + ) { if (length >= 16) { diff --git a/src/SharpCompress/Archives/AbstractArchive.cs b/src/SharpCompress/Archives/AbstractArchive.cs index b6c0ef76..16b07864 100644 --- a/src/SharpCompress/Archives/AbstractArchive.cs +++ b/src/SharpCompress/Archives/AbstractArchive.cs @@ -42,13 +42,17 @@ namespace SharpCompress.Archives lazyVolumes = new LazyReadOnlyCollection(Enumerable.Empty()); lazyEntries = new LazyReadOnlyCollection(Enumerable.Empty()); } + #nullable enable public ArchiveType Type { get; } void IArchiveExtractionListener.FireEntryExtractionBegin(IArchiveEntry entry) { - EntryExtractionBegin?.Invoke(this, new ArchiveExtractionEventArgs(entry)); + EntryExtractionBegin?.Invoke( + this, + new ArchiveExtractionEventArgs(entry) + ); } void IArchiveExtractionListener.FireEntryExtractionEnd(IArchiveEntry entry) @@ -78,12 +82,14 @@ namespace SharpCompress.Archives /// /// The total size of the files compressed in the archive. /// - public virtual long TotalSize => Entries.Aggregate(0L, (total, cf) => total + cf.CompressedSize); + public virtual long TotalSize => + Entries.Aggregate(0L, (total, cf) => total + cf.CompressedSize); /// /// The total size of the files as uncompressed in the archive. /// - public virtual long TotalUncompressSize => Entries.Aggregate(0L, (total, cf) => total + cf.Size); + public virtual long TotalUncompressSize => + Entries.Aggregate(0L, (total, cf) => total + cf.Size); protected abstract IEnumerable LoadVolumes(SourceStream srcStream); protected abstract IEnumerable LoadEntries(IEnumerable volumes); @@ -110,21 +116,34 @@ namespace SharpCompress.Archives lazyVolumes.EnsureFullyLoaded(); } - void IExtractionListener.FireCompressedBytesRead(long currentPartCompressedBytes, long compressedReadBytes) + void IExtractionListener.FireCompressedBytesRead( + long currentPartCompressedBytes, + long compressedReadBytes + ) { - CompressedBytesRead?.Invoke(this, new CompressedBytesReadEventArgs( - currentFilePartCompressedBytesRead: currentPartCompressedBytes, - compressedBytesRead: compressedReadBytes - )); + CompressedBytesRead?.Invoke( + this, + new CompressedBytesReadEventArgs( + currentFilePartCompressedBytesRead: currentPartCompressedBytes, + compressedBytesRead: compressedReadBytes + ) + ); } - void IExtractionListener.FireFilePartExtractionBegin(string name, long size, long compressedSize) + void IExtractionListener.FireFilePartExtractionBegin( + string name, + long size, + long compressedSize + ) { - FilePartExtractionBegin?.Invoke(this, new FilePartExtractionBeginEventArgs( - compressedSize: compressedSize, - size: size, - name: name - )); + FilePartExtractionBegin?.Invoke( + this, + new FilePartExtractionBeginEventArgs( + compressedSize: compressedSize, + size: size, + name: name + ) + ); } /// diff --git a/src/SharpCompress/Archives/AbstractWritableArchive.cs b/src/SharpCompress/Archives/AbstractWritableArchive.cs index 42a8213e..fc877cbd 100644 --- a/src/SharpCompress/Archives/AbstractWritableArchive.cs +++ b/src/SharpCompress/Archives/AbstractWritableArchive.cs @@ -9,7 +9,9 @@ using SharpCompress.Writers; namespace SharpCompress.Archives { - public abstract class AbstractWritableArchive : AbstractArchive, IWritableArchive + public abstract class AbstractWritableArchive + : AbstractArchive, + IWritableArchive where TEntry : IArchiveEntry where TVolume : IVolume { @@ -29,6 +31,7 @@ namespace SharpCompress.Archives archive.RebuildModifiedCollection(); } } + private readonly List newEntries = new List(); private readonly List removedEntries = new List(); @@ -36,15 +39,10 @@ namespace SharpCompress.Archives private bool hasModifications; private bool pauseRebuilding; - internal AbstractWritableArchive(ArchiveType type) - : base(type) - { - } + internal AbstractWritableArchive(ArchiveType type) : base(type) { } internal AbstractWritableArchive(ArchiveType type, SourceStream srcStream) - : base(type, srcStream) - { - } + : base(type, srcStream) { } public override ICollection Entries { @@ -75,7 +73,10 @@ namespace SharpCompress.Archives modifiedEntries.AddRange(OldEntries.Concat(newEntries)); } - private IEnumerable OldEntries { get { return base.Entries.Where(x => !removedEntries.Contains(x)); } } + private IEnumerable OldEntries + { + get { return base.Entries.Where(x => !removedEntries.Contains(x)); } + } public void RemoveEntry(TEntry entry) { @@ -91,19 +92,29 @@ namespace SharpCompress.Archives RemoveEntry((TEntry)entry); } - public TEntry AddEntry(string key, Stream source, - long size = 0, DateTime? modified = null) + public TEntry AddEntry(string key, Stream source, long size = 0, DateTime? modified = null) { return AddEntry(key, source, false, size, modified); } - IArchiveEntry IWritableArchive.AddEntry(string key, Stream source, bool closeStream, long size, DateTime? modified) + IArchiveEntry IWritableArchive.AddEntry( + string key, + Stream source, + bool closeStream, + long size, + DateTime? modified + ) { return AddEntry(key, source, closeStream, size, modified); } - public TEntry AddEntry(string key, Stream source, bool closeStream, - long size = 0, DateTime? modified = null) + public TEntry AddEntry( + string key, + Stream source, + bool closeStream, + long size = 0, + DateTime? modified = null + ) { if (key.Length > 0 && key[0] is '/' or '\\') { @@ -136,24 +147,43 @@ namespace SharpCompress.Archives public void SaveTo(Stream stream, WriterOptions options) { //reset streams of new entries - newEntries.Cast().ForEach(x => x.Stream.Seek(0, SeekOrigin.Begin)); + newEntries + .Cast() + .ForEach(x => x.Stream.Seek(0, SeekOrigin.Begin)); SaveTo(stream, options, OldEntries, newEntries); } - protected TEntry CreateEntry(string key, Stream source, long size, DateTime? modified, - bool closeStream) + protected TEntry CreateEntry( + string key, + Stream source, + long size, + DateTime? modified, + bool closeStream + ) { if (!source.CanRead || !source.CanSeek) { - throw new ArgumentException("Streams must be readable and seekable to use the Writing Archive API"); + throw new ArgumentException( + "Streams must be readable and seekable to use the Writing Archive API" + ); } return CreateEntryInternal(key, source, size, modified, closeStream); } - protected abstract TEntry CreateEntryInternal(string key, Stream source, long size, DateTime? modified, - bool closeStream); + protected abstract TEntry CreateEntryInternal( + string key, + Stream source, + long size, + DateTime? modified, + bool closeStream + ); - protected abstract void SaveTo(Stream stream, WriterOptions options, IEnumerable oldEntries, IEnumerable newEntries); + protected abstract void SaveTo( + Stream stream, + WriterOptions options, + IEnumerable oldEntries, + IEnumerable newEntries + ); public override void Dispose() { diff --git a/src/SharpCompress/Archives/ArchiveFactory.cs b/src/SharpCompress/Archives/ArchiveFactory.cs index 71c0358e..f5c5cdee 100644 --- a/src/SharpCompress/Archives/ArchiveFactory.cs +++ b/src/SharpCompress/Archives/ArchiveFactory.cs @@ -31,14 +31,13 @@ namespace SharpCompress.Archives public static IWritableArchive Create(ArchiveType type) { - var factory = Factories.Factory - .Factories + var factory = Factories.Factory.Factories .OfType() .Where(item => item.KnownArchiveType == type) .FirstOrDefault(); if (factory != null) - return factory.CreateWriteableArchive(); + return factory.CreateWriteableArchive(); throw new NotSupportedException("Cannot create Archives of type: " + type); } @@ -60,7 +59,7 @@ namespace SharpCompress.Archives /// /// public static IArchive Open(FileInfo fileInfo, ReaderOptions? options = null) - { + { options ??= new ReaderOptions { LeaveStreamOpen = false }; return FindFactory(fileInfo).Open(fileInfo, options); @@ -105,14 +104,17 @@ namespace SharpCompress.Archives firstStream.CheckNotNull(nameof(firstStream)); options ??= new ReaderOptions(); - return FindFactory(firstStream).Open(streamsArray, options); - } + return FindFactory(firstStream).Open(streamsArray, options); + } /// /// Extract to specific directory, retaining filename /// - public static void WriteToDirectory(string sourceArchive, string destinationDirectory, - ExtractionOptions? options = null) + public static void WriteToDirectory( + string sourceArchive, + string destinationDirectory, + ExtractionOptions? options = null + ) { using IArchive archive = Open(sourceArchive); foreach (IArchiveEntry entry in archive.Entries) @@ -121,8 +123,7 @@ namespace SharpCompress.Archives } } - private static T FindFactory(FileInfo finfo) - where T : IFactory + private static T FindFactory(FileInfo finfo) where T : IFactory { finfo.CheckNotNull(nameof(finfo)); using (Stream stream = finfo.OpenRead()) @@ -131,8 +132,7 @@ namespace SharpCompress.Archives } } - private static T FindFactory(Stream stream) - where T: IFactory + private static T FindFactory(Stream stream) where T : IFactory { stream.CheckNotNull(nameof(stream)); if (!stream.CanRead || !stream.CanSeek) @@ -158,7 +158,9 @@ namespace SharpCompress.Archives var extensions = string.Join(", ", factories.Select(item => item.Name)); - throw new InvalidOperationException($"Cannot determine compressed stream type. Supported Archive Formats: {extensions}"); + throw new InvalidOperationException( + $"Cannot determine compressed stream type. Supported Archive Formats: {extensions}" + ); } public static bool IsArchive(string filePath, out ArchiveType? type) @@ -180,7 +182,7 @@ namespace SharpCompress.Archives var startPosition = stream.Position; - foreach(var factory in Factories.Factory.Factories) + foreach (var factory in Factories.Factory.Factories) { stream.Position = startPosition; @@ -213,9 +215,9 @@ namespace SharpCompress.Archives public static IEnumerable GetFileParts(FileInfo part1) { part1.CheckNotNull(nameof(part1)); - yield return part1; + yield return part1; - foreach(var factory in Factory.Factories.OfType()) + foreach (var factory in Factory.Factories.OfType()) { int i = 1; FileInfo? part = factory.GetFilePart(i++, part1); diff --git a/src/SharpCompress/Archives/ArchiveVolumeFactory.cs b/src/SharpCompress/Archives/ArchiveVolumeFactory.cs index 09315b40..fc68399b 100644 --- a/src/SharpCompress/Archives/ArchiveVolumeFactory.cs +++ b/src/SharpCompress/Archives/ArchiveVolumeFactory.cs @@ -18,12 +18,19 @@ namespace SharpCompress.Archives //split 001, 002 ... Match m = Regex.Match(part1.Name, @"^(.*\.)([0-9]+)$", RegexOptions.IgnoreCase); if (m.Success) - item = new FileInfo(Path.Combine(part1.DirectoryName!, String.Concat(m.Groups[1].Value, (index + 1).ToString().PadLeft(m.Groups[2].Value.Length, '0')))); + item = new FileInfo( + Path.Combine( + part1.DirectoryName!, + String.Concat( + m.Groups[1].Value, + (index + 1).ToString().PadLeft(m.Groups[2].Value.Length, '0') + ) + ) + ); if (item != null && item.Exists) return item; return null; } - } } diff --git a/src/SharpCompress/Archives/GZip/GZipArchive.cs b/src/SharpCompress/Archives/GZip/GZipArchive.cs index 845e05fb..ed1b6a6b 100644 --- a/src/SharpCompress/Archives/GZip/GZipArchive.cs +++ b/src/SharpCompress/Archives/GZip/GZipArchive.cs @@ -33,7 +33,13 @@ namespace SharpCompress.Archives.GZip public static GZipArchive Open(FileInfo fileInfo, ReaderOptions? readerOptions = null) { fileInfo.CheckNotNull(nameof(fileInfo)); - return new GZipArchive(new SourceStream(fileInfo, i => ArchiveVolumeFactory.GetFilePart(i, fileInfo), readerOptions ?? new ReaderOptions())); + return new GZipArchive( + new SourceStream( + fileInfo, + i => ArchiveVolumeFactory.GetFilePart(i, fileInfo), + readerOptions ?? new ReaderOptions() + ) + ); } /// @@ -41,11 +47,20 @@ namespace SharpCompress.Archives.GZip /// /// /// - public static GZipArchive Open(IEnumerable fileInfos, ReaderOptions? readerOptions = null) + public static GZipArchive Open( + IEnumerable fileInfos, + ReaderOptions? readerOptions = null + ) { fileInfos.CheckNotNull(nameof(fileInfos)); FileInfo[] files = fileInfos.ToArray(); - return new GZipArchive(new SourceStream(files[0], i => i < files.Length ? files[i] : null, readerOptions ?? new ReaderOptions())); + return new GZipArchive( + new SourceStream( + files[0], + i => i < files.Length ? files[i] : null, + readerOptions ?? new ReaderOptions() + ) + ); } /// @@ -53,11 +68,20 @@ namespace SharpCompress.Archives.GZip /// /// /// - public static GZipArchive Open(IEnumerable streams, ReaderOptions? readerOptions = null) + public static GZipArchive Open( + IEnumerable streams, + ReaderOptions? readerOptions = null + ) { streams.CheckNotNull(nameof(streams)); Stream[] strms = streams.ToArray(); - return new GZipArchive(new SourceStream(strms[0], i => i < strms.Length ? strms[i] : null, readerOptions ?? new ReaderOptions())); + return new GZipArchive( + new SourceStream( + strms[0], + i => i < strms.Length ? strms[i] : null, + readerOptions ?? new ReaderOptions() + ) + ); } /// @@ -68,7 +92,9 @@ namespace SharpCompress.Archives.GZip public static GZipArchive Open(Stream stream, ReaderOptions? readerOptions = null) { stream.CheckNotNull(nameof(stream)); - return new GZipArchive(new SourceStream(stream, i => null, readerOptions ?? new ReaderOptions())); + return new GZipArchive( + new SourceStream(stream, i => null, readerOptions ?? new ReaderOptions()) + ); } public static GZipArchive Create() @@ -81,10 +107,7 @@ namespace SharpCompress.Archives.GZip /// /// /// - internal GZipArchive(SourceStream srcStream) - : base(ArchiveType.Tar, srcStream) - { - } + internal GZipArchive(SourceStream srcStream) : base(ArchiveType.Tar, srcStream) { } protected override IEnumerable LoadVolumes(SourceStream srcStream) { @@ -92,6 +115,7 @@ namespace SharpCompress.Archives.GZip int idx = 0; return srcStream.Streams.Select(a => new GZipVolume(a, ReaderOptions, idx++)); } + public static bool IsGZipFile(string filePath) { return IsGZipFile(new FileInfo(filePath)); @@ -140,24 +164,36 @@ namespace SharpCompress.Archives.GZip return true; } - internal GZipArchive() - : base(ArchiveType.GZip) - { - } + internal GZipArchive() : base(ArchiveType.GZip) { } - protected override GZipArchiveEntry CreateEntryInternal(string filePath, Stream source, long size, DateTime? modified, - bool closeStream) + protected override GZipArchiveEntry CreateEntryInternal( + string filePath, + Stream source, + long size, + DateTime? modified, + bool closeStream + ) { if (Entries.Any()) { throw new InvalidOperationException("Only one entry is allowed in a GZip Archive"); } - return new GZipWritableArchiveEntry(this, source, filePath, size, modified, closeStream); + return new GZipWritableArchiveEntry( + this, + source, + filePath, + size, + modified, + closeStream + ); } - protected override void SaveTo(Stream stream, WriterOptions options, - IEnumerable oldEntries, - IEnumerable newEntries) + protected override void SaveTo( + Stream stream, + WriterOptions options, + IEnumerable oldEntries, + IEnumerable newEntries + ) { if (Entries.Count > 1) { @@ -165,8 +201,7 @@ namespace SharpCompress.Archives.GZip } using (var writer = new GZipWriter(stream, new GZipWriterOptions(options))) { - foreach (var entry in oldEntries.Concat(newEntries) - .Where(x => !x.IsDirectory)) + foreach (var entry in oldEntries.Concat(newEntries).Where(x => !x.IsDirectory)) { using (var entryStream = entry.OpenEntryStream()) { @@ -176,10 +211,15 @@ namespace SharpCompress.Archives.GZip } } - protected override IEnumerable LoadEntries(IEnumerable volumes) + protected override IEnumerable LoadEntries( + IEnumerable volumes + ) { Stream stream = volumes.Single().Stream; - yield return new GZipArchiveEntry(this, new GZipFilePart(stream, ReaderOptions.ArchiveEncoding)); + yield return new GZipArchiveEntry( + this, + new GZipFilePart(stream, ReaderOptions.ArchiveEncoding) + ); } protected override IReader CreateReaderForSolidExtraction() diff --git a/src/SharpCompress/Archives/GZip/GZipArchiveEntry.cs b/src/SharpCompress/Archives/GZip/GZipArchiveEntry.cs index 237a5247..23316046 100644 --- a/src/SharpCompress/Archives/GZip/GZipArchiveEntry.cs +++ b/src/SharpCompress/Archives/GZip/GZipArchiveEntry.cs @@ -6,8 +6,7 @@ namespace SharpCompress.Archives.GZip { public class GZipArchiveEntry : GZipEntry, IArchiveEntry { - internal GZipArchiveEntry(GZipArchive archive, GZipFilePart part) - : base(part) + internal GZipArchiveEntry(GZipArchive archive, GZipFilePart part) : base(part) { Archive = archive; } @@ -31,4 +30,4 @@ namespace SharpCompress.Archives.GZip #endregion } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Archives/GZip/GZipWritableArchiveEntry.cs b/src/SharpCompress/Archives/GZip/GZipWritableArchiveEntry.cs index 4a315571..4f35f24d 100644 --- a/src/SharpCompress/Archives/GZip/GZipWritableArchiveEntry.cs +++ b/src/SharpCompress/Archives/GZip/GZipWritableArchiveEntry.cs @@ -13,9 +13,14 @@ namespace SharpCompress.Archives.GZip private readonly bool closeStream; private readonly Stream stream; - internal GZipWritableArchiveEntry(GZipArchive archive, Stream stream, - string path, long size, DateTime? lastModified, bool closeStream) - : base(archive, null) + internal GZipWritableArchiveEntry( + GZipArchive archive, + Stream stream, + string path, + long size, + DateTime? lastModified, + bool closeStream + ) : base(archive, null) { this.stream = stream; Key = path; diff --git a/src/SharpCompress/Archives/IArchive.cs b/src/SharpCompress/Archives/IArchive.cs index 2ba84a39..acb2bf11 100644 --- a/src/SharpCompress/Archives/IArchive.cs +++ b/src/SharpCompress/Archives/IArchive.cs @@ -20,7 +20,7 @@ namespace SharpCompress.Archives /// /// Use this method to extract all entries in an archive in order. - /// This is primarily for SOLID Rar Archives or 7Zip Archives as they need to be + /// This is primarily for SOLID Rar Archives or 7Zip Archives as they need to be /// extracted sequentially for the best performance. /// IReader ExtractAllEntries(); @@ -46,4 +46,4 @@ namespace SharpCompress.Archives /// long TotalUncompressSize { get; } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Archives/IArchiveEntry.cs b/src/SharpCompress/Archives/IArchiveEntry.cs index 43e681b4..e3351582 100644 --- a/src/SharpCompress/Archives/IArchiveEntry.cs +++ b/src/SharpCompress/Archives/IArchiveEntry.cs @@ -21,4 +21,4 @@ namespace SharpCompress.Archives /// IArchive Archive { get; } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Archives/IArchiveEntryExtensions.cs b/src/SharpCompress/Archives/IArchiveEntryExtensions.cs index 829b8bbd..d5eac3f9 100644 --- a/src/SharpCompress/Archives/IArchiveEntryExtensions.cs +++ b/src/SharpCompress/Archives/IArchiveEntryExtensions.cs @@ -16,7 +16,11 @@ namespace SharpCompress.Archives var streamListener = (IArchiveExtractionListener)archiveEntry.Archive; streamListener.EnsureEntriesLoaded(); streamListener.FireEntryExtractionBegin(archiveEntry); - streamListener.FireFilePartExtractionBegin(archiveEntry.Key, archiveEntry.Size, archiveEntry.CompressedSize); + streamListener.FireFilePartExtractionBegin( + archiveEntry.Key, + archiveEntry.Size, + archiveEntry.CompressedSize + ); var entryStream = archiveEntry.OpenEntryStream(); if (entryStream is null) { @@ -35,29 +39,41 @@ namespace SharpCompress.Archives /// /// Extract to specific directory, retaining filename /// - public static void WriteToDirectory(this IArchiveEntry entry, string destinationDirectory, - ExtractionOptions? options = null) + public static void WriteToDirectory( + this IArchiveEntry entry, + string destinationDirectory, + ExtractionOptions? options = null + ) { - ExtractionMethods.WriteEntryToDirectory(entry, destinationDirectory, options, - entry.WriteToFile); + ExtractionMethods.WriteEntryToDirectory( + entry, + destinationDirectory, + options, + entry.WriteToFile + ); } /// /// Extract to specific file /// - public static void WriteToFile(this IArchiveEntry entry, - string destinationFileName, - ExtractionOptions? options = null) + public static void WriteToFile( + this IArchiveEntry entry, + string destinationFileName, + ExtractionOptions? options = null + ) { - - ExtractionMethods.WriteEntryToFile(entry, destinationFileName, options, - (x, fm) => - { - using (FileStream fs = File.Open(destinationFileName, fm)) - { - entry.WriteTo(fs); - } - }); + ExtractionMethods.WriteEntryToFile( + entry, + destinationFileName, + options, + (x, fm) => + { + using (FileStream fs = File.Open(destinationFileName, fm)) + { + entry.WriteTo(fs); + } + } + ); } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Archives/IArchiveExtensions.cs b/src/SharpCompress/Archives/IArchiveExtensions.cs index 23b8a27e..c0a9e1dd 100644 --- a/src/SharpCompress/Archives/IArchiveExtensions.cs +++ b/src/SharpCompress/Archives/IArchiveExtensions.cs @@ -8,8 +8,11 @@ namespace SharpCompress.Archives /// /// Extract to specific directory, retaining filename /// - public static void WriteToDirectory(this IArchive archive, string destinationDirectory, - ExtractionOptions? options = null) + public static void WriteToDirectory( + this IArchive archive, + string destinationDirectory, + ExtractionOptions? options = null + ) { foreach (IArchiveEntry entry in archive.Entries.Where(x => !x.IsDirectory)) { @@ -17,4 +20,4 @@ namespace SharpCompress.Archives } } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Archives/IArchiveExtractionListener.cs b/src/SharpCompress/Archives/IArchiveExtractionListener.cs index 9ce07e8a..b352691e 100644 --- a/src/SharpCompress/Archives/IArchiveExtractionListener.cs +++ b/src/SharpCompress/Archives/IArchiveExtractionListener.cs @@ -8,4 +8,4 @@ namespace SharpCompress.Archives void FireEntryExtractionBegin(IArchiveEntry entry); void FireEntryExtractionEnd(IArchiveEntry entry); } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Archives/IArchiveFactory.cs b/src/SharpCompress/Archives/IArchiveFactory.cs index 98014688..6ba64079 100644 --- a/src/SharpCompress/Archives/IArchiveFactory.cs +++ b/src/SharpCompress/Archives/IArchiveFactory.cs @@ -16,8 +16,8 @@ namespace SharpCompress.Archives /// /// /// - /// - /// + /// + /// /// /// /// diff --git a/src/SharpCompress/Archives/IMultiArchiveFactory.cs b/src/SharpCompress/Archives/IMultiArchiveFactory.cs index 6ba39280..7610b146 100644 --- a/src/SharpCompress/Archives/IMultiArchiveFactory.cs +++ b/src/SharpCompress/Archives/IMultiArchiveFactory.cs @@ -16,8 +16,8 @@ namespace SharpCompress.Archives /// /// /// - /// - /// + /// + /// /// /// /// @@ -35,6 +35,9 @@ namespace SharpCompress.Archives /// /// /// reading options. - IArchive Open(IReadOnlyList fileInfos, ReaderOptions? readerOptions = null); + IArchive Open( + IReadOnlyList fileInfos, + ReaderOptions? readerOptions = null + ); } } diff --git a/src/SharpCompress/Archives/IWritableArchive.cs b/src/SharpCompress/Archives/IWritableArchive.cs index 3b1b0328..02b76f66 100644 --- a/src/SharpCompress/Archives/IWritableArchive.cs +++ b/src/SharpCompress/Archives/IWritableArchive.cs @@ -8,7 +8,13 @@ namespace SharpCompress.Archives { void RemoveEntry(IArchiveEntry entry); - IArchiveEntry AddEntry(string key, Stream source, bool closeStream, long size = 0, DateTime? modified = null); + IArchiveEntry AddEntry( + string key, + Stream source, + bool closeStream, + long size = 0, + DateTime? modified = null + ); void SaveTo(Stream stream, WriterOptions options); @@ -18,4 +24,4 @@ namespace SharpCompress.Archives /// IDisposeable to resume entry rebuilding IDisposable PauseEntryRebuilding(); } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Archives/IWritableArchiveEntry.cs b/src/SharpCompress/Archives/IWritableArchiveEntry.cs index 044eb1c7..f3d5eb26 100644 --- a/src/SharpCompress/Archives/IWritableArchiveEntry.cs +++ b/src/SharpCompress/Archives/IWritableArchiveEntry.cs @@ -6,4 +6,4 @@ namespace SharpCompress.Archives { Stream Stream { get; } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Archives/IWritableArchiveExtensions.cs b/src/SharpCompress/Archives/IWritableArchiveExtensions.cs index 468622a7..1827e9e8 100644 --- a/src/SharpCompress/Archives/IWritableArchiveExtensions.cs +++ b/src/SharpCompress/Archives/IWritableArchiveExtensions.cs @@ -6,24 +6,40 @@ namespace SharpCompress.Archives { public static class IWritableArchiveExtensions { - public static void AddEntry(this IWritableArchive writableArchive, - string entryPath, string filePath) + public static void AddEntry( + this IWritableArchive writableArchive, + string entryPath, + string filePath + ) { var fileInfo = new FileInfo(filePath); if (!fileInfo.Exists) { throw new FileNotFoundException("Could not AddEntry: " + filePath); } - writableArchive.AddEntry(entryPath, new FileInfo(filePath).OpenRead(), true, fileInfo.Length, - fileInfo.LastWriteTime); + writableArchive.AddEntry( + entryPath, + new FileInfo(filePath).OpenRead(), + true, + fileInfo.Length, + fileInfo.LastWriteTime + ); } - public static void SaveTo(this IWritableArchive writableArchive, string filePath, WriterOptions options) + public static void SaveTo( + this IWritableArchive writableArchive, + string filePath, + WriterOptions options + ) { writableArchive.SaveTo(new FileInfo(filePath), options); } - public static void SaveTo(this IWritableArchive writableArchive, FileInfo fileInfo, WriterOptions options) + public static void SaveTo( + this IWritableArchive writableArchive, + FileInfo fileInfo, + WriterOptions options + ) { using (var stream = fileInfo.Open(FileMode.Create, FileAccess.Write)) { @@ -33,25 +49,46 @@ namespace SharpCompress.Archives public static void AddAllFromDirectory( this IWritableArchive writableArchive, - string filePath, string searchPattern = "*.*", SearchOption searchOption = SearchOption.AllDirectories) + string filePath, + string searchPattern = "*.*", + SearchOption searchOption = SearchOption.AllDirectories + ) { using (writableArchive.PauseEntryRebuilding()) { - foreach (var path in Directory.EnumerateFiles(filePath, searchPattern, searchOption)) + foreach ( + var path in Directory.EnumerateFiles(filePath, searchPattern, searchOption) + ) { var fileInfo = new FileInfo(path); - writableArchive.AddEntry(path.Substring(filePath.Length), fileInfo.OpenRead(), true, fileInfo.Length, - fileInfo.LastWriteTime); + writableArchive.AddEntry( + path.Substring(filePath.Length), + fileInfo.OpenRead(), + true, + fileInfo.Length, + fileInfo.LastWriteTime + ); } } } - public static IArchiveEntry AddEntry(this IWritableArchive writableArchive, string key, FileInfo fileInfo) + + public static IArchiveEntry AddEntry( + this IWritableArchive writableArchive, + string key, + FileInfo fileInfo + ) { if (!fileInfo.Exists) { throw new ArgumentException("FileInfo does not exist."); } - return writableArchive.AddEntry(key, fileInfo.OpenRead(), true, fileInfo.Length, fileInfo.LastWriteTime); + return writableArchive.AddEntry( + key, + fileInfo.OpenRead(), + true, + fileInfo.Length, + fileInfo.LastWriteTime + ); } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Archives/Rar/FileInfoRarArchiveVolume.cs b/src/SharpCompress/Archives/Rar/FileInfoRarArchiveVolume.cs index 1afba647..78ec29e8 100644 --- a/src/SharpCompress/Archives/Rar/FileInfoRarArchiveVolume.cs +++ b/src/SharpCompress/Archives/Rar/FileInfoRarArchiveVolume.cs @@ -33,7 +33,13 @@ namespace SharpCompress.Archives.Rar internal override RarFilePart CreateFilePart(MarkHeader markHeader, FileHeader fileHeader) { - return new FileInfoRarFilePart(this, ReaderOptions.Password, markHeader, fileHeader, FileInfo); + return new FileInfoRarFilePart( + this, + ReaderOptions.Password, + markHeader, + fileHeader, + FileInfo + ); } internal override IEnumerable ReadFileParts() diff --git a/src/SharpCompress/Archives/Rar/FileInfoRarFilePart.cs b/src/SharpCompress/Archives/Rar/FileInfoRarFilePart.cs index b2134e6d..1908c8af 100644 --- a/src/SharpCompress/Archives/Rar/FileInfoRarFilePart.cs +++ b/src/SharpCompress/Archives/Rar/FileInfoRarFilePart.cs @@ -5,8 +5,13 @@ namespace SharpCompress.Archives.Rar { internal sealed class FileInfoRarFilePart : SeekableFilePart { - internal FileInfoRarFilePart(FileInfoRarArchiveVolume volume, string? password, MarkHeader mh, FileHeader fh, FileInfo fi) - : base(mh, fh, volume.Index, volume.Stream, password) + internal FileInfoRarFilePart( + FileInfoRarArchiveVolume volume, + string? password, + MarkHeader mh, + FileHeader fh, + FileInfo fi + ) : base(mh, fh, volume.Index, volume.Stream, password) { FileInfo = fi; } @@ -15,11 +20,7 @@ namespace SharpCompress.Archives.Rar internal override string FilePartName { - get - { - return "Rar File: " + FileInfo.FullName - + " File Entry: " + FileHeader.FileName; - } + get { return "Rar File: " + FileInfo.FullName + " File Entry: " + FileHeader.FileName; } } } } diff --git a/src/SharpCompress/Archives/Rar/RarArchive.Extensions.cs b/src/SharpCompress/Archives/Rar/RarArchive.Extensions.cs index 7eefef9c..41abe3f4 100644 --- a/src/SharpCompress/Archives/Rar/RarArchive.Extensions.cs +++ b/src/SharpCompress/Archives/Rar/RarArchive.Extensions.cs @@ -20,4 +20,4 @@ namespace SharpCompress.Archives.Rar return archive.Volumes.First().IsMultiVolume; } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Archives/Rar/RarArchive.cs b/src/SharpCompress/Archives/Rar/RarArchive.cs index 6d43a46b..67a4d070 100644 --- a/src/SharpCompress/Archives/Rar/RarArchive.cs +++ b/src/SharpCompress/Archives/Rar/RarArchive.cs @@ -11,22 +11,19 @@ using SharpCompress.Readers.Rar; namespace SharpCompress.Archives.Rar { - public class - RarArchive : AbstractArchive + public class RarArchive : AbstractArchive { - internal Lazy UnpackV2017 { get; } = new Lazy(() => new SharpCompress.Compressors.Rar.UnpackV2017.Unpack()); - internal Lazy UnpackV1 { get; } = new Lazy(() => new SharpCompress.Compressors.Rar.UnpackV1.Unpack()); - + internal Lazy UnpackV2017 { get; } = + new Lazy(() => new SharpCompress.Compressors.Rar.UnpackV2017.Unpack()); + internal Lazy UnpackV1 { get; } = + new Lazy(() => new SharpCompress.Compressors.Rar.UnpackV1.Unpack()); /// /// Constructor with a SourceStream able to handle FileInfo and Streams. /// /// /// - internal RarArchive(SourceStream srcStream) - : base(ArchiveType.Rar, srcStream) - { - } + internal RarArchive(SourceStream srcStream) : base(ArchiveType.Rar, srcStream) { } protected override IEnumerable LoadEntries(IEnumerable volumes) { @@ -44,7 +41,9 @@ namespace SharpCompress.Archives.Rar streams[1].Position = 0; base.SrcStream.Position = 0; - return srcStream.Streams.Select(a => new StreamRarArchiveVolume(a, ReaderOptions, idx++)); + return srcStream.Streams.Select( + a => new StreamRarArchiveVolume(a, ReaderOptions, idx++) + ); } else //split mode or single file return new StreamRarArchiveVolume(base.SrcStream, ReaderOptions, idx++).AsEnumerable(); @@ -72,7 +71,13 @@ namespace SharpCompress.Archives.Rar { filePath.CheckNotNullOrEmpty(nameof(filePath)); FileInfo fileInfo = new FileInfo(filePath); - return new RarArchive(new SourceStream(fileInfo, i => RarArchiveVolumeFactory.GetFilePart(i, fileInfo), options ?? new ReaderOptions())); + return new RarArchive( + new SourceStream( + fileInfo, + i => RarArchiveVolumeFactory.GetFilePart(i, fileInfo), + options ?? new ReaderOptions() + ) + ); } /// @@ -83,7 +88,13 @@ namespace SharpCompress.Archives.Rar public static RarArchive Open(FileInfo fileInfo, ReaderOptions? options = null) { fileInfo.CheckNotNull(nameof(fileInfo)); - return new RarArchive(new SourceStream(fileInfo, i => RarArchiveVolumeFactory.GetFilePart(i, fileInfo), options ?? new ReaderOptions())); + return new RarArchive( + new SourceStream( + fileInfo, + i => RarArchiveVolumeFactory.GetFilePart(i, fileInfo), + options ?? new ReaderOptions() + ) + ); } /// @@ -94,7 +105,9 @@ namespace SharpCompress.Archives.Rar 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, i => null, options ?? new ReaderOptions()) + ); } /// @@ -102,11 +115,20 @@ namespace SharpCompress.Archives.Rar /// /// /// - public static RarArchive Open(IEnumerable fileInfos, ReaderOptions? readerOptions = null) + public static RarArchive Open( + IEnumerable fileInfos, + ReaderOptions? readerOptions = null + ) { fileInfos.CheckNotNull(nameof(fileInfos)); FileInfo[] files = fileInfos.ToArray(); - return new RarArchive(new SourceStream(files[0], i => i < files.Length ? files[i] : null, readerOptions ?? new ReaderOptions())); + return new RarArchive( + new SourceStream( + files[0], + i => i < files.Length ? files[i] : null, + readerOptions ?? new ReaderOptions() + ) + ); } /// @@ -114,14 +136,22 @@ namespace SharpCompress.Archives.Rar /// /// /// - public static RarArchive Open(IEnumerable streams, ReaderOptions? readerOptions = null) + public static RarArchive Open( + IEnumerable streams, + ReaderOptions? readerOptions = null + ) { streams.CheckNotNull(nameof(streams)); Stream[] strms = streams.ToArray(); - return new RarArchive(new SourceStream(strms[0], i => i < strms.Length ? strms[i] : null, readerOptions ?? new ReaderOptions())); + return new RarArchive( + new SourceStream( + strms[0], + i => i < strms.Length ? strms[i] : null, + readerOptions ?? new ReaderOptions() + ) + ); } - public static bool IsRarFile(string filePath) { return IsRarFile(new FileInfo(filePath)); diff --git a/src/SharpCompress/Archives/Rar/RarArchiveEntry.cs b/src/SharpCompress/Archives/Rar/RarArchiveEntry.cs index fb2ba0f8..a5f4d038 100644 --- a/src/SharpCompress/Archives/Rar/RarArchiveEntry.cs +++ b/src/SharpCompress/Archives/Rar/RarArchiveEntry.cs @@ -16,7 +16,11 @@ namespace SharpCompress.Archives.Rar private readonly RarArchive archive; private readonly ReaderOptions readerOptions; - internal RarArchiveEntry(RarArchive archive, IEnumerable parts, ReaderOptions readerOptions) + internal RarArchiveEntry( + RarArchive archive, + IEnumerable parts, + ReaderOptions readerOptions + ) { this.parts = parts.ToList(); this.archive = archive; @@ -63,10 +67,18 @@ namespace SharpCompress.Archives.Rar { if (IsRarV3) { - return new RarStream(archive.UnpackV1.Value, FileHeader, new MultiVolumeReadOnlyStream(Parts.Cast(), archive)); + return new RarStream( + archive.UnpackV1.Value, + FileHeader, + new MultiVolumeReadOnlyStream(Parts.Cast(), archive) + ); } - return new RarStream(archive.UnpackV2017.Value, FileHeader, new MultiVolumeReadOnlyStream(Parts.Cast(), archive)); + return new RarStream( + archive.UnpackV2017.Value, + FileHeader, + new MultiVolumeReadOnlyStream(Parts.Cast(), archive) + ); } public bool IsComplete @@ -82,7 +94,9 @@ namespace SharpCompress.Archives.Rar { if (!readerOptions.DisableCheckIncomplete && !IsComplete) { - throw new IncompleteArchiveException("ArchiveEntry is incomplete and cannot perform this operation."); + throw new IncompleteArchiveException( + "ArchiveEntry is incomplete and cannot perform this operation." + ); } } } diff --git a/src/SharpCompress/Archives/Rar/RarArchiveEntryFactory.cs b/src/SharpCompress/Archives/Rar/RarArchiveEntryFactory.cs index 2d471c18..e345e8d3 100644 --- a/src/SharpCompress/Archives/Rar/RarArchiveEntryFactory.cs +++ b/src/SharpCompress/Archives/Rar/RarArchiveEntryFactory.cs @@ -17,7 +17,9 @@ namespace SharpCompress.Archives.Rar } } - private static IEnumerable> GetMatchedFileParts(IEnumerable parts) + private static IEnumerable> GetMatchedFileParts( + IEnumerable parts + ) { var groupedParts = new List(); foreach (RarFilePart fp in GetFileParts(parts)) @@ -36,9 +38,11 @@ namespace SharpCompress.Archives.Rar } } - internal static IEnumerable GetEntries(RarArchive archive, - IEnumerable rarParts, - ReaderOptions readerOptions) + internal static IEnumerable GetEntries( + RarArchive archive, + IEnumerable rarParts, + ReaderOptions readerOptions + ) { foreach (var groupedParts in GetMatchedFileParts(rarParts)) { @@ -46,4 +50,4 @@ namespace SharpCompress.Archives.Rar } } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Archives/Rar/RarArchiveVolumeFactory.cs b/src/SharpCompress/Archives/Rar/RarArchiveVolumeFactory.cs index abbd73b3..58ab96eb 100644 --- a/src/SharpCompress/Archives/Rar/RarArchiveVolumeFactory.cs +++ b/src/SharpCompress/Archives/Rar/RarArchiveVolumeFactory.cs @@ -17,15 +17,38 @@ namespace SharpCompress.Archives.Rar FileInfo? item = null; //new style rar - ..part1 | /part01 | part001 .... - Match m = Regex.Match(part1.Name, @"^(.*\.part)([0-9]+)(\.rar)$", RegexOptions.IgnoreCase); + Match m = Regex.Match( + part1.Name, + @"^(.*\.part)([0-9]+)(\.rar)$", + RegexOptions.IgnoreCase + ); if (m.Success) - item = new FileInfo(Path.Combine(part1.DirectoryName!, String.Concat(m.Groups[1].Value, (index + 1).ToString().PadLeft(m.Groups[2].Value.Length, '0'), m.Groups[3].Value))); + item = new FileInfo( + Path.Combine( + part1.DirectoryName!, + String.Concat( + m.Groups[1].Value, + (index + 1).ToString().PadLeft(m.Groups[2].Value.Length, '0'), + m.Groups[3].Value + ) + ) + ); else { //old style - ...rar, .r00, .r01 ... m = Regex.Match(part1.Name, @"^(.*\.r)(ar|[0-9]+)$", RegexOptions.IgnoreCase); if (m.Success) - item = new FileInfo(Path.Combine(part1.DirectoryName!, String.Concat(m.Groups[1].Value, index == 0 ? "ar" : (index - 1).ToString().PadLeft(m.Groups[2].Value.Length, '0')))); + item = new FileInfo( + Path.Combine( + part1.DirectoryName!, + String.Concat( + m.Groups[1].Value, + index == 0 + ? "ar" + : (index - 1).ToString().PadLeft(m.Groups[2].Value.Length, '0') + ) + ) + ); else //split .001, .002 .... return ArchiveVolumeFactory.GetFilePart(index, part1); } @@ -35,6 +58,5 @@ namespace SharpCompress.Archives.Rar return null; //no more items } - } } diff --git a/src/SharpCompress/Archives/Rar/SeekableFilePart.cs b/src/SharpCompress/Archives/Rar/SeekableFilePart.cs index 1e4758ad..601c9788 100644 --- a/src/SharpCompress/Archives/Rar/SeekableFilePart.cs +++ b/src/SharpCompress/Archives/Rar/SeekableFilePart.cs @@ -9,8 +9,13 @@ namespace SharpCompress.Archives.Rar private readonly Stream stream; private readonly string? password; - internal SeekableFilePart(MarkHeader mh, FileHeader fh, int index, Stream stream, string? password) - : base(mh, fh, index) + internal SeekableFilePart( + MarkHeader mh, + FileHeader fh, + int index, + Stream stream, + string? password + ) : base(mh, fh, index) { this.stream = stream; this.password = password; @@ -26,6 +31,7 @@ namespace SharpCompress.Archives.Rar return stream; } - internal override string FilePartName => "Unknown Stream - File Entry: " + FileHeader.FileName; + 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 68def3f7..ac5dc5de 100644 --- a/src/SharpCompress/Archives/Rar/StreamRarArchiveVolume.cs +++ b/src/SharpCompress/Archives/Rar/StreamRarArchiveVolume.cs @@ -10,9 +10,7 @@ namespace SharpCompress.Archives.Rar internal class StreamRarArchiveVolume : RarVolume { internal StreamRarArchiveVolume(Stream stream, ReaderOptions options, int index = 0) - : base(StreamingMode.Seekable, stream, options, index) - { - } + : base(StreamingMode.Seekable, stream, options, index) { } internal override IEnumerable ReadFileParts() { @@ -21,7 +19,13 @@ namespace SharpCompress.Archives.Rar internal override RarFilePart CreateFilePart(MarkHeader markHeader, FileHeader fileHeader) { - return new SeekableFilePart(markHeader, fileHeader, this.Index, Stream, ReaderOptions.Password); + return new SeekableFilePart( + markHeader, + fileHeader, + this.Index, + Stream, + ReaderOptions.Password + ); } } } diff --git a/src/SharpCompress/Archives/SevenZip/SevenZipArchive.cs b/src/SharpCompress/Archives/SevenZip/SevenZipArchive.cs index 276f1399..99c455d7 100644 --- a/src/SharpCompress/Archives/SevenZip/SevenZipArchive.cs +++ b/src/SharpCompress/Archives/SevenZip/SevenZipArchive.cs @@ -15,6 +15,7 @@ namespace SharpCompress.Archives.SevenZip public class SevenZipArchive : AbstractArchive { private ArchiveDatabase database; + /// /// Constructor expects a filepath to an existing file. /// @@ -34,7 +35,13 @@ namespace SharpCompress.Archives.SevenZip public static SevenZipArchive Open(FileInfo fileInfo, ReaderOptions readerOptions = null) { fileInfo.CheckNotNull("fileInfo"); - return new SevenZipArchive(new SourceStream(fileInfo, i => ArchiveVolumeFactory.GetFilePart(i, fileInfo), readerOptions ?? new ReaderOptions())); + return new SevenZipArchive( + new SourceStream( + fileInfo, + i => ArchiveVolumeFactory.GetFilePart(i, fileInfo), + readerOptions ?? new ReaderOptions() + ) + ); } /// @@ -42,11 +49,20 @@ namespace SharpCompress.Archives.SevenZip /// /// /// - public static SevenZipArchive Open(IEnumerable fileInfos, ReaderOptions readerOptions = null) + public static SevenZipArchive Open( + IEnumerable fileInfos, + ReaderOptions readerOptions = null + ) { fileInfos.CheckNotNull(nameof(fileInfos)); FileInfo[] files = fileInfos.ToArray(); - return new SevenZipArchive(new SourceStream(files[0], i => i < files.Length ? files[i] : null, readerOptions ?? new ReaderOptions())); + return new SevenZipArchive( + new SourceStream( + files[0], + i => i < files.Length ? files[i] : null, + readerOptions ?? new ReaderOptions() + ) + ); } /// @@ -54,11 +70,20 @@ namespace SharpCompress.Archives.SevenZip /// /// /// - public static SevenZipArchive Open(IEnumerable streams, ReaderOptions readerOptions = null) + public static SevenZipArchive Open( + IEnumerable streams, + ReaderOptions readerOptions = null + ) { streams.CheckNotNull(nameof(streams)); Stream[] strms = streams.ToArray(); - return new SevenZipArchive(new SourceStream(strms[0], i => i < strms.Length ? strms[i] : null, readerOptions ?? new ReaderOptions())); + return new SevenZipArchive( + new SourceStream( + strms[0], + i => i < strms.Length ? strms[i] : null, + readerOptions ?? new ReaderOptions() + ) + ); } /// @@ -69,7 +94,9 @@ namespace SharpCompress.Archives.SevenZip public static SevenZipArchive Open(Stream stream, ReaderOptions readerOptions = null) { stream.CheckNotNull("stream"); - return new SevenZipArchive(new SourceStream(stream, i => null, readerOptions ?? new ReaderOptions())); + return new SevenZipArchive( + new SourceStream(stream, i => null, readerOptions ?? new ReaderOptions()) + ); } /// @@ -77,10 +104,7 @@ namespace SharpCompress.Archives.SevenZip /// /// /// - internal SevenZipArchive(SourceStream srcStream) - : base(ArchiveType.SevenZip, srcStream) - { - } + internal SevenZipArchive(SourceStream srcStream) : base(ArchiveType.SevenZip, srcStream) { } protected override IEnumerable LoadVolumes(SourceStream srcStream) { @@ -106,12 +130,11 @@ namespace SharpCompress.Archives.SevenZip } } - internal SevenZipArchive() - : base(ArchiveType.SevenZip) - { - } + internal SevenZipArchive() : base(ArchiveType.SevenZip) { } - protected override IEnumerable LoadEntries(IEnumerable volumes) + protected override IEnumerable LoadEntries( + IEnumerable volumes + ) { var stream = volumes.Single().Stream; LoadFactory(stream); @@ -119,9 +142,14 @@ namespace SharpCompress.Archives.SevenZip for (int 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)); + entries[i] = new SevenZipArchiveEntry( + this, + new SevenZipFilePart(stream, database, i, file, ReaderOptions.ArchiveEncoding) + ); } - foreach (var group in entries.Where(x => !x.IsDirectory).GroupBy(x => x.FilePart.Folder)) + foreach ( + var group in entries.Where(x => !x.IsDirectory).GroupBy(x => x.FilePart.Folder) + ) { var isSolid = false; foreach (var entry in group) @@ -157,7 +185,8 @@ namespace SharpCompress.Archives.SevenZip } } - private static ReadOnlySpan SIGNATURE => new byte[] { (byte)'7', (byte)'z', 0xBC, 0xAF, 0x27, 0x1C }; + private static ReadOnlySpan SIGNATURE => + new byte[] { (byte)'7', (byte)'z', 0xBC, 0xAF, 0x27, 0x1C }; private static bool SignatureMatch(Stream stream) { @@ -171,7 +200,14 @@ namespace SharpCompress.Archives.SevenZip return new SevenZipReader(ReaderOptions, this); } - public override bool IsSolid { get { return Entries.Where(x => !x.IsDirectory).GroupBy(x => x.FilePart.Folder).Count() > 1; } } + public override bool IsSolid + { + get + { + return Entries.Where(x => !x.IsDirectory).GroupBy(x => x.FilePart.Folder).Count() + > 1; + } + } public override long TotalSize { @@ -205,7 +241,9 @@ namespace SharpCompress.Archives.SevenZip { yield return dir; } - foreach (var group in entries.Where(x => !x.IsDirectory).GroupBy(x => x.FilePart.Folder)) + foreach ( + var group in entries.Where(x => !x.IsDirectory).GroupBy(x => x.FilePart.Folder) + ) { currentFolder = group.Key; if (group.Key is null) @@ -214,7 +252,11 @@ namespace SharpCompress.Archives.SevenZip } else { - currentStream = archive.database.GetFolderStream(stream, currentFolder, new PasswordProvider(Options.Password)); + currentStream = archive.database.GetFolderStream( + stream, + currentFolder, + new PasswordProvider(Options.Password) + ); } foreach (var entry in group) { diff --git a/src/SharpCompress/Archives/SevenZip/SevenZipArchiveEntry.cs b/src/SharpCompress/Archives/SevenZip/SevenZipArchiveEntry.cs index ea80b5cb..c276eade 100644 --- a/src/SharpCompress/Archives/SevenZip/SevenZipArchiveEntry.cs +++ b/src/SharpCompress/Archives/SevenZip/SevenZipArchiveEntry.cs @@ -5,8 +5,7 @@ namespace SharpCompress.Archives.SevenZip { public class SevenZipArchiveEntry : SevenZipEntry, IArchiveEntry { - internal SevenZipArchiveEntry(SevenZipArchive archive, SevenZipFilePart part) - : base(part) + internal SevenZipArchiveEntry(SevenZipArchive archive, SevenZipFilePart part) : base(part) { Archive = archive; } @@ -25,4 +24,4 @@ namespace SharpCompress.Archives.SevenZip /// public bool IsAnti => FilePart.Header.IsAnti; } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Archives/Tar/TarArchive.cs b/src/SharpCompress/Archives/Tar/TarArchive.cs index 51bdbc1f..1357660f 100644 --- a/src/SharpCompress/Archives/Tar/TarArchive.cs +++ b/src/SharpCompress/Archives/Tar/TarArchive.cs @@ -34,7 +34,13 @@ namespace SharpCompress.Archives.Tar public static TarArchive Open(FileInfo fileInfo, ReaderOptions? readerOptions = null) { fileInfo.CheckNotNull(nameof(fileInfo)); - return new TarArchive(new SourceStream(fileInfo, i => ArchiveVolumeFactory.GetFilePart(i, fileInfo), readerOptions ?? new ReaderOptions())); + return new TarArchive( + new SourceStream( + fileInfo, + i => ArchiveVolumeFactory.GetFilePart(i, fileInfo), + readerOptions ?? new ReaderOptions() + ) + ); } /// @@ -42,11 +48,20 @@ namespace SharpCompress.Archives.Tar /// /// /// - public static TarArchive Open(IEnumerable fileInfos, ReaderOptions? readerOptions = null) + public static TarArchive Open( + IEnumerable fileInfos, + ReaderOptions? readerOptions = null + ) { fileInfos.CheckNotNull(nameof(fileInfos)); FileInfo[] files = fileInfos.ToArray(); - return new TarArchive(new SourceStream(files[0], i => i < files.Length ? files[i] : null, readerOptions ?? new ReaderOptions())); + return new TarArchive( + new SourceStream( + files[0], + i => i < files.Length ? files[i] : null, + readerOptions ?? new ReaderOptions() + ) + ); } /// @@ -54,11 +69,20 @@ namespace SharpCompress.Archives.Tar /// /// /// - public static TarArchive Open(IEnumerable streams, ReaderOptions? readerOptions = null) + public static TarArchive Open( + IEnumerable streams, + ReaderOptions? readerOptions = null + ) { streams.CheckNotNull(nameof(streams)); Stream[] strms = streams.ToArray(); - return new TarArchive(new SourceStream(strms[0], i => i < strms.Length ? strms[i] : null, readerOptions ?? new ReaderOptions())); + return new TarArchive( + new SourceStream( + strms[0], + i => i < strms.Length ? strms[i] : null, + readerOptions ?? new ReaderOptions() + ) + ); } /// @@ -69,7 +93,9 @@ namespace SharpCompress.Archives.Tar public static TarArchive Open(Stream stream, ReaderOptions? readerOptions = null) { stream.CheckNotNull(nameof(stream)); - return new TarArchive(new SourceStream(stream, i => null, readerOptions ?? new ReaderOptions())); + return new TarArchive( + new SourceStream(stream, i => null, readerOptions ?? new ReaderOptions()) + ); } public static bool IsTarFile(string filePath) @@ -95,12 +121,13 @@ namespace SharpCompress.Archives.Tar { TarHeader tarHeader = new TarHeader(new ArchiveEncoding()); bool readSucceeded = tarHeader.Read(new BinaryReader(stream)); - bool isEmptyArchive = tarHeader.Name.Length == 0 && tarHeader.Size == 0 && Enum.IsDefined(typeof(EntryType), tarHeader.EntryType); + bool isEmptyArchive = + tarHeader.Name.Length == 0 + && tarHeader.Size == 0 + && Enum.IsDefined(typeof(EntryType), tarHeader.EntryType); return readSucceeded || isEmptyArchive; } - catch - { - } + catch { } return false; } @@ -116,21 +143,21 @@ namespace SharpCompress.Archives.Tar /// /// /// - internal TarArchive(SourceStream srcStream) - : base(ArchiveType.Tar, srcStream) - { - } + internal TarArchive(SourceStream srcStream) : base(ArchiveType.Tar, srcStream) { } - internal TarArchive() - : base(ArchiveType.Tar) - { - } + internal TarArchive() : base(ArchiveType.Tar) { } protected override IEnumerable LoadEntries(IEnumerable volumes) { Stream stream = volumes.Single().Stream; TarHeader? previousHeader = null; - foreach (TarHeader? header in TarHeaderFactory.ReadHeader(StreamingMode.Seekable, stream, ReaderOptions.ArchiveEncoding)) + foreach ( + TarHeader? header in TarHeaderFactory.ReadHeader( + StreamingMode.Seekable, + stream, + ReaderOptions.ArchiveEncoding + ) + ) { if (header != null) { @@ -142,8 +169,11 @@ namespace SharpCompress.Archives.Tar { if (previousHeader != null) { - var entry = new TarArchiveEntry(this, new TarFilePart(previousHeader, stream), - CompressionType.None); + var entry = new TarArchiveEntry( + this, + new TarFilePart(previousHeader, stream), + CompressionType.None + ); var oldStreamPos = stream.Position; @@ -155,7 +185,9 @@ namespace SharpCompress.Archives.Tar memoryStream.Position = 0; var bytes = memoryStream.ToArray(); - header.Name = ReaderOptions.ArchiveEncoding.Decode(bytes).TrimNulls(); + header.Name = ReaderOptions.ArchiveEncoding + .Decode(bytes) + .TrimNulls(); } } @@ -163,7 +195,11 @@ namespace SharpCompress.Archives.Tar previousHeader = null; } - yield return new TarArchiveEntry(this, new TarFilePart(header, stream), CompressionType.None); + yield return new TarArchiveEntry( + this, + new TarFilePart(header, stream), + CompressionType.None + ); } } } @@ -174,21 +210,35 @@ namespace SharpCompress.Archives.Tar return new TarArchive(); } - protected override TarArchiveEntry CreateEntryInternal(string filePath, Stream source, - long size, DateTime? modified, bool closeStream) + protected override TarArchiveEntry CreateEntryInternal( + string filePath, + Stream source, + long size, + DateTime? modified, + bool closeStream + ) { - return new TarWritableArchiveEntry(this, source, CompressionType.Unknown, filePath, size, modified, - closeStream); + return new TarWritableArchiveEntry( + this, + source, + CompressionType.Unknown, + filePath, + size, + modified, + closeStream + ); } - protected override void SaveTo(Stream stream, WriterOptions options, - IEnumerable oldEntries, - IEnumerable newEntries) + protected override void SaveTo( + Stream stream, + WriterOptions options, + IEnumerable oldEntries, + IEnumerable newEntries + ) { using (var writer = new TarWriter(stream, new TarWriterOptions(options))) { - foreach (var entry in oldEntries.Concat(newEntries) - .Where(x => !x.IsDirectory)) + foreach (var entry in oldEntries.Concat(newEntries).Where(x => !x.IsDirectory)) { using (var entryStream = entry.OpenEntryStream()) { diff --git a/src/SharpCompress/Archives/Tar/TarArchiveEntry.cs b/src/SharpCompress/Archives/Tar/TarArchiveEntry.cs index 51a0a49b..99a2498f 100644 --- a/src/SharpCompress/Archives/Tar/TarArchiveEntry.cs +++ b/src/SharpCompress/Archives/Tar/TarArchiveEntry.cs @@ -7,8 +7,11 @@ namespace SharpCompress.Archives.Tar { public class TarArchiveEntry : TarEntry, IArchiveEntry { - internal TarArchiveEntry(TarArchive archive, TarFilePart part, CompressionType compressionType) - : base(part, compressionType) + internal TarArchiveEntry( + TarArchive archive, + TarFilePart part, + CompressionType compressionType + ) : base(part, compressionType) { Archive = archive; } @@ -26,4 +29,4 @@ namespace SharpCompress.Archives.Tar #endregion } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Archives/Tar/TarWritableArchiveEntry.cs b/src/SharpCompress/Archives/Tar/TarWritableArchiveEntry.cs index 1f96ca3d..7c6cfbcb 100644 --- a/src/SharpCompress/Archives/Tar/TarWritableArchiveEntry.cs +++ b/src/SharpCompress/Archives/Tar/TarWritableArchiveEntry.cs @@ -13,9 +13,15 @@ namespace SharpCompress.Archives.Tar private readonly bool closeStream; private readonly Stream stream; - internal TarWritableArchiveEntry(TarArchive archive, Stream stream, CompressionType compressionType, - string path, long size, DateTime? lastModified, bool closeStream) - : base(archive, null, compressionType) + internal TarWritableArchiveEntry( + TarArchive archive, + Stream stream, + CompressionType compressionType, + string path, + long size, + DateTime? lastModified, + bool closeStream + ) : base(archive, null, compressionType) { this.stream = stream; Key = path; diff --git a/src/SharpCompress/Archives/Zip/ZipArchive.cs b/src/SharpCompress/Archives/Zip/ZipArchive.cs index 97f83e02..f5c52863 100644 --- a/src/SharpCompress/Archives/Zip/ZipArchive.cs +++ b/src/SharpCompress/Archives/Zip/ZipArchive.cs @@ -18,6 +18,7 @@ namespace SharpCompress.Archives.Zip { #nullable disable private readonly SeekableZipHeaderFactory headerFactory; + #nullable enable /// @@ -31,10 +32,12 @@ namespace SharpCompress.Archives.Zip /// /// /// - internal ZipArchive(SourceStream srcStream) - : base(ArchiveType.Zip, srcStream) + internal ZipArchive(SourceStream srcStream) : base(ArchiveType.Zip, srcStream) { - headerFactory = new SeekableZipHeaderFactory(srcStream.ReaderOptions.Password, srcStream.ReaderOptions.ArchiveEncoding); + headerFactory = new SeekableZipHeaderFactory( + srcStream.ReaderOptions.Password, + srcStream.ReaderOptions.ArchiveEncoding + ); } /// @@ -56,7 +59,13 @@ namespace SharpCompress.Archives.Zip public static ZipArchive Open(FileInfo fileInfo, ReaderOptions? readerOptions = null) { fileInfo.CheckNotNull(nameof(fileInfo)); - return new ZipArchive(new SourceStream(fileInfo, i => ZipArchiveVolumeFactory.GetFilePart(i, fileInfo), readerOptions ?? new ReaderOptions())); + return new ZipArchive( + new SourceStream( + fileInfo, + i => ZipArchiveVolumeFactory.GetFilePart(i, fileInfo), + readerOptions ?? new ReaderOptions() + ) + ); } /// @@ -64,11 +73,20 @@ namespace SharpCompress.Archives.Zip /// /// /// - public static ZipArchive Open(IEnumerable fileInfos, ReaderOptions? readerOptions = null) + public static ZipArchive Open( + IEnumerable fileInfos, + ReaderOptions? readerOptions = null + ) { fileInfos.CheckNotNull(nameof(fileInfos)); FileInfo[] files = fileInfos.ToArray(); - return new ZipArchive(new SourceStream(files[0], i => i < files.Length ? files[i] : null, readerOptions ?? new ReaderOptions())); + return new ZipArchive( + new SourceStream( + files[0], + i => i < files.Length ? files[i] : null, + readerOptions ?? new ReaderOptions() + ) + ); } /// @@ -76,11 +94,20 @@ namespace SharpCompress.Archives.Zip /// /// /// - public static ZipArchive Open(IEnumerable streams, ReaderOptions? readerOptions = null) + public static ZipArchive Open( + IEnumerable streams, + ReaderOptions? readerOptions = null + ) { streams.CheckNotNull(nameof(streams)); Stream[] strms = streams.ToArray(); - return new ZipArchive(new SourceStream(strms[0], i => i < strms.Length ? strms[i] : null, readerOptions ?? new ReaderOptions())); + return new ZipArchive( + new SourceStream( + strms[0], + i => i < strms.Length ? strms[i] : null, + readerOptions ?? new ReaderOptions() + ) + ); } /// @@ -91,7 +118,9 @@ namespace SharpCompress.Archives.Zip public static ZipArchive Open(Stream stream, ReaderOptions? readerOptions = null) { stream.CheckNotNull(nameof(stream)); - return new ZipArchive(new SourceStream(stream, i => null, readerOptions ?? new ReaderOptions())); + return new ZipArchive( + new SourceStream(stream, i => null, readerOptions ?? new ReaderOptions()) + ); } public static bool IsZipFile(string filePath, string? password = null) @@ -113,10 +142,15 @@ namespace SharpCompress.Archives.Zip public static bool IsZipFile(Stream stream, string? password = null) { - StreamingZipHeaderFactory headerFactory = new StreamingZipHeaderFactory(password, new ArchiveEncoding()); + StreamingZipHeaderFactory headerFactory = new StreamingZipHeaderFactory( + password, + new ArchiveEncoding() + ); try { - ZipHeader? header = headerFactory.ReadStreamHeader(stream).FirstOrDefault(x => x.ZipHeaderType != ZipHeaderType.Split); + ZipHeader? header = headerFactory + .ReadStreamHeader(stream) + .FirstOrDefault(x => x.ZipHeaderType != ZipHeaderType.Split); if (header is null) { return false; @@ -135,15 +169,23 @@ namespace SharpCompress.Archives.Zip public static bool IsZipMulti(Stream stream, string? password = null) { - StreamingZipHeaderFactory headerFactory = new StreamingZipHeaderFactory(password, new ArchiveEncoding()); + StreamingZipHeaderFactory headerFactory = new StreamingZipHeaderFactory( + password, + new ArchiveEncoding() + ); try { - ZipHeader? header = headerFactory.ReadStreamHeader(stream).FirstOrDefault(x => x.ZipHeaderType != ZipHeaderType.Split); + ZipHeader? header = headerFactory + .ReadStreamHeader(stream) + .FirstOrDefault(x => x.ZipHeaderType != ZipHeaderType.Split); if (header is null) { if (stream.CanSeek) //could be multipart. Test for central directory - might not be z64 safe { - SeekableZipHeaderFactory z = new SeekableZipHeaderFactory(password, new ArchiveEncoding()); + SeekableZipHeaderFactory z = new SeekableZipHeaderFactory( + password, + new ArchiveEncoding() + ); var x = z.ReadSeekableHeader(stream).FirstOrDefault(); return x?.ZipHeaderType == ZipHeaderType.DirectoryEntry; } @@ -191,10 +233,7 @@ namespace SharpCompress.Archives.Zip return new ZipVolume(base.SrcStream, ReaderOptions, idx++).AsEnumerable(); } - internal ZipArchive() - : base(ArchiveType.Zip) - { - } + internal ZipArchive() : base(ArchiveType.Zip) { } protected override IEnumerable LoadEntries(IEnumerable volumes) { @@ -206,19 +245,30 @@ namespace SharpCompress.Archives.Zip switch (h.ZipHeaderType) { case ZipHeaderType.DirectoryEntry: - { - DirectoryEntryHeader deh = (DirectoryEntryHeader)h; - Stream s; - if (deh.RelativeOffsetOfEntryHeader + deh.CompressedSize > vols[deh.DiskNumberStart].Stream.Length) + { - var v = vols.Skip(deh.DiskNumberStart).ToArray(); - s = new SourceStream(v[0].Stream, i => i < v.Length ? v[i].Stream : null, new ReaderOptions() { LeaveStreamOpen = true }); + DirectoryEntryHeader deh = (DirectoryEntryHeader)h; + Stream s; + if ( + deh.RelativeOffsetOfEntryHeader + deh.CompressedSize + > vols[deh.DiskNumberStart].Stream.Length + ) + { + var v = vols.Skip(deh.DiskNumberStart).ToArray(); + s = new SourceStream( + v[0].Stream, + i => i < v.Length ? v[i].Stream : null, + new ReaderOptions() { LeaveStreamOpen = true } + ); + } + else + s = vols[deh.DiskNumberStart].Stream; + yield return new ZipArchiveEntry( + this, + new SeekableZipFilePart(headerFactory, deh, s) + ); } - else - s = vols[deh.DiskNumberStart].Stream; - yield return new ZipArchiveEntry(this, new SeekableZipFilePart(headerFactory, deh, s)); - } - break; + break; case ZipHeaderType.DirectoryEnd: { byte[] bytes = ((DirectoryEndHeader)h).Comment ?? Array.Empty(); @@ -235,14 +285,16 @@ namespace SharpCompress.Archives.Zip SaveTo(stream, new WriterOptions(CompressionType.Deflate)); } - protected override void SaveTo(Stream stream, WriterOptions options, - IEnumerable oldEntries, - IEnumerable newEntries) + protected override void SaveTo( + Stream stream, + WriterOptions options, + IEnumerable oldEntries, + IEnumerable newEntries + ) { using (var writer = new ZipWriter(stream, new ZipWriterOptions(options))) { - foreach (var entry in oldEntries.Concat(newEntries) - .Where(x => !x.IsDirectory)) + foreach (var entry in oldEntries.Concat(newEntries).Where(x => !x.IsDirectory)) { using (var entryStream = entry.OpenEntryStream()) { @@ -252,8 +304,13 @@ namespace SharpCompress.Archives.Zip } } - protected override ZipArchiveEntry CreateEntryInternal(string filePath, Stream source, long size, DateTime? modified, - bool closeStream) + protected override ZipArchiveEntry CreateEntryInternal( + string filePath, + Stream source, + long size, + DateTime? modified, + bool closeStream + ) { return new ZipWritableArchiveEntry(this, source, filePath, size, modified, closeStream); } diff --git a/src/SharpCompress/Archives/Zip/ZipArchiveEntry.cs b/src/SharpCompress/Archives/Zip/ZipArchiveEntry.cs index 2aad807b..dd1354fd 100644 --- a/src/SharpCompress/Archives/Zip/ZipArchiveEntry.cs +++ b/src/SharpCompress/Archives/Zip/ZipArchiveEntry.cs @@ -6,8 +6,7 @@ namespace SharpCompress.Archives.Zip { public class ZipArchiveEntry : ZipEntry, IArchiveEntry { - internal ZipArchiveEntry(ZipArchive archive, SeekableZipFilePart? part) - : base(part) + internal ZipArchiveEntry(ZipArchive archive, SeekableZipFilePart? part) : base(part) { Archive = archive; } @@ -27,4 +26,4 @@ namespace SharpCompress.Archives.Zip public string? Comment => ((SeekableZipFilePart)Parts.Single()).Comment; } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Archives/Zip/ZipArchiveVolumeFactory.cs b/src/SharpCompress/Archives/Zip/ZipArchiveVolumeFactory.cs index 439e5a70..e38e4af1 100644 --- a/src/SharpCompress/Archives/Zip/ZipArchiveVolumeFactory.cs +++ b/src/SharpCompress/Archives/Zip/ZipArchiveVolumeFactory.cs @@ -18,9 +18,22 @@ namespace SharpCompress.Archives.Zip //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); + Match m = Regex.Match( + part1.Name, + @"^(.*\.)(zipx?|zx?[0-9]+)$", + RegexOptions.IgnoreCase + ); if (m.Success) - item = new FileInfo(Path.Combine(part1.DirectoryName!, String.Concat(m.Groups[1].Value, Regex.Replace(m.Groups[2].Value, @"[^xz]", ""), index.ToString().PadLeft(2, '0')))); + item = new FileInfo( + Path.Combine( + part1.DirectoryName!, + String.Concat( + m.Groups[1].Value, + Regex.Replace(m.Groups[2].Value, @"[^xz]", ""), + index.ToString().PadLeft(2, '0') + ) + ) + ); else //split - 001, 002 ... return ArchiveVolumeFactory.GetFilePart(index, part1); @@ -29,6 +42,5 @@ namespace SharpCompress.Archives.Zip return null; //no more items } - } } diff --git a/src/SharpCompress/Archives/Zip/ZipWritableArchiveEntry.cs b/src/SharpCompress/Archives/Zip/ZipWritableArchiveEntry.cs index 7a91993a..ac595792 100644 --- a/src/SharpCompress/Archives/Zip/ZipWritableArchiveEntry.cs +++ b/src/SharpCompress/Archives/Zip/ZipWritableArchiveEntry.cs @@ -12,9 +12,14 @@ namespace SharpCompress.Archives.Zip private readonly Stream stream; private bool isDisposed; - internal ZipWritableArchiveEntry(ZipArchive archive, Stream stream, string path, long size, - DateTime? lastModified, bool closeStream) - : base(archive, null) + internal ZipWritableArchiveEntry( + ZipArchive archive, + Stream stream, + string path, + long size, + DateTime? lastModified, + bool closeStream + ) : base(archive, null) { this.stream = stream; Key = path; diff --git a/src/SharpCompress/Common/ArchiveEncoding.cs b/src/SharpCompress/Common/ArchiveEncoding.cs index 81e81099..d50f0930 100644 --- a/src/SharpCompress/Common/ArchiveEncoding.cs +++ b/src/SharpCompress/Common/ArchiveEncoding.cs @@ -26,10 +26,8 @@ namespace SharpCompress.Common /// string Func(bytes, index, length) public Func? CustomDecoder { get; set; } - public ArchiveEncoding() - : this(Encoding.Default, Encoding.Default) - { - } + public ArchiveEncoding() : this(Encoding.Default, Encoding.Default) { } + public ArchiveEncoding(Encoding def, Encoding password) { Default = def; @@ -70,7 +68,8 @@ namespace SharpCompress.Common public Func GetDecoder() { - return CustomDecoder ?? ((bytes, index, count) => GetEncoding().GetString(bytes, index, count)); + return CustomDecoder + ?? ((bytes, index, count) => GetEncoding().GetString(bytes, index, count)); } } } diff --git a/src/SharpCompress/Common/ArchiveException.cs b/src/SharpCompress/Common/ArchiveException.cs index 18207c64..51fe7463 100644 --- a/src/SharpCompress/Common/ArchiveException.cs +++ b/src/SharpCompress/Common/ArchiveException.cs @@ -4,9 +4,6 @@ namespace SharpCompress.Common { public class ArchiveException : Exception { - public ArchiveException(string message) - : base(message) - { - } + public ArchiveException(string message) : base(message) { } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/ArchiveExtractionEventArgs.cs b/src/SharpCompress/Common/ArchiveExtractionEventArgs.cs index b1c9fc75..0be0383c 100644 --- a/src/SharpCompress/Common/ArchiveExtractionEventArgs.cs +++ b/src/SharpCompress/Common/ArchiveExtractionEventArgs.cs @@ -11,4 +11,4 @@ namespace SharpCompress.Common public T Item { get; } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/ArchiveType.cs b/src/SharpCompress/Common/ArchiveType.cs index a0d3097a..1a899398 100644 --- a/src/SharpCompress/Common/ArchiveType.cs +++ b/src/SharpCompress/Common/ArchiveType.cs @@ -8,4 +8,4 @@ SevenZip, GZip } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/CompressedBytesReadEventArgs.cs b/src/SharpCompress/Common/CompressedBytesReadEventArgs.cs index 322a3c64..c87a3588 100644 --- a/src/SharpCompress/Common/CompressedBytesReadEventArgs.cs +++ b/src/SharpCompress/Common/CompressedBytesReadEventArgs.cs @@ -4,7 +4,10 @@ namespace SharpCompress.Common { public sealed class CompressedBytesReadEventArgs : EventArgs { - public CompressedBytesReadEventArgs(long compressedBytesRead, long currentFilePartCompressedBytesRead) + public CompressedBytesReadEventArgs( + long compressedBytesRead, + long currentFilePartCompressedBytesRead + ) { CompressedBytesRead = compressedBytesRead; CurrentFilePartCompressedBytesRead = currentFilePartCompressedBytesRead; @@ -20,4 +23,4 @@ namespace SharpCompress.Common /// public long CurrentFilePartCompressedBytesRead { get; } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/CompressionType.cs b/src/SharpCompress/Common/CompressionType.cs index 23ed354f..7dfc857c 100644 --- a/src/SharpCompress/Common/CompressionType.cs +++ b/src/SharpCompress/Common/CompressionType.cs @@ -16,4 +16,4 @@ Unknown, Deflate64 } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/CryptographicException.cs b/src/SharpCompress/Common/CryptographicException.cs index 450cd237..3bdfccb5 100644 --- a/src/SharpCompress/Common/CryptographicException.cs +++ b/src/SharpCompress/Common/CryptographicException.cs @@ -4,9 +4,6 @@ namespace SharpCompress.Common { public class CryptographicException : Exception { - public CryptographicException(string message) - : base(message) - { - } + public CryptographicException(string message) : base(message) { } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/Entry.cs b/src/SharpCompress/Common/Entry.cs index 06afcabd..17ecc31b 100644 --- a/src/SharpCompress/Common/Entry.cs +++ b/src/SharpCompress/Common/Entry.cs @@ -73,6 +73,7 @@ namespace SharpCompress.Common public int VolumeIndexFirst => this.Parts?.FirstOrDefault()?.Index ?? 0; public int VolumeIndexLast => this.Parts?.LastOrDefault()?.Index ?? 0; + /// public override string ToString() => Key; @@ -80,9 +81,7 @@ namespace SharpCompress.Common public bool IsSolid { get; set; } - internal virtual void Close() - { - } + internal virtual void Close() { } /// /// Entry file attribute. diff --git a/src/SharpCompress/Common/EntryStream.cs b/src/SharpCompress/Common/EntryStream.cs index 43ca0537..44d8e235 100644 --- a/src/SharpCompress/Common/EntryStream.cs +++ b/src/SharpCompress/Common/EntryStream.cs @@ -47,13 +47,15 @@ namespace SharpCompress.Common public override bool CanWrite => false; - public override void Flush() - { - } + public override void Flush() { } public override long Length => _stream.Length; - public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); } + public override long Position + { + get => throw new NotSupportedException(); + set => throw new NotSupportedException(); + } public override int Read(byte[] buffer, int offset, int count) { @@ -90,4 +92,4 @@ namespace SharpCompress.Common throw new NotSupportedException(); } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/ExtractionException.cs b/src/SharpCompress/Common/ExtractionException.cs index be5e688c..51f9bc1e 100644 --- a/src/SharpCompress/Common/ExtractionException.cs +++ b/src/SharpCompress/Common/ExtractionException.cs @@ -4,14 +4,8 @@ namespace SharpCompress.Common { public class ExtractionException : Exception { - public ExtractionException(string message) - : base(message) - { - } + public ExtractionException(string message) : base(message) { } - public ExtractionException(string message, Exception inner) - : base(message, inner) - { - } + public ExtractionException(string message, Exception inner) : base(message, inner) { } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/ExtractionMethods.cs b/src/SharpCompress/Common/ExtractionMethods.cs index 51ded979..7a6cb9db 100644 --- a/src/SharpCompress/Common/ExtractionMethods.cs +++ b/src/SharpCompress/Common/ExtractionMethods.cs @@ -8,41 +8,49 @@ namespace SharpCompress.Common /// /// Extract to specific directory, retaining filename /// - public static void WriteEntryToDirectory(IEntry entry, - string destinationDirectory, - ExtractionOptions? options, - Action write) + public static void WriteEntryToDirectory( + IEntry entry, + string destinationDirectory, + ExtractionOptions? options, + Action write + ) { string destinationFileName; string fullDestinationDirectoryPath = Path.GetFullPath(destinationDirectory); //check for trailing slash. - if (fullDestinationDirectoryPath[fullDestinationDirectoryPath.Length - 1] != Path.DirectorySeparatorChar) + if ( + fullDestinationDirectoryPath[fullDestinationDirectoryPath.Length - 1] + != Path.DirectorySeparatorChar + ) { fullDestinationDirectoryPath += Path.DirectorySeparatorChar; } if (!Directory.Exists(fullDestinationDirectoryPath)) { - throw new ExtractionException($"Directory does not exist to extract to: {fullDestinationDirectoryPath}"); + throw new ExtractionException( + $"Directory does not exist to extract to: {fullDestinationDirectoryPath}" + ); } - options ??= new ExtractionOptions() - { - Overwrite = true - }; + options ??= new ExtractionOptions() { Overwrite = true }; string file = Path.GetFileName(entry.Key); if (options.ExtractFullPath) { string folder = Path.GetDirectoryName(entry.Key)!; - string destdir = Path.GetFullPath(Path.Combine(fullDestinationDirectoryPath, folder)); + string destdir = Path.GetFullPath( + Path.Combine(fullDestinationDirectoryPath, folder) + ); if (!Directory.Exists(destdir)) { if (!destdir.StartsWith(fullDestinationDirectoryPath, StringComparison.Ordinal)) { - throw new ExtractionException("Entry is trying to create a directory outside of the destination directory."); + throw new ExtractionException( + "Entry is trying to create a directory outside of the destination directory." + ); } Directory.CreateDirectory(destdir); @@ -52,16 +60,22 @@ namespace SharpCompress.Common else { destinationFileName = Path.Combine(fullDestinationDirectoryPath, file); - } if (!entry.IsDirectory) { destinationFileName = Path.GetFullPath(destinationFileName); - if (!destinationFileName.StartsWith(fullDestinationDirectoryPath, StringComparison.Ordinal)) + if ( + !destinationFileName.StartsWith( + fullDestinationDirectoryPath, + StringComparison.Ordinal + ) + ) { - throw new ExtractionException("Entry is trying to write a file outside of the destination directory."); + throw new ExtractionException( + "Entry is trying to write a file outside of the destination directory." + ); } write(destinationFileName, options); } @@ -71,25 +85,27 @@ namespace SharpCompress.Common } } - public static void WriteEntryToFile(IEntry entry, string destinationFileName, - ExtractionOptions? options, - Action openAndWrite) + public static void WriteEntryToFile( + IEntry entry, + string destinationFileName, + ExtractionOptions? options, + Action openAndWrite + ) { if (entry.LinkTarget != null) { if (options?.WriteSymbolicLink is null) { - throw new ExtractionException("Entry is a symbolic link but ExtractionOptions.WriteSymbolicLink delegate is null"); + throw new ExtractionException( + "Entry is a symbolic link but ExtractionOptions.WriteSymbolicLink delegate is null" + ); } options.WriteSymbolicLink(destinationFileName, entry.LinkTarget); } else { FileMode fm = FileMode.Create; - options ??= new ExtractionOptions() - { - Overwrite = true - }; + options ??= new ExtractionOptions() { Overwrite = true }; if (!options.Overwrite) { @@ -101,4 +117,4 @@ namespace SharpCompress.Common } } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/ExtractionOptions.cs b/src/SharpCompress/Common/ExtractionOptions.cs index 54dbe79f..650708cc 100644 --- a/src/SharpCompress/Common/ExtractionOptions.cs +++ b/src/SharpCompress/Common/ExtractionOptions.cs @@ -31,10 +31,11 @@ namespace SharpCompress.Common /// public delegate void SymbolicLinkWriterDelegate(string sourcePath, string targetPath); - public SymbolicLinkWriterDelegate WriteSymbolicLink = - (sourcePath, targetPath) => - { - Console.WriteLine($"Could not write symlink {sourcePath} -> {targetPath}, for more information please see https://github.com/dotnet/runtime/issues/24271"); - }; + public SymbolicLinkWriterDelegate WriteSymbolicLink = (sourcePath, targetPath) => + { + Console.WriteLine( + $"Could not write symlink {sourcePath} -> {targetPath}, for more information please see https://github.com/dotnet/runtime/issues/24271" + ); + }; } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/FilePartExtractionBeginEventArgs.cs b/src/SharpCompress/Common/FilePartExtractionBeginEventArgs.cs index ee80a4ab..c05ff46e 100644 --- a/src/SharpCompress/Common/FilePartExtractionBeginEventArgs.cs +++ b/src/SharpCompress/Common/FilePartExtractionBeginEventArgs.cs @@ -26,4 +26,4 @@ namespace SharpCompress.Common /// public long CompressedSize { get; } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/FlagUtility.cs b/src/SharpCompress/Common/FlagUtility.cs index 8a3aaee1..67aa1428 100644 --- a/src/SharpCompress/Common/FlagUtility.cs +++ b/src/SharpCompress/Common/FlagUtility.cs @@ -6,35 +6,33 @@ namespace SharpCompress.Common { /// /// Returns true if the flag is set on the specified bit field. - /// Currently only works with 32-bit bitfields. + /// Currently only works with 32-bit bitfields. /// /// Enumeration with Flags attribute /// Flagged variable /// Flag to test /// - public static bool HasFlag(long bitField, T flag) - where T : struct + public static bool HasFlag(long bitField, T flag) where T : struct { return HasFlag(bitField, flag); } /// /// Returns true if the flag is set on the specified bit field. - /// Currently only works with 32-bit bitfields. + /// Currently only works with 32-bit bitfields. /// /// Enumeration with Flags attribute /// Flagged variable /// Flag to test /// - public static bool HasFlag(ulong bitField, T flag) - where T : struct + public static bool HasFlag(ulong bitField, T flag) where T : struct { return HasFlag(bitField, flag); } /// /// Returns true if the flag is set on the specified bit field. - /// Currently only works with 32-bit bitfields. + /// Currently only works with 32-bit bitfields. /// /// Flagged variable /// Flag to test @@ -51,21 +49,20 @@ namespace SharpCompress.Common /// /// Returns true if the flag is set on the specified bit field. - /// Currently only works with 32-bit bitfields. + /// Currently only works with 32-bit bitfields. /// /// Enumeration with Flags attribute /// Flagged variable /// Flag to test /// - public static bool HasFlag(T bitField, T flag) - where T : struct + public static bool HasFlag(T bitField, T flag) where T : struct { return HasFlag(Convert.ToInt64(bitField), Convert.ToInt64(flag)); } /// /// Returns true if the flag is set on the specified bit field. - /// Currently only works with 32-bit bitfields. + /// Currently only works with 32-bit bitfields. /// /// Flagged variable /// Flag to test @@ -99,10 +96,9 @@ namespace SharpCompress.Common /// Flag to change /// bool /// The flagged variable with the flag changed - public static long SetFlag(T bitField, T flag, bool on) - where T : struct + public static long SetFlag(T bitField, T flag, bool on) where T : struct { return SetFlag(Convert.ToInt64(bitField), Convert.ToInt64(flag), on); } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/GZip/GZipEntry.cs b/src/SharpCompress/Common/GZip/GZipEntry.cs index 1204cfd7..9da986ee 100644 --- a/src/SharpCompress/Common/GZip/GZipEntry.cs +++ b/src/SharpCompress/Common/GZip/GZipEntry.cs @@ -46,4 +46,4 @@ namespace SharpCompress.Common.GZip yield return new GZipEntry(new GZipFilePart(stream, options.ArchiveEncoding)); } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/GZip/GZipFilePart.cs b/src/SharpCompress/Common/GZip/GZipFilePart.cs index c6fd9849..a5062267 100644 --- a/src/SharpCompress/Common/GZip/GZipFilePart.cs +++ b/src/SharpCompress/Common/GZip/GZipFilePart.cs @@ -129,8 +129,7 @@ namespace SharpCompress.Common.GZip { list.Add(buf1[0]); } - } - while (!done); + } while (!done); byte[] buffer = list.ToArray(); return ArchiveEncoding.Decode(buffer); } diff --git a/src/SharpCompress/Common/GZip/GZipVolume.cs b/src/SharpCompress/Common/GZip/GZipVolume.cs index 6d77029f..10e0574d 100644 --- a/src/SharpCompress/Common/GZip/GZipVolume.cs +++ b/src/SharpCompress/Common/GZip/GZipVolume.cs @@ -6,9 +6,7 @@ namespace SharpCompress.Common.GZip public class GZipVolume : Volume { public GZipVolume(Stream stream, ReaderOptions options, int index = 0) - : base(stream, options, index) - { - } + : base(stream, options, index) { } public GZipVolume(FileInfo fileInfo, ReaderOptions options) : base(fileInfo.OpenRead(), options) diff --git a/src/SharpCompress/Common/IEntry.Extensions.cs b/src/SharpCompress/Common/IEntry.Extensions.cs index 02acd59a..fdf321bd 100644 --- a/src/SharpCompress/Common/IEntry.Extensions.cs +++ b/src/SharpCompress/Common/IEntry.Extensions.cs @@ -4,8 +4,11 @@ namespace SharpCompress.Common { internal static class EntryExtensions { - internal static void PreserveExtractionOptions(this IEntry entry, string destinationFileName, - ExtractionOptions options) + internal static void PreserveExtractionOptions( + this IEntry entry, + string destinationFileName, + ExtractionOptions options + ) { if (options.PreserveFileTime || options.PreserveAttributes) { @@ -38,7 +41,8 @@ namespace SharpCompress.Common { if (entry.Attrib.HasValue) { - nf.Attributes = (FileAttributes)System.Enum.ToObject(typeof(FileAttributes), entry.Attrib.Value); + nf.Attributes = (FileAttributes) + System.Enum.ToObject(typeof(FileAttributes), entry.Attrib.Value); } } } diff --git a/src/SharpCompress/Common/IncompleteArchiveException.cs b/src/SharpCompress/Common/IncompleteArchiveException.cs index 78d567f4..aca34349 100644 --- a/src/SharpCompress/Common/IncompleteArchiveException.cs +++ b/src/SharpCompress/Common/IncompleteArchiveException.cs @@ -2,9 +2,6 @@ { public class IncompleteArchiveException : ArchiveException { - public IncompleteArchiveException(string message) - : base(message) - { - } + public IncompleteArchiveException(string message) : base(message) { } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/InvalidFormatException.cs b/src/SharpCompress/Common/InvalidFormatException.cs index fa141cb4..ffb16003 100644 --- a/src/SharpCompress/Common/InvalidFormatException.cs +++ b/src/SharpCompress/Common/InvalidFormatException.cs @@ -4,14 +4,8 @@ namespace SharpCompress.Common { public class InvalidFormatException : ExtractionException { - public InvalidFormatException(string message) - : base(message) - { - } + public InvalidFormatException(string message) : base(message) { } - public InvalidFormatException(string message, Exception inner) - : base(message, inner) - { - } + public InvalidFormatException(string message, Exception inner) : base(message, inner) { } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/MultiVolumeExtractionException.cs b/src/SharpCompress/Common/MultiVolumeExtractionException.cs index d9b97fa3..7e6da358 100644 --- a/src/SharpCompress/Common/MultiVolumeExtractionException.cs +++ b/src/SharpCompress/Common/MultiVolumeExtractionException.cs @@ -4,14 +4,9 @@ namespace SharpCompress.Common { public class MultiVolumeExtractionException : ExtractionException { - public MultiVolumeExtractionException(string message) - : base(message) - { - } + public MultiVolumeExtractionException(string message) : base(message) { } public MultiVolumeExtractionException(string message, Exception inner) - : base(message, inner) - { - } + : base(message, inner) { } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/MultipartStreamRequiredException.cs b/src/SharpCompress/Common/MultipartStreamRequiredException.cs index cf030ed6..84b673ef 100644 --- a/src/SharpCompress/Common/MultipartStreamRequiredException.cs +++ b/src/SharpCompress/Common/MultipartStreamRequiredException.cs @@ -2,9 +2,6 @@ { public class MultipartStreamRequiredException : ExtractionException { - public MultipartStreamRequiredException(string message) - : base(message) - { - } + public MultipartStreamRequiredException(string message) : base(message) { } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/OptionsBase.cs b/src/SharpCompress/Common/OptionsBase.cs index b98f0a60..6591f975 100644 --- a/src/SharpCompress/Common/OptionsBase.cs +++ b/src/SharpCompress/Common/OptionsBase.cs @@ -1,5 +1,4 @@ - -namespace SharpCompress.Common +namespace SharpCompress.Common { public class OptionsBase { @@ -10,4 +9,4 @@ namespace SharpCompress.Common public ArchiveEncoding ArchiveEncoding { get; set; } = new ArchiveEncoding(); } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/PasswordProtectedException.cs b/src/SharpCompress/Common/PasswordProtectedException.cs index 58dc7660..ade0a55d 100644 --- a/src/SharpCompress/Common/PasswordProtectedException.cs +++ b/src/SharpCompress/Common/PasswordProtectedException.cs @@ -4,14 +4,9 @@ namespace SharpCompress.Common { public class PasswordProtectedException : ExtractionException { - public PasswordProtectedException(string message) - : base(message) - { - } + public PasswordProtectedException(string message) : base(message) { } - public PasswordProtectedException(string message, Exception inner) - : base(message, inner) - { - } + public PasswordProtectedException(string message, Exception inner) : base(message, inner) + { } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/Rar/Headers/AVHeader.cs b/src/SharpCompress/Common/Rar/Headers/AVHeader.cs index 44d2b15a..b235e5ce 100644 --- a/src/SharpCompress/Common/Rar/Headers/AVHeader.cs +++ b/src/SharpCompress/Common/Rar/Headers/AVHeader.cs @@ -29,4 +29,4 @@ namespace SharpCompress.Common.Rar.Headers internal byte AvVersion { get; private set; } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/Rar/Headers/ArchiveCryptHeader.cs b/src/SharpCompress/Common/Rar/Headers/ArchiveCryptHeader.cs index 51cf05b2..56784c52 100644 --- a/src/SharpCompress/Common/Rar/Headers/ArchiveCryptHeader.cs +++ b/src/SharpCompress/Common/Rar/Headers/ArchiveCryptHeader.cs @@ -6,7 +6,6 @@ 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_SALT30 = 8; @@ -16,7 +15,6 @@ namespace SharpCompress.Common.Rar.Headers private const int CRYPT5_KDF_LG2_COUNT = 15; // LOG2 of PDKDF2 iteration count. 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; @@ -24,9 +22,7 @@ namespace SharpCompress.Common.Rar.Headers private byte[] _pswCheckCsm; public ArchiveCryptHeader(RarHeader header, RarCrcBinaryReader reader) - : base(header, reader, HeaderType.Crypt) - { - } + : base(header, reader, HeaderType.Crypt) { } protected override void ReadFinish(MarkingBinaryReader reader) { @@ -37,10 +33,12 @@ namespace SharpCompress.Common.Rar.Headers return; } var encryptionFlags = reader.ReadRarVIntUInt32(); - _usePswCheck = FlagUtility.HasFlag(encryptionFlags, EncryptionFlagsV5.CHFL_CRYPT_PSWCHECK); + _usePswCheck = FlagUtility.HasFlag( + encryptionFlags, + EncryptionFlagsV5.CHFL_CRYPT_PSWCHECK + ); _lg2Count = reader.ReadRarVIntByte(1); - //UsePswCheck = HasHeaderFlag(EncryptionFlagsV5.CHFL_CRYPT_PSWCHECK); if (_lg2Count > CRYPT5_KDF_LG2_COUNT_MAX) { @@ -56,4 +54,4 @@ namespace SharpCompress.Common.Rar.Headers } } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/Rar/Headers/ArchiveHeader.cs b/src/SharpCompress/Common/Rar/Headers/ArchiveHeader.cs index 39249656..33bc6e9a 100644 --- a/src/SharpCompress/Common/Rar/Headers/ArchiveHeader.cs +++ b/src/SharpCompress/Common/Rar/Headers/ArchiveHeader.cs @@ -5,9 +5,7 @@ namespace SharpCompress.Common.Rar.Headers internal sealed class ArchiveHeader : RarHeader { public ArchiveHeader(RarHeader header, RarCrcBinaryReader reader) - : base(header, reader, HeaderType.Archive) - { - } + : base(header, reader, HeaderType.Archive) { } protected override void ReadFinish(MarkingBinaryReader reader) { @@ -81,8 +79,9 @@ namespace SharpCompress.Common.Rar.Headers public bool IsVolume => HasFlag(IsRar5 ? ArchiveFlagsV5.VOLUME : ArchiveFlagsV4.VOLUME); // RAR5: Volume number field is present. True for all volumes except first. - public bool IsFirstVolume => IsRar5 ? VolumeNumber is null : HasFlag(ArchiveFlagsV4.FIRST_VOLUME); + public bool IsFirstVolume => + IsRar5 ? VolumeNumber is null : HasFlag(ArchiveFlagsV4.FIRST_VOLUME); public bool IsSolid => HasFlag(IsRar5 ? ArchiveFlagsV5.SOLID : ArchiveFlagsV4.SOLID); } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/Rar/Headers/CommentHeader.cs b/src/SharpCompress/Common/Rar/Headers/CommentHeader.cs index 00a9cc25..1742aabe 100644 --- a/src/SharpCompress/Common/Rar/Headers/CommentHeader.cs +++ b/src/SharpCompress/Common/Rar/Headers/CommentHeader.cs @@ -28,4 +28,4 @@ namespace SharpCompress.Common.Rar.Headers internal byte UnpMethod { get; private set; } internal short CommCrc { get; private set; } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/Rar/Headers/EndArchiveHeader.cs b/src/SharpCompress/Common/Rar/Headers/EndArchiveHeader.cs index d993f1d9..bff19b76 100644 --- a/src/SharpCompress/Common/Rar/Headers/EndArchiveHeader.cs +++ b/src/SharpCompress/Common/Rar/Headers/EndArchiveHeader.cs @@ -5,9 +5,7 @@ namespace SharpCompress.Common.Rar.Headers internal class EndArchiveHeader : RarHeader { public EndArchiveHeader(RarHeader header, RarCrcBinaryReader reader) - : base(header, reader, HeaderType.EndArchive) - { - } + : base(header, reader, HeaderType.EndArchive) { } protected override void ReadFinish(MarkingBinaryReader reader) { @@ -40,4 +38,4 @@ namespace SharpCompress.Common.Rar.Headers internal short? VolumeNumber { get; private set; } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/Rar/Headers/FileHeader.cs b/src/SharpCompress/Common/Rar/Headers/FileHeader.cs index 2c361a09..8ef40ec5 100644 --- a/src/SharpCompress/Common/Rar/Headers/FileHeader.cs +++ b/src/SharpCompress/Common/Rar/Headers/FileHeader.cs @@ -22,9 +22,7 @@ namespace SharpCompress.Common.Rar.Headers private uint _fileCrc; public FileHeader(RarHeader header, RarCrcBinaryReader reader, HeaderType headerType) - : base(header, reader, headerType) - { - } + : base(header, reader, headerType) { } protected override void ReadFinish(MarkingBinaryReader reader) { @@ -68,7 +66,7 @@ namespace SharpCompress.Common.Rar.Headers // them. CompressionAlgorithm = (byte)((compressionInfo & 0x3f) + 50); - // 7th bit (0x0040) defines the solid flag. If it is set, RAR continues to use the compression dictionary left after processing preceding files. + // 7th bit (0x0040) defines the solid flag. If it is set, RAR continues to use the compression dictionary left after processing preceding files. // It can be set only for file headers and is never set for service headers. IsSolid = (compressionInfo & 0x40) == 0x40; @@ -89,7 +87,7 @@ namespace SharpCompress.Common.Rar.Headers // TODO: not sure if anything needs to be done to handle the following: // If Unix file name contains any high ASCII characters which cannot be correctly converted to Unicode and UTF-8 // we map such characters to to 0xE080 - 0xE0FF private use Unicode area and insert 0xFFFE Unicode non-character - // to resulting string to indicate that it contains mapped characters, which need to be converted back when extracting. + // to resulting string to indicate that it contains mapped characters, which need to be converted back when extracting. // Concrete position of 0xFFFE is not defined, we need to search the entire string for it. Such mapped names are not // portable and can be correctly unpacked only on the same system where they were created. // @@ -119,6 +117,7 @@ namespace SharpCompress.Common.Rar.Headers { //TODO case 1: // file encryption + { isEncryptedRar5 = true; @@ -132,6 +131,7 @@ namespace SharpCompress.Common.Rar.Headers // } // break; case 3: // file time + { ushort flags = reader.ReadRarVIntUInt16(); var isWindowsTime = (flags & 1) == 0; @@ -190,7 +190,6 @@ namespace SharpCompress.Common.Rar.Headers } } - private static DateTime ReadExtendedTimeV5(MarkingBinaryReader reader, bool isWindowsTime) { if (isWindowsTime) @@ -213,12 +212,13 @@ namespace SharpCompress.Common.Rar.Headers return path; } - private void ReadFromReaderV4(MarkingBinaryReader reader) { Flags = HeaderFlags; IsSolid = HasFlag(FileFlagsV4.SOLID); - WindowSize = IsDirectory ? 0U : ((size_t)0x10000) << ((Flags & FileFlagsV4.WINDOW_MASK) >> 5); + WindowSize = IsDirectory + ? 0U + : ((size_t)0x10000) << ((Flags & FileFlagsV4.WINDOW_MASK) >> 5); uint lowUncompressedSize = reader.ReadUInt32(); @@ -263,12 +263,12 @@ namespace SharpCompress.Common.Rar.Headers switch (HeaderCode) { case HeaderCodeV.RAR4_FILE_HEADER: + { if (HasFlag(FileFlagsV4.UNICODE)) { int length = 0; - while (length < fileNameBytes.Length - && fileNameBytes[length] != 0) + while (length < fileNameBytes.Length && fileNameBytes[length] != 0) { length++; } @@ -290,6 +290,7 @@ namespace SharpCompress.Common.Rar.Headers } break; case HeaderCodeV.RAR4_NEW_SUB_HEADER: + { int datasize = HeaderSize - newLhdSize - nameSize; if (HasFlag(FileFlagsV4.SALT)) @@ -303,8 +304,11 @@ namespace SharpCompress.Common.Rar.Headers if (NewSubHeaderType.SUBHEAD_TYPE_RR.Equals(fileNameBytes)) { - RecoverySectors = SubData[8] + (SubData[9] << 8) - + (SubData[10] << 16) + (SubData[11] << 24); + RecoverySectors = + SubData[8] + + (SubData[9] << 8) + + (SubData[10] << 16) + + (SubData[11] << 24); } } break; @@ -321,7 +325,12 @@ namespace SharpCompress.Common.Rar.Headers if (RemainingHeaderBytes(reader) >= 2) { ushort extendedFlags = reader.ReadUInt16(); - FileLastModifiedTime = ProcessExtendedTimeV4(extendedFlags, FileLastModifiedTime, reader, 0); + FileLastModifiedTime = ProcessExtendedTimeV4( + extendedFlags, + FileLastModifiedTime, + reader, + 0 + ); FileCreatedTime = ProcessExtendedTimeV4(extendedFlags, null, reader, 1); FileLastAccessedTime = ProcessExtendedTimeV4(extendedFlags, null, reader, 2); FileArchivedTime = ProcessExtendedTimeV4(extendedFlags, null, reader, 3); @@ -336,7 +345,12 @@ namespace SharpCompress.Common.Rar.Headers return l + y; } - private static DateTime? ProcessExtendedTimeV4(ushort extendedFlags, DateTime? time, MarkingBinaryReader reader, int i) + private static DateTime? ProcessExtendedTimeV4( + ushort extendedFlags, + DateTime? time, + MarkingBinaryReader reader, + int i + ) { uint rmode = (uint)extendedFlags >> (3 - i) * 4; if ((rmode & 8) == 0) @@ -395,7 +409,7 @@ namespace SharpCompress.Common.Rar.Headers { if (IsRar5 && !HasFlag(FileFlagsV5.HAS_CRC32)) { - //!!! rar5: + //!!! rar5: throw new InvalidOperationException("TODO rar5"); } return _fileCrc; @@ -437,8 +451,10 @@ namespace SharpCompress.Common.Rar.Headers internal long DataStartPosition { get; set; } public Stream PackedStream { get; set; } - public bool IsSplitBefore => IsRar5 ? HasHeaderFlag(HeaderFlagsV5.SPLIT_BEFORE) : HasFlag(FileFlagsV4.SPLIT_BEFORE); - public bool IsSplitAfter => IsRar5 ? HasHeaderFlag(HeaderFlagsV5.SPLIT_AFTER) : HasFlag(FileFlagsV4.SPLIT_AFTER); + public bool IsSplitBefore => + IsRar5 ? HasHeaderFlag(HeaderFlagsV5.SPLIT_BEFORE) : HasFlag(FileFlagsV4.SPLIT_BEFORE); + public bool IsSplitAfter => + IsRar5 ? HasHeaderFlag(HeaderFlagsV5.SPLIT_AFTER) : HasFlag(FileFlagsV4.SPLIT_AFTER); public bool IsDirectory => HasFlag(IsRar5 ? FileFlagsV5.DIRECTORY : FileFlagsV4.DIRECTORY); @@ -453,4 +469,4 @@ namespace SharpCompress.Common.Rar.Headers internal DateTime? FileArchivedTime { get; private set; } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/Rar/Headers/FileNameDecoder.cs b/src/SharpCompress/Common/Rar/Headers/FileNameDecoder.cs index 98da75da..f2afaa39 100644 --- a/src/SharpCompress/Common/Rar/Headers/FileNameDecoder.cs +++ b/src/SharpCompress/Common/Rar/Headers/FileNameDecoder.cs @@ -54,7 +54,11 @@ namespace SharpCompress.Common.Rar.Headers if ((length & 0x80) != 0) { int correction = GetChar(name, encPos++); - for (length = (length & 0x7f) + 2; length > 0 && decPos < name.Length; length--, decPos++) + for ( + length = (length & 0x7f) + 2; + length > 0 && decPos < name.Length; + length--, decPos++ + ) { low = (GetChar(name, decPos) + correction) & 0xff; buf.Append((char)((highByte << 8) + low)); @@ -62,7 +66,11 @@ namespace SharpCompress.Common.Rar.Headers } else { - for (length += 2; length > 0 && decPos < name.Length; length--, decPos++) + for ( + length += 2; + length > 0 && decPos < name.Length; + length--, decPos++ + ) { buf.Append((char)(GetChar(name, decPos))); } @@ -75,4 +83,4 @@ namespace SharpCompress.Common.Rar.Headers return buf.ToString(); } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/Rar/Headers/Flags.cs b/src/SharpCompress/Common/Rar/Headers/Flags.cs index 7925ca5f..7f6ad0aa 100644 --- a/src/SharpCompress/Common/Rar/Headers/Flags.cs +++ b/src/SharpCompress/Common/Rar/Headers/Flags.cs @@ -54,7 +54,7 @@ namespace SharpCompress.Common.Rar.Headers { public const ushort HAS_EXTRA = 0x0001; public const ushort HAS_DATA = 0x0002; - public const ushort KEEP = 0x0004; // block must be kept during an update + public const ushort KEEP = 0x0004; // block must be kept during an update public const ushort SPLIT_BEFORE = 0x0008; public const ushort SPLIT_AFTER = 0x0010; public const ushort CHILD = 0x0020; // ??? Block depends on preceding file block. diff --git a/src/SharpCompress/Common/Rar/Headers/MarkHeader.cs b/src/SharpCompress/Common/Rar/Headers/MarkHeader.cs index 82b40ad8..8416270d 100644 --- a/src/SharpCompress/Common/Rar/Headers/MarkHeader.cs +++ b/src/SharpCompress/Common/Rar/Headers/MarkHeader.cs @@ -34,7 +34,8 @@ namespace SharpCompress.Common.Rar.Headers try { int start = -1; - var b = GetByte(stream); start++; + var b = GetByte(stream); + start++; while (start <= maxScanIndex) { // Rar old signature: 52 45 7E 5E @@ -42,37 +43,44 @@ namespace SharpCompress.Common.Rar.Headers // Rar5 signature: 52 61 72 21 1A 07 01 00 if (b == 0x52) { - b = GetByte(stream); start++; + b = GetByte(stream); + start++; if (b == 0x61) { - b = GetByte(stream); start++; + b = GetByte(stream); + start++; if (b != 0x72) { continue; } - b = GetByte(stream); start++; + b = GetByte(stream); + start++; if (b != 0x21) { continue; } - b = GetByte(stream); start++; + b = GetByte(stream); + start++; if (b != 0x1a) { continue; } - b = GetByte(stream); start++; + b = GetByte(stream); + start++; if (b != 0x07) { continue; } - b = GetByte(stream); start++; + b = GetByte(stream); + start++; if (b == 1) { - b = GetByte(stream); start++; + b = GetByte(stream); + start++; if (b != 0) { continue; @@ -87,24 +95,29 @@ namespace SharpCompress.Common.Rar.Headers } else if (b == 0x45) { - b = GetByte(stream); start++; + b = GetByte(stream); + start++; if (b != 0x7e) { continue; } - b = GetByte(stream); start++; + b = GetByte(stream); + start++; if (b != 0x5e) { continue; } - throw new InvalidFormatException("Rar format version pre-4 is unsupported."); + throw new InvalidFormatException( + "Rar format version pre-4 is unsupported." + ); } } else { - b = GetByte(stream); start++; + b = GetByte(stream); + start++; } } } diff --git a/src/SharpCompress/Common/Rar/Headers/NewSubHeaderType.cs b/src/SharpCompress/Common/Rar/Headers/NewSubHeaderType.cs index 5e07c92e..9814d6bc 100644 --- a/src/SharpCompress/Common/Rar/Headers/NewSubHeaderType.cs +++ b/src/SharpCompress/Common/Rar/Headers/NewSubHeaderType.cs @@ -46,4 +46,4 @@ namespace SharpCompress.Common.Rar.Headers return other is not null && Equals(other._bytes); } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/Rar/Headers/ProtectHeader.cs b/src/SharpCompress/Common/Rar/Headers/ProtectHeader.cs index 27d5297b..9785f369 100644 --- a/src/SharpCompress/Common/Rar/Headers/ProtectHeader.cs +++ b/src/SharpCompress/Common/Rar/Headers/ProtectHeader.cs @@ -28,4 +28,4 @@ namespace SharpCompress.Common.Rar.Headers internal uint TotalBlocks { get; private set; } internal byte[]? Mark { get; private set; } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/Rar/Headers/RarHeader.cs b/src/SharpCompress/Common/Rar/Headers/RarHeader.cs index cb58b51e..732bfab4 100644 --- a/src/SharpCompress/Common/Rar/Headers/RarHeader.cs +++ b/src/SharpCompress/Common/Rar/Headers/RarHeader.cs @@ -11,7 +11,11 @@ namespace SharpCompress.Common.Rar.Headers private readonly HeaderType _headerType; private readonly bool _isRar5; - internal static RarHeader? TryReadBase(RarCrcBinaryReader reader, bool isRar5, ArchiveEncoding archiveEncoding) + internal static RarHeader? TryReadBase( + RarCrcBinaryReader reader, + bool isRar5, + ArchiveEncoding archiveEncoding + ) { try { @@ -131,4 +135,4 @@ namespace SharpCompress.Common.Rar.Headers /// protected long AdditionalDataSize { get; } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/Rar/Headers/RarHeaderFactory.cs b/src/SharpCompress/Common/Rar/Headers/RarHeaderFactory.cs index 4ac686a2..d5641959 100644 --- a/src/SharpCompress/Common/Rar/Headers/RarHeaderFactory.cs +++ b/src/SharpCompress/Common/Rar/Headers/RarHeaderFactory.cs @@ -21,7 +21,11 @@ namespace SharpCompress.Common.Rar.Headers public IEnumerable ReadHeaders(Stream stream) { - var markHeader = MarkHeader.Read(stream, Options.LeaveStreamOpen, Options.LookForHeader); + var markHeader = MarkHeader.Read( + stream, + Options.LeaveStreamOpen, + Options.LookForHeader + ); _isRar5 = markHeader.IsRar5; yield return markHeader; @@ -49,7 +53,9 @@ namespace SharpCompress.Common.Rar.Headers { if (Options.Password is null) { - throw new CryptographicException("Encrypted Rar archive has no password specified."); + throw new CryptographicException( + "Encrypted Rar archive has no password specified." + ); } reader = new RarCryptoBinaryReader(stream, Options.Password); } @@ -63,102 +69,113 @@ namespace SharpCompress.Common.Rar.Headers { case HeaderCodeV.RAR5_ARCHIVE_HEADER: case HeaderCodeV.RAR4_ARCHIVE_HEADER: + { + var ah = new ArchiveHeader(header, reader); + if (ah.IsEncrypted == true) { - var ah = new ArchiveHeader(header, reader); - if (ah.IsEncrypted == true) - { - //!!! rar5 we don't know yet - IsEncrypted = true; - } - return ah; + //!!! rar5 we don't know yet + IsEncrypted = true; } + return ah; + } case HeaderCodeV.RAR4_PROTECT_HEADER: + { + var ph = new ProtectHeader(header, reader); + // skip the recovery record data, we do not use it. + switch (StreamingMode) { - var ph = new ProtectHeader(header, reader); - // skip the recovery record data, we do not use it. - switch (StreamingMode) - { - case StreamingMode.Seekable: - { - reader.BaseStream.Position += ph.DataSize; - } - break; - case StreamingMode.Streaming: - { - reader.BaseStream.Skip(ph.DataSize); - } - break; - default: - { - throw new InvalidFormatException("Invalid StreamingMode"); - } - } + case StreamingMode.Seekable: - return ph; + { + reader.BaseStream.Position += ph.DataSize; + } + break; + case StreamingMode.Streaming: + + { + reader.BaseStream.Skip(ph.DataSize); + } + break; + default: + { + throw new InvalidFormatException("Invalid StreamingMode"); + } } + return ph; + } + case HeaderCodeV.RAR5_SERVICE_HEADER: - { - var fh = new FileHeader(header, reader, HeaderType.Service); - SkipData(fh, reader); - return fh; - } + { + var fh = new FileHeader(header, reader, HeaderType.Service); + SkipData(fh, reader); + return fh; + } case HeaderCodeV.RAR4_NEW_SUB_HEADER: - { - var fh = new FileHeader(header, reader, HeaderType.NewSub); - SkipData(fh, reader); - return fh; - } + { + var fh = new FileHeader(header, reader, HeaderType.NewSub); + SkipData(fh, reader); + return fh; + } case HeaderCodeV.RAR5_FILE_HEADER: case HeaderCodeV.RAR4_FILE_HEADER: + { + var fh = new FileHeader(header, reader, HeaderType.File); + switch (StreamingMode) { - var fh = new FileHeader(header, reader, HeaderType.File); - 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) + { + fh.PackedStream = ms; + } + else + { + fh.PackedStream = new RarCryptoWrapper( + ms, + Options.Password!, + fh.R4Salt + ); + } + } + break; + default: { - 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) - { - fh.PackedStream = ms; - } - else - { - fh.PackedStream = new RarCryptoWrapper(ms, Options.Password!, fh.R4Salt); - } - } - break; - default: - { - throw new InvalidFormatException("Invalid StreamingMode"); - } + throw new InvalidFormatException("Invalid StreamingMode"); } - return fh; } + return fh; + } case HeaderCodeV.RAR5_END_ARCHIVE_HEADER: case HeaderCodeV.RAR4_END_ARCHIVE_HEADER: - { - return new EndArchiveHeader(header, reader); - } + { + return new EndArchiveHeader(header, reader); + } case HeaderCodeV.RAR5_ARCHIVE_ENCRYPTION_HEADER: - { - var ch = new ArchiveCryptHeader(header, reader); - IsEncrypted = true; - return ch; - } + { + var ch = new ArchiveCryptHeader(header, reader); + IsEncrypted = true; + return ch; + } default: - { - throw new InvalidFormatException("Unknown Rar Header: " + header.HeaderCode); - } + { + throw new InvalidFormatException("Unknown Rar Header: " + header.HeaderCode); + } } } @@ -167,21 +184,23 @@ namespace SharpCompress.Common.Rar.Headers 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); } break; default: - { - throw new InvalidFormatException("Invalid StreamingMode"); - } + { + throw new InvalidFormatException("Invalid StreamingMode"); + } } } } diff --git a/src/SharpCompress/Common/Rar/Headers/SignHeader.cs b/src/SharpCompress/Common/Rar/Headers/SignHeader.cs index b45c76b2..c03a60f1 100644 --- a/src/SharpCompress/Common/Rar/Headers/SignHeader.cs +++ b/src/SharpCompress/Common/Rar/Headers/SignHeader.cs @@ -26,4 +26,4 @@ namespace SharpCompress.Common.Rar.Headers internal short UserNameSize { get; private set; } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/Rar/RarCrcBinaryReader.cs b/src/SharpCompress/Common/Rar/RarCrcBinaryReader.cs index ddfd8b98..34a64d16 100644 --- a/src/SharpCompress/Common/Rar/RarCrcBinaryReader.cs +++ b/src/SharpCompress/Common/Rar/RarCrcBinaryReader.cs @@ -8,10 +8,7 @@ namespace SharpCompress.Common.Rar { private uint _currentCrc; - public RarCrcBinaryReader(Stream stream) - : base(stream) - { - } + public RarCrcBinaryReader(Stream stream) : base(stream) { } public uint GetCrc32() { @@ -47,4 +44,4 @@ namespace SharpCompress.Common.Rar return result; } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/Rar/RarCryptoBinaryReader.cs b/src/SharpCompress/Common/Rar/RarCryptoBinaryReader.cs index e5b7cf33..728690e3 100644 --- a/src/SharpCompress/Common/Rar/RarCryptoBinaryReader.cs +++ b/src/SharpCompress/Common/Rar/RarCryptoBinaryReader.cs @@ -11,8 +11,7 @@ namespace SharpCompress.Common.Rar private readonly Queue _data = new Queue(); private long _readCount; - public RarCryptoBinaryReader(Stream stream, string password) - : base(stream) + public RarCryptoBinaryReader(Stream stream, string password) : base(stream) { _password = password; @@ -108,4 +107,4 @@ namespace SharpCompress.Common.Rar ClearQueue(); } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/Rar/RarEntry.cs b/src/SharpCompress/Common/Rar/RarEntry.cs index fc084d5c..05ab67ec 100644 --- a/src/SharpCompress/Common/Rar/RarEntry.cs +++ b/src/SharpCompress/Common/Rar/RarEntry.cs @@ -10,7 +10,11 @@ namespace SharpCompress.Common.Rar /// /// As the V2017 port isn't complete, add this check to use the legacy Rar code. /// - internal bool IsRarV3 => FileHeader.CompressionAlgorithm == 20 || FileHeader.CompressionAlgorithm == 26 || FileHeader.CompressionAlgorithm == 29 || FileHeader.CompressionAlgorithm == 36; //Nanook - Added 20+26 as Test arc from WinRar2.8 (algo 20) was failing with 2017 code + internal bool IsRarV3 => + FileHeader.CompressionAlgorithm == 20 + || FileHeader.CompressionAlgorithm == 26 + || FileHeader.CompressionAlgorithm == 29 + || FileHeader.CompressionAlgorithm == 36; //Nanook - Added 20+26 as Test arc from WinRar2.8 (algo 20) was failing with 2017 code /// /// The File's 32 bit CRC Hash @@ -58,8 +62,13 @@ namespace SharpCompress.Common.Rar public override string ToString() { - return string.Format("Entry Path: {0} Compressed Size: {1} Uncompressed Size: {2} CRC: {3}", - Key, CompressedSize, Size, Crc); + return string.Format( + "Entry Path: {0} Compressed Size: {1} Uncompressed Size: {2} CRC: {3}", + Key, + CompressedSize, + Size, + Crc + ); } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/Rar/RarFilePart.cs b/src/SharpCompress/Common/Rar/RarFilePart.cs index 4075198e..b57ab184 100644 --- a/src/SharpCompress/Common/Rar/RarFilePart.cs +++ b/src/SharpCompress/Common/Rar/RarFilePart.cs @@ -8,8 +8,7 @@ namespace SharpCompress.Common.Rar /// internal abstract class RarFilePart : FilePart { - internal RarFilePart(MarkHeader mh, FileHeader fh, int index) - : base(fh.ArchiveEncoding) + internal RarFilePart(MarkHeader mh, FileHeader fh, int index) : base(fh.ArchiveEncoding) { MarkHeader = mh; FileHeader = fh; diff --git a/src/SharpCompress/Common/Rar/RarRijndael.cs b/src/SharpCompress/Common/Rar/RarRijndael.cs index 44531159..a2a5731f 100644 --- a/src/SharpCompress/Common/Rar/RarRijndael.cs +++ b/src/SharpCompress/Common/Rar/RarRijndael.cs @@ -24,7 +24,6 @@ namespace SharpCompress.Common.Rar private void Initialize() { - _rijndael = new RijndaelEngine(); _aesInitializationVector = new byte[CRYPTO_BLOCK_SIZE]; int rawLength = 2 * _password.Length; @@ -52,11 +51,14 @@ namespace SharpCompress.Common.Rar 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); + 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)); + digest = SHA1.Create() + .ComputeHash(data, 0, (i + 1) * (rawPassword.Length + iblock)); _aesInitializationVector[i / (noOfRounds / CRYPTO_BLOCK_SIZE)] = digest[19]; } } @@ -68,16 +70,18 @@ namespace SharpCompress.Common.Rar { for (int 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)); + 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) @@ -106,8 +110,6 @@ namespace SharpCompress.Common.Rar return decryptedBytes; } - public void Dispose() - { - } + public void Dispose() { } } } diff --git a/src/SharpCompress/Common/Rar/RarVolume.cs b/src/SharpCompress/Common/Rar/RarVolume.cs index 4efbdd92..8e6a8026 100644 --- a/src/SharpCompress/Common/Rar/RarVolume.cs +++ b/src/SharpCompress/Common/Rar/RarVolume.cs @@ -24,6 +24,7 @@ namespace SharpCompress.Common.Rar #nullable disable internal ArchiveHeader ArchiveHeader { get; private set; } + #nullable enable internal StreamingMode Mode => _headerFactory.StreamingMode; @@ -40,16 +41,19 @@ namespace SharpCompress.Common.Rar 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) @@ -58,17 +62,22 @@ namespace SharpCompress.Common.Rar } 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); - } - } - break; + + { + 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 + ); + } + } + break; } } } @@ -79,7 +88,9 @@ namespace SharpCompress.Common.Rar { if (Mode == StreamingMode.Streaming) { - throw new InvalidOperationException("ArchiveHeader should never been null in a streaming read."); + throw new InvalidOperationException( + "ArchiveHeader should never been null in a streaming read." + ); } // we only want to load the archive header to avoid overhead but have to do the nasty thing and reset the stream @@ -157,7 +168,7 @@ namespace SharpCompress.Common.Rar return 1; } } - + public string? Comment { get; internal set; } } } diff --git a/src/SharpCompress/Common/ReaderExtractionEventArgs.cs b/src/SharpCompress/Common/ReaderExtractionEventArgs.cs index 32d5b710..87362b68 100644 --- a/src/SharpCompress/Common/ReaderExtractionEventArgs.cs +++ b/src/SharpCompress/Common/ReaderExtractionEventArgs.cs @@ -15,4 +15,4 @@ namespace SharpCompress.Common public ReaderProgress? ReaderProgress { get; } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/SevenZip/ArchiveDatabase.cs b/src/SharpCompress/Common/SevenZip/ArchiveDatabase.cs index 2722bf55..e16751e6 100644 --- a/src/SharpCompress/Common/SevenZip/ArchiveDatabase.cs +++ b/src/SharpCompress/Common/SevenZip/ArchiveDatabase.cs @@ -48,10 +48,10 @@ namespace SharpCompress.Common.SevenZip internal bool IsEmpty() { return _packSizes.Count == 0 - && _packCrCs.Count == 0 - && _folders.Count == 0 - && _numUnpackStreamsVector.Count == 0 - && _files.Count == 0; + && _packCrCs.Count == 0 + && _folders.Count == 0 + && _numUnpackStreamsVector.Count == 0 + && _files.Count == 0; } private void FillStartPos() @@ -161,7 +161,13 @@ namespace SharpCompress.Common.SevenZip packSizes[j] = _packSizes[packStreamIndex + j]; } - return DecoderStreamHelper.CreateDecoderStream(stream, folderStartPackPos, packSizes, folder, pw); + return DecoderStreamHelper.CreateDecoderStream( + stream, + folderStartPackPos, + packSizes, + folder, + pw + ); } private long GetFolderPackStreamSize(int folderIndex, int streamIndex) diff --git a/src/SharpCompress/Common/SevenZip/ArchiveReader.cs b/src/SharpCompress/Common/SevenZip/ArchiveReader.cs index 6a2b8ea4..babae147 100644 --- a/src/SharpCompress/Common/SevenZip/ArchiveReader.cs +++ b/src/SharpCompress/Common/SevenZip/ArchiveReader.cs @@ -154,7 +154,11 @@ namespace SharpCompress.Common.SevenZip return ReadBitVector(length); } - private void ReadNumberVector(List dataVector, int numFiles, Action action) + private void ReadNumberVector( + List dataVector, + int numFiles, + Action action + ) { var defined = ReadOptionalBitVector(numFiles); @@ -191,12 +195,24 @@ namespace SharpCompress.Common.SevenZip return null; } - private void ReadDateTimeVector(List dataVector, int numFiles, Action action) + private void ReadDateTimeVector( + List dataVector, + int numFiles, + Action action + ) { - ReadNumberVector(dataVector, numFiles, (index, value) => action(index, TranslateTime(value))); + ReadNumberVector( + dataVector, + numFiles, + (index, value) => action(index, TranslateTime(value)) + ); } - private void ReadAttributeVector(List dataVector, int numFiles, Action action) + private void ReadAttributeVector( + List dataVector, + int numFiles, + Action action + ) { BitVector boolVector = ReadOptionalBitVector(numFiles); using (var streamSwitch = new CStreamSwitch()) @@ -251,7 +267,16 @@ namespace SharpCompress.Common.SevenZip byte[] longId = new byte[idSize]; ReadBytes(longId, 0, idSize); #if DEBUG - Log.WriteLine("MethodId: " + String.Join("", Enumerable.Range(0, idSize).Select(x => longId[x].ToString("x2")).ToArray())); + Log.WriteLine( + "MethodId: " + + String.Join( + "", + Enumerable + .Range(0, idSize) + .Select(x => longId[x].ToString("x2")) + .ToArray() + ) + ); #endif if (idSize > 8) { @@ -269,7 +294,13 @@ namespace SharpCompress.Common.SevenZip coder._numInStreams = ReadNum(); coder._numOutStreams = ReadNum(); #if DEBUG - Log.WriteLine("Complex Stream (In: " + coder._numInStreams + " - Out: " + coder._numOutStreams + ")"); + Log.WriteLine( + "Complex Stream (In: " + + coder._numInStreams + + " - Out: " + + coder._numOutStreams + + ")" + ); #endif } else @@ -287,7 +318,13 @@ namespace SharpCompress.Common.SevenZip coder._props = new byte[propsSize]; ReadBytes(coder._props, 0, propsSize); #if DEBUG - Log.WriteLine("Settings: " + String.Join("", coder._props.Select(bt => bt.ToString("x2")).ToArray())); + Log.WriteLine( + "Settings: " + + String.Join( + "", + coder._props.Select(bt => bt.ToString("x2")).ToArray() + ) + ); #endif } @@ -414,7 +451,11 @@ namespace SharpCompress.Common.SevenZip return digests; } - private void ReadPackInfo(out long dataOffset, out List packSizes, out List packCrCs) + private void ReadPackInfo( + out long dataOffset, + out List packSizes, + out List packCrCs + ) { #if DEBUG Log.WriteLine("-- ReadPackInfo --"); @@ -568,8 +609,12 @@ namespace SharpCompress.Common.SevenZip } } - private void ReadSubStreamsInfo(List folders, out List numUnpackStreamsInFolders, - out List unpackSizes, out List digests) + private void ReadSubStreamsInfo( + List folders, + out List numUnpackStreamsInFolders, + out List unpackSizes, + out List digests + ) { #if DEBUG Log.WriteLine("-- ReadSubStreamsInfo --"); @@ -739,7 +784,8 @@ namespace SharpCompress.Common.SevenZip out List folders, out List numUnpackStreamsInFolders, out List unpackSizes, - out List digests) + out List digests + ) { #if DEBUG Log.WriteLine("-- ReadStreamsInfo --"); @@ -768,7 +814,12 @@ namespace SharpCompress.Common.SevenZip ReadUnpackInfo(dataVector, out folders); break; case BlockType.SubStreamsInfo: - ReadSubStreamsInfo(folders, out numUnpackStreamsInFolders, out unpackSizes, out digests); + ReadSubStreamsInfo( + folders, + out numUnpackStreamsInFolders, + out unpackSizes, + out digests + ); break; default: throw new InvalidOperationException(); @@ -791,14 +842,16 @@ namespace SharpCompress.Common.SevenZip #endif try { - ReadStreamsInfo(null, - out long dataStartPos, - out List packSizes, - out List packCrCs, - out List folders, - out List numUnpackStreamsInFolders, - out List unpackSizes, - out List digests); + ReadStreamsInfo( + null, + out long dataStartPos, + out List packSizes, + out List packCrCs, + out List folders, + out List numUnpackStreamsInFolders, + out List unpackSizes, + out List digests + ); dataStartPos += baseOffset; @@ -815,23 +868,35 @@ namespace SharpCompress.Common.SevenZip dataStartPos += packSize; } - var outStream = DecoderStreamHelper.CreateDecoderStream(_stream, oldDataStartPos, myPackSizes, - folder, pass); + var outStream = DecoderStreamHelper.CreateDecoderStream( + _stream, + oldDataStartPos, + myPackSizes, + folder, + pass + ); int unpackSize = checked((int)folder.GetUnpackSize()); byte[] data = new byte[unpackSize]; outStream.ReadExact(data, 0, data.Length); if (outStream.ReadByte() >= 0) { - throw new InvalidOperationException("Decoded stream is longer than expected."); + throw new InvalidOperationException( + "Decoded stream is longer than expected." + ); } dataVector.Add(data); if (folder.UnpackCrcDefined) { - if (Crc.Finish(Crc.Update(Crc.INIT_CRC, data, 0, unpackSize)) != folder._unpackCrc) + if ( + Crc.Finish(Crc.Update(Crc.INIT_CRC, data, 0, unpackSize)) + != folder._unpackCrc + ) { - throw new InvalidOperationException("Decoded stream does not match expected CRC."); + throw new InvalidOperationException( + "Decoded stream does not match expected CRC." + ); } } } @@ -864,7 +929,10 @@ namespace SharpCompress.Common.SevenZip List dataVector = null; if (type == BlockType.AdditionalStreamsInfo) { - dataVector = ReadAndDecodePackedStreams(db._startPositionAfterHeader, getTextPassword); + dataVector = ReadAndDecodePackedStreams( + db._startPositionAfterHeader, + getTextPassword + ); type = ReadId(); } @@ -873,14 +941,16 @@ namespace SharpCompress.Common.SevenZip if (type == BlockType.MainStreamsInfo) { - ReadStreamsInfo(dataVector, - out db._dataStartPosition, - out db._packSizes, - out db._packCrCs, - out db._folders, - out db._numUnpackStreamsVector, - out unpackSizes, - out digests); + ReadStreamsInfo( + dataVector, + out db._dataStartPosition, + out db._packSizes, + out db._packCrCs, + out db._folders, + out db._numUnpackStreamsVector, + out unpackSizes, + out digests + ); db._dataStartPosition += db._startPositionAfterHeader; type = ReadId(); @@ -961,35 +1031,41 @@ namespace SharpCompress.Common.SevenZip #if DEBUG Log.Write("WinAttributes:"); #endif - ReadAttributeVector(dataVector, numFiles, delegate (int i, uint? attr) - { - // Some third party implementations established an unofficial extension - // of the 7z archive format by placing posix file attributes in the high - // bits of the windows file attributes. This makes use of the fact that - // the official implementation does not perform checks on this value. - // - // Newer versions of the official 7z GUI client will try to parse this - // extension, thus acknowledging the unofficial use of these bits. - // - // For us it is safe to just discard the upper bits if they are set and - // keep the windows attributes from the lower bits (which should be set - // properly even if posix file attributes are present, in order to be - // compatible with older 7z archive readers) - // - // Note that the 15th bit is used by some implementations to indicate - // presence of the extension, but not all implementations do that so - // we can't trust that bit and must ignore it. - // - if (attr.HasValue && (attr.Value >> 16) != 0) - { - attr = attr.Value & 0x7FFFu; - } + ReadAttributeVector( + dataVector, + numFiles, + delegate(int i, uint? attr) + { + // Some third party implementations established an unofficial extension + // of the 7z archive format by placing posix file attributes in the high + // bits of the windows file attributes. This makes use of the fact that + // the official implementation does not perform checks on this value. + // + // Newer versions of the official 7z GUI client will try to parse this + // extension, thus acknowledging the unofficial use of these bits. + // + // For us it is safe to just discard the upper bits if they are set and + // keep the windows attributes from the lower bits (which should be set + // properly even if posix file attributes are present, in order to be + // compatible with older 7z archive readers) + // + // Note that the 15th bit is used by some implementations to indicate + // presence of the extension, but not all implementations do that so + // we can't trust that bit and must ignore it. + // + if (attr.HasValue && (attr.Value >> 16) != 0) + { + attr = attr.Value & 0x7FFFu; + } - db._files[i].Attrib = attr; + db._files[i].Attrib = attr; #if DEBUG - Log.Write(" " + (attr.HasValue ? attr.Value.ToString("x8") : "n/a")); + Log.Write( + " " + (attr.HasValue ? attr.Value.ToString("x8") : "n/a") + ); #endif - }); + } + ); #if DEBUG Log.WriteLine(); #endif @@ -1049,13 +1125,24 @@ namespace SharpCompress.Common.SevenZip #if DEBUG Log.Write("StartPos:"); #endif - ReadNumberVector(dataVector, numFiles, delegate (int i, long? startPos) - { - db._files[i].StartPos = startPos; + ReadNumberVector( + dataVector, + numFiles, + delegate(int i, long? startPos) + { + db._files[i].StartPos = startPos; #if DEBUG - Log.Write(" " + (startPos.HasValue ? startPos.Value.ToString() : "n/a")); + Log.Write( + " " + + ( + startPos.HasValue + ? startPos.Value.ToString() + : "n/a" + ) + ); #endif - }); + } + ); #if DEBUG Log.WriteLine(); #endif @@ -1064,13 +1151,19 @@ namespace SharpCompress.Common.SevenZip #if DEBUG Log.Write("CTime:"); #endif - ReadDateTimeVector(dataVector, numFiles, delegate (int i, DateTime? time) - { - db._files[i].CTime = time; + ReadDateTimeVector( + dataVector, + numFiles, + delegate(int i, DateTime? time) + { + db._files[i].CTime = time; #if DEBUG - Log.Write(" " + (time.HasValue ? time.Value.ToString() : "n/a")); + Log.Write( + " " + (time.HasValue ? time.Value.ToString() : "n/a") + ); #endif - }); + } + ); #if DEBUG Log.WriteLine(); #endif @@ -1079,13 +1172,19 @@ namespace SharpCompress.Common.SevenZip #if DEBUG Log.Write("ATime:"); #endif - ReadDateTimeVector(dataVector, numFiles, delegate (int i, DateTime? time) - { - db._files[i].ATime = time; + ReadDateTimeVector( + dataVector, + numFiles, + delegate(int i, DateTime? time) + { + db._files[i].ATime = time; #if DEBUG - Log.Write(" " + (time.HasValue ? time.Value.ToString() : "n/a")); + Log.Write( + " " + (time.HasValue ? time.Value.ToString() : "n/a") + ); #endif - }); + } + ); #if DEBUG Log.WriteLine(); #endif @@ -1094,13 +1193,19 @@ namespace SharpCompress.Common.SevenZip #if DEBUG Log.Write("MTime:"); #endif - ReadDateTimeVector(dataVector, numFiles, delegate (int i, DateTime? time) - { - db._files[i].MTime = time; + ReadDateTimeVector( + dataVector, + numFiles, + delegate(int i, DateTime? time) + { + db._files[i].MTime = time; #if DEBUG - Log.Write(" " + (time.HasValue ? time.Value.ToString() : "n/a")); + Log.Write( + " " + (time.HasValue ? time.Value.ToString() : "n/a") + ); #endif - }); + } + ); #if DEBUG Log.WriteLine(); #endif @@ -1175,7 +1280,7 @@ namespace SharpCompress.Common.SevenZip // TODO: Check Signature! _header = new byte[0x20]; - for (int offset = 0; offset < 0x20;) + for (int offset = 0; offset < 0x20; ) { int delta = stream.Read(_header, offset, 0x20 - offset); if (delta == 0) @@ -1273,7 +1378,10 @@ namespace SharpCompress.Common.SevenZip throw new InvalidOperationException(); } - var dataVector = ReadAndDecodePackedStreams(db._startPositionAfterHeader, db.PasswordProvider); + var dataVector = ReadAndDecodePackedStreams( + db._startPositionAfterHeader, + db.PasswordProvider + ); // compressed header without content is odd but ok if (dataVector.Count == 0) @@ -1346,7 +1454,11 @@ namespace SharpCompress.Common.SevenZip public override long Length => throw new NotSupportedException(); - public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); } + public override long Position + { + get => throw new NotSupportedException(); + set => throw new NotSupportedException(); + } public override int Read(byte[] buffer, int offset, int count) { @@ -1369,7 +1481,10 @@ namespace SharpCompress.Common.SevenZip private void ProcessEmptyFiles() { - while (_currentIndex < _extractStatuses.Count && _db._files[_startIndex + _currentIndex].Size == 0) + while ( + _currentIndex < _extractStatuses.Count + && _db._files[_startIndex + _currentIndex].Size == 0 + ) { OpenFile(); _stream.Dispose(); @@ -1449,8 +1564,13 @@ namespace SharpCompress.Common.SevenZip packSizes[j] = db._packSizes[packStreamIndex + j]; } - s = DecoderStreamHelper.CreateDecoderStream(_stream, folderStartPackPos, packSizes, folderInfo, - db.PasswordProvider); + s = DecoderStreamHelper.CreateDecoderStream( + _stream, + folderStartPackPos, + packSizes, + folderInfo, + db.PasswordProvider + ); _cachedStreams.Add(folderIndex, s); } return s; @@ -1482,9 +1602,7 @@ namespace SharpCompress.Common.SevenZip { bool allFilesMode = (indices is null); - int numItems = allFilesMode - ? db._files.Count - : indices.Length; + int numItems = allFilesMode ? db._files.Count : indices.Length; if (numItems == 0) { @@ -1503,7 +1621,10 @@ namespace SharpCompress.Common.SevenZip continue; } - if (extractFolderInfoVector.Count == 0 || folderIndex != extractFolderInfoVector.Last()._folderIndex) + if ( + extractFolderInfoVector.Count == 0 + || folderIndex != extractFolderInfoVector.Last()._folderIndex + ) { extractFolderInfoVector.Add(new CExtractFolderInfo(-1, folderIndex)); } @@ -1511,7 +1632,11 @@ namespace SharpCompress.Common.SevenZip CExtractFolderInfo efi = extractFolderInfoVector.Last(); int startIndex = db._folderStartFileIndex[folderIndex]; - for (int index = efi._extractStatuses.Count; index <= fileIndex - startIndex; index++) + for ( + int index = efi._extractStatuses.Count; + index <= fileIndex - startIndex; + index++ + ) { efi._extractStatuses.Add(index == fileIndex - startIndex); } @@ -1552,8 +1677,13 @@ namespace SharpCompress.Common.SevenZip // TODO: If the decoding fails the last file may be extracted incompletely. Delete it? - Stream s = DecoderStreamHelper.CreateDecoderStream(_stream, folderStartPackPos, packSizes, - folderInfo, db.PasswordProvider); + Stream s = DecoderStreamHelper.CreateDecoderStream( + _stream, + folderStartPackPos, + packSizes, + folderInfo, + db.PasswordProvider + ); buffer ??= new byte[4 << 10]; for (; ; ) { diff --git a/src/SharpCompress/Common/SevenZip/CBindPair.cs b/src/SharpCompress/Common/SevenZip/CBindPair.cs index ad947967..1d76acf0 100644 --- a/src/SharpCompress/Common/SevenZip/CBindPair.cs +++ b/src/SharpCompress/Common/SevenZip/CBindPair.cs @@ -5,4 +5,4 @@ internal int _inIndex; internal int _outIndex; } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/SevenZip/CCoderInfo.cs b/src/SharpCompress/Common/SevenZip/CCoderInfo.cs index af6345d3..5db367b2 100644 --- a/src/SharpCompress/Common/SevenZip/CCoderInfo.cs +++ b/src/SharpCompress/Common/SevenZip/CCoderInfo.cs @@ -9,4 +9,4 @@ namespace SharpCompress.Common.SevenZip internal int _numInStreams; internal int _numOutStreams; } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/SevenZip/CFileItem.cs b/src/SharpCompress/Common/SevenZip/CFileItem.cs index 7624f8b3..a97d2c9b 100644 --- a/src/SharpCompress/Common/SevenZip/CFileItem.cs +++ b/src/SharpCompress/Common/SevenZip/CFileItem.cs @@ -35,4 +35,4 @@ namespace SharpCompress.Common.SevenZip HasStream = true; } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/SevenZip/CMethodId.cs b/src/SharpCompress/Common/SevenZip/CMethodId.cs index 5069b051..871989e4 100644 --- a/src/SharpCompress/Common/SevenZip/CMethodId.cs +++ b/src/SharpCompress/Common/SevenZip/CMethodId.cs @@ -54,4 +54,4 @@ return bytes; } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/SevenZip/CStreamSwitch.cs b/src/SharpCompress/Common/SevenZip/CStreamSwitch.cs index c1cd51c9..706bfc55 100644 --- a/src/SharpCompress/Common/SevenZip/CStreamSwitch.cs +++ b/src/SharpCompress/Common/SevenZip/CStreamSwitch.cs @@ -66,4 +66,4 @@ namespace SharpCompress.Common.SevenZip } } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/SevenZip/DataReader.cs b/src/SharpCompress/Common/SevenZip/DataReader.cs index 48fcd099..ad20a491 100644 --- a/src/SharpCompress/Common/SevenZip/DataReader.cs +++ b/src/SharpCompress/Common/SevenZip/DataReader.cs @@ -12,21 +12,21 @@ namespace SharpCompress.Common.SevenZip public static uint Get32(byte[] buffer, int offset) { return buffer[offset] - + ((uint)buffer[offset + 1] << 8) - + ((uint)buffer[offset + 2] << 16) - + ((uint)buffer[offset + 3] << 24); + + ((uint)buffer[offset + 1] << 8) + + ((uint)buffer[offset + 2] << 16) + + ((uint)buffer[offset + 3] << 24); } public static ulong Get64(byte[] buffer, int offset) { return buffer[offset] - + ((ulong)buffer[offset + 1] << 8) - + ((ulong)buffer[offset + 2] << 16) - + ((ulong)buffer[offset + 3] << 24) - + ((ulong)buffer[offset + 4] << 32) - + ((ulong)buffer[offset + 5] << 40) - + ((ulong)buffer[offset + 6] << 48) - + ((ulong)buffer[offset + 7] << 56); + + ((ulong)buffer[offset + 1] << 8) + + ((ulong)buffer[offset + 2] << 16) + + ((ulong)buffer[offset + 3] << 24) + + ((ulong)buffer[offset + 4] << 32) + + ((ulong)buffer[offset + 5] << 40) + + ((ulong)buffer[offset + 6] << 48) + + ((ulong)buffer[offset + 7] << 56); } #endregion @@ -183,4 +183,4 @@ namespace SharpCompress.Common.SevenZip #endregion } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/SevenZip/SevenZipEntry.cs b/src/SharpCompress/Common/SevenZip/SevenZipEntry.cs index d2dd2cd1..7be12a96 100644 --- a/src/SharpCompress/Common/SevenZip/SevenZipEntry.cs +++ b/src/SharpCompress/Common/SevenZip/SevenZipEntry.cs @@ -38,8 +38,9 @@ namespace SharpCompress.Common.SevenZip public override bool IsSplitAfter => false; - public override int? Attrib => FilePart.Header.Attrib.HasValue ? (int?)FilePart.Header.Attrib.Value : null; + public override int? Attrib => + FilePart.Header.Attrib.HasValue ? (int?)FilePart.Header.Attrib.Value : null; internal override IEnumerable Parts => FilePart.AsEnumerable(); } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/SevenZip/SevenZipFilePart.cs b/src/SharpCompress/Common/SevenZip/SevenZipFilePart.cs index 4a5a8d43..e6927712 100644 --- a/src/SharpCompress/Common/SevenZip/SevenZipFilePart.cs +++ b/src/SharpCompress/Common/SevenZip/SevenZipFilePart.cs @@ -11,8 +11,13 @@ namespace SharpCompress.Common.SevenZip private readonly Stream _stream; private readonly ArchiveDatabase _database; - internal SevenZipFilePart(Stream stream, ArchiveDatabase database, int index, CFileItem fileEntry, ArchiveEncoding archiveEncoding) - : base(archiveEncoding) + internal SevenZipFilePart( + Stream stream, + ArchiveDatabase database, + int index, + CFileItem fileEntry, + ArchiveEncoding archiveEncoding + ) : base(archiveEncoding) { _stream = stream; _database = database; @@ -40,9 +45,15 @@ namespace SharpCompress.Common.SevenZip { return null!; } - var folderStream = _database.GetFolderStream(_stream, Folder!, _database.PasswordProvider); + var folderStream = _database.GetFolderStream( + _stream, + Folder!, + _database.PasswordProvider + ); - int firstFileIndex = _database._folderStartFileIndex[_database._folders.IndexOf(Folder!)]; + int firstFileIndex = _database._folderStartFileIndex[ + _database._folders.IndexOf(Folder!) + ]; int skipCount = Index - firstFileIndex; long skipSize = 0; for (int i = 0; i < skipCount; i++) @@ -86,22 +97,23 @@ namespace SharpCompress.Common.SevenZip { case K_LZMA: case K_LZMA2: - { - return CompressionType.LZMA; - } + { + return CompressionType.LZMA; + } case K_PPMD: - { - return CompressionType.PPMd; - } + { + return CompressionType.PPMd; + } case K_B_ZIP2: - { - return CompressionType.BZip2; - } + { + return CompressionType.BZip2; + } default: throw new NotImplementedException(); } } - internal bool IsEncrypted => Folder!._coders.FindIndex(c => c._methodId._id == CMethodId.K_AES_ID) != -1; + internal bool IsEncrypted => + Folder!._coders.FindIndex(c => c._methodId._id == CMethodId.K_AES_ID) != -1; } } diff --git a/src/SharpCompress/Common/SevenZip/SevenZipVolume.cs b/src/SharpCompress/Common/SevenZip/SevenZipVolume.cs index 79d6c9d0..19e7b2f0 100644 --- a/src/SharpCompress/Common/SevenZip/SevenZipVolume.cs +++ b/src/SharpCompress/Common/SevenZip/SevenZipVolume.cs @@ -6,8 +6,6 @@ namespace SharpCompress.Common.SevenZip public class SevenZipVolume : Volume { public SevenZipVolume(Stream stream, ReaderOptions readerFactoryOptions, int index = 0) - : base(stream, readerFactoryOptions, index) - { - } + : base(stream, readerFactoryOptions, index) { } } } diff --git a/src/SharpCompress/Common/Tar/Headers/EntryType.cs b/src/SharpCompress/Common/Tar/Headers/EntryType.cs index 06ba1f0d..feeaa6cc 100644 --- a/src/SharpCompress/Common/Tar/Headers/EntryType.cs +++ b/src/SharpCompress/Common/Tar/Headers/EntryType.cs @@ -16,4 +16,4 @@ VolumeHeader = (byte)'V', GlobalExtendedHeader = (byte)'g' } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/Tar/Headers/TarHeader.cs b/src/SharpCompress/Common/Tar/Headers/TarHeader.cs index 6dad0682..e9b38971 100644 --- a/src/SharpCompress/Common/Tar/Headers/TarHeader.cs +++ b/src/SharpCompress/Common/Tar/Headers/TarHeader.cs @@ -9,7 +9,15 @@ 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 DateTime( + 1970, + 1, + 1, + 0, + 0, + 0, + DateTimeKind.Utc + ); public TarHeader(ArchiveEncoding archiveEncoding) { @@ -79,7 +87,11 @@ namespace SharpCompress.Common.Tar.Headers // var truncated = Encoding.UTF8.GetBytes(Encoding.UTF8.GetString(bytes, 0, 100)); // // and then infinite recursion is occured in WriteLongFilenameHeader because truncated.Length is 102. - Name = ArchiveEncoding.Decode(ArchiveEncoding.Encode(Name), 0, 100 - ArchiveEncoding.GetEncoding().GetMaxByteCount(1)); + Name = ArchiveEncoding.Decode( + ArchiveEncoding.Encode(Name), + 0, + 100 - ArchiveEncoding.GetEncoding().GetMaxByteCount(1) + ); Write(output); } } @@ -126,7 +138,7 @@ namespace SharpCompress.Common.Tar.Headers Size = ReadSize(buffer); Mode = ReadAsciiInt64Base8(buffer, 100, 7); - if(EntryType == EntryType.Directory) + if (EntryType == EntryType.Directory) Mode |= 0b1_000_000_000; UserId = ReadAsciiInt64Base8(buffer, 108, 7); @@ -136,8 +148,7 @@ namespace SharpCompress.Common.Tar.Headers Magic = ArchiveEncoding.Decode(buffer, 257, 6).TrimNulls(); - if (!string.IsNullOrEmpty(Magic) - && "ustar".Equals(Magic)) + if (!string.IsNullOrEmpty(Magic) && "ustar".Equals(Magic)) { string namePrefix = ArchiveEncoding.Decode(buffer, 345, 157); namePrefix = namePrefix.TrimNulls(); @@ -146,8 +157,7 @@ namespace SharpCompress.Common.Tar.Headers Name = namePrefix + "/" + Name; } } - if (EntryType != EntryType.LongName - && Name.Length == 0) + if (EntryType != EntryType.LongName && Name.Length == 0) { return false; } @@ -261,10 +271,16 @@ namespace SharpCompress.Common.Tar.Headers return Convert.ToInt64(s); } - - private static readonly byte[] eightSpaces = { - (byte)' ', (byte)' ', (byte)' ', (byte)' ', - (byte)' ', (byte)' ', (byte)' ', (byte)' ' + private static readonly byte[] eightSpaces = + { + (byte)' ', + (byte)' ', + (byte)' ', + (byte)' ', + (byte)' ', + (byte)' ', + (byte)' ', + (byte)' ' }; internal static int RecalculateChecksum(byte[] buf) diff --git a/src/SharpCompress/Common/Tar/TarEntry.cs b/src/SharpCompress/Common/Tar/TarEntry.cs index 7de745c8..59434661 100644 --- a/src/SharpCompress/Common/Tar/TarEntry.cs +++ b/src/SharpCompress/Common/Tar/TarEntry.cs @@ -47,13 +47,17 @@ namespace SharpCompress.Common.Tar public long Mode => _filePart.Header.Mode; public long UserID => _filePart.Header.UserId; - + public long GroupId => _filePart.Header.GroupId; internal override IEnumerable Parts => _filePart.AsEnumerable(); - internal static IEnumerable GetEntries(StreamingMode mode, Stream stream, - CompressionType compressionType, ArchiveEncoding archiveEncoding) + internal static IEnumerable GetEntries( + StreamingMode mode, + Stream stream, + CompressionType compressionType, + ArchiveEncoding archiveEncoding + ) { foreach (TarHeader h in TarHeaderFactory.ReadHeader(mode, stream, archiveEncoding)) { @@ -71,4 +75,4 @@ namespace SharpCompress.Common.Tar } } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/Tar/TarFilePart.cs b/src/SharpCompress/Common/Tar/TarFilePart.cs index 2e11db3d..f71a41a8 100644 --- a/src/SharpCompress/Common/Tar/TarFilePart.cs +++ b/src/SharpCompress/Common/Tar/TarFilePart.cs @@ -8,8 +8,7 @@ namespace SharpCompress.Common.Tar { private readonly Stream _seekableStream; - internal TarFilePart(TarHeader header, Stream seekableStream) - : base(header.ArchiveEncoding) + internal TarFilePart(TarHeader header, Stream seekableStream) : base(header.ArchiveEncoding) { _seekableStream = seekableStream; Header = header; @@ -34,4 +33,4 @@ namespace SharpCompress.Common.Tar return null; } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/Tar/TarHeaderFactory.cs b/src/SharpCompress/Common/Tar/TarHeaderFactory.cs index eb4d7464..6a9e8327 100644 --- a/src/SharpCompress/Common/Tar/TarHeaderFactory.cs +++ b/src/SharpCompress/Common/Tar/TarHeaderFactory.cs @@ -7,7 +7,11 @@ namespace SharpCompress.Common.Tar { internal static class TarHeaderFactory { - internal static IEnumerable ReadHeader(StreamingMode mode, Stream stream, ArchiveEncoding archiveEncoding) + internal static IEnumerable ReadHeader( + StreamingMode mode, + Stream stream, + ArchiveEncoding archiveEncoding + ) { while (true) { @@ -24,6 +28,7 @@ namespace SharpCompress.Common.Tar switch (mode) { case StreamingMode.Seekable: + { header.DataStartPosition = reader.BaseStream.Position; @@ -32,14 +37,15 @@ namespace SharpCompress.Common.Tar } break; case StreamingMode.Streaming: + { header.PackedStream = new TarReadOnlySubStream(stream, header.Size); } break; default: - { - throw new InvalidFormatException("Invalid StreamingMode"); - } + { + throw new InvalidFormatException("Invalid StreamingMode"); + } } } catch @@ -60,4 +66,4 @@ namespace SharpCompress.Common.Tar return 512 - zeros + size; } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/Tar/TarReadOnlySubStream.cs b/src/SharpCompress/Common/Tar/TarReadOnlySubStream.cs index f0782c6e..bea2858f 100644 --- a/src/SharpCompress/Common/Tar/TarReadOnlySubStream.cs +++ b/src/SharpCompress/Common/Tar/TarReadOnlySubStream.cs @@ -9,7 +9,8 @@ namespace SharpCompress.Common.Tar private bool _isDisposed; private long _amountRead; - public TarReadOnlySubStream(Stream stream, long bytesToRead) : base(stream, throwOnDispose: false) + public TarReadOnlySubStream(Stream stream, long bytesToRead) + : base(stream, throwOnDispose: false) { BytesLeftToRead = bytesToRead; } @@ -56,7 +57,11 @@ namespace SharpCompress.Common.Tar public override long Length => throw new NotSupportedException(); - public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); } + public override long Position + { + get => throw new NotSupportedException(); + set => throw new NotSupportedException(); + } public override int Read(byte[] buffer, int offset, int count) { @@ -86,7 +91,6 @@ namespace SharpCompress.Common.Tar ++_amountRead; } return value; - } public override long Seek(long offset, SeekOrigin origin) @@ -104,4 +108,4 @@ namespace SharpCompress.Common.Tar throw new NotSupportedException(); } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/Tar/TarVolume.cs b/src/SharpCompress/Common/Tar/TarVolume.cs index 5b76c56f..4b914920 100644 --- a/src/SharpCompress/Common/Tar/TarVolume.cs +++ b/src/SharpCompress/Common/Tar/TarVolume.cs @@ -6,8 +6,6 @@ namespace SharpCompress.Common.Tar public class TarVolume : Volume { public TarVolume(Stream stream, ReaderOptions readerOptions, int index = 0) - : base(stream, readerOptions, index) - { - } + : base(stream, readerOptions, index) { } } } diff --git a/src/SharpCompress/Common/Volume.cs b/src/SharpCompress/Common/Volume.cs index 8e1446b9..ac716b67 100644 --- a/src/SharpCompress/Common/Volume.cs +++ b/src/SharpCompress/Common/Volume.cs @@ -32,7 +32,10 @@ namespace SharpCompress.Common public virtual int Index { get; internal set; } - public string FileName { get { return (_actualStream as FileStream)?.Name!; } } + public string FileName + { + get { return (_actualStream as FileStream)?.Name!; } + } /// /// RarArchive is part of a multi-part archive. diff --git a/src/SharpCompress/Common/Zip/Headers/DirectoryEndHeader.cs b/src/SharpCompress/Common/Zip/Headers/DirectoryEndHeader.cs index db950602..42c8865c 100644 --- a/src/SharpCompress/Common/Zip/Headers/DirectoryEndHeader.cs +++ b/src/SharpCompress/Common/Zip/Headers/DirectoryEndHeader.cs @@ -4,10 +4,7 @@ namespace SharpCompress.Common.Zip.Headers { internal class DirectoryEndHeader : ZipHeader { - public DirectoryEndHeader() - : base(ZipHeaderType.DirectoryEnd) - { - } + public DirectoryEndHeader() : base(ZipHeaderType.DirectoryEnd) { } internal override void Read(BinaryReader reader) { @@ -37,8 +34,9 @@ namespace SharpCompress.Common.Zip.Headers public ushort TotalNumberOfEntries { get; private set; } - public bool IsZip64 => TotalNumberOfEntriesInDisk == ushort.MaxValue - || DirectorySize == uint.MaxValue - || DirectoryStartOffsetRelativeToDisk == uint.MaxValue; + public bool IsZip64 => + TotalNumberOfEntriesInDisk == ushort.MaxValue + || DirectorySize == uint.MaxValue + || DirectoryStartOffsetRelativeToDisk == uint.MaxValue; } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/Zip/Headers/DirectoryEntryHeader.cs b/src/SharpCompress/Common/Zip/Headers/DirectoryEntryHeader.cs index 8b55dcd6..0a28c602 100644 --- a/src/SharpCompress/Common/Zip/Headers/DirectoryEntryHeader.cs +++ b/src/SharpCompress/Common/Zip/Headers/DirectoryEntryHeader.cs @@ -6,9 +6,7 @@ namespace SharpCompress.Common.Zip.Headers internal class DirectoryEntryHeader : ZipFileEntry { public DirectoryEntryHeader(ArchiveEncoding archiveEncoding) - : base(ZipHeaderType.DirectoryEntry, archiveEncoding) - { - } + : base(ZipHeaderType.DirectoryEntry, archiveEncoding) { } internal override void Read(BinaryReader reader) { @@ -54,16 +52,25 @@ namespace SharpCompress.Common.Zip.Headers 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) { Name = ((ExtraUnicodePathExtraField)unicodePathExtra).UnicodeName; } - var zip64ExtraData = Extra.OfType().FirstOrDefault(); + var zip64ExtraData = Extra + .OfType() + .FirstOrDefault(); if (zip64ExtraData != null) { - zip64ExtraData.Process(UncompressedSize, CompressedSize, RelativeOffsetOfEntryHeader, DiskNumberStart); + zip64ExtraData.Process( + UncompressedSize, + CompressedSize, + RelativeOffsetOfEntryHeader, + DiskNumberStart + ); if (CompressedSize == uint.MaxValue) { @@ -96,4 +103,4 @@ namespace SharpCompress.Common.Zip.Headers public string? Comment { get; private set; } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/Zip/Headers/HeaderFlags.cs b/src/SharpCompress/Common/Zip/Headers/HeaderFlags.cs index 92aaaca7..09cf7f29 100644 --- a/src/SharpCompress/Common/Zip/Headers/HeaderFlags.cs +++ b/src/SharpCompress/Common/Zip/Headers/HeaderFlags.cs @@ -11,7 +11,8 @@ namespace SharpCompress.Common.Zip.Headers Bit2 = 4, UsePostDataDescriptor = 8, EnhancedDeflate = 16, - //Bit 11: Language encoding flag + + //Bit 11: Language encoding flag Efs = 2048 } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/Zip/Headers/IgnoreHeader.cs b/src/SharpCompress/Common/Zip/Headers/IgnoreHeader.cs index 0a086ad7..6957f62f 100644 --- a/src/SharpCompress/Common/Zip/Headers/IgnoreHeader.cs +++ b/src/SharpCompress/Common/Zip/Headers/IgnoreHeader.cs @@ -4,13 +4,8 @@ namespace SharpCompress.Common.Zip.Headers { internal class IgnoreHeader : ZipHeader { - public IgnoreHeader(ZipHeaderType type) - : base(type) - { - } + public IgnoreHeader(ZipHeaderType type) : base(type) { } - internal override void Read(BinaryReader reader) - { - } + internal override void Read(BinaryReader reader) { } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/Zip/Headers/LocalEntryHeader.cs b/src/SharpCompress/Common/Zip/Headers/LocalEntryHeader.cs index 422ca6f4..e3fc8071 100644 --- a/src/SharpCompress/Common/Zip/Headers/LocalEntryHeader.cs +++ b/src/SharpCompress/Common/Zip/Headers/LocalEntryHeader.cs @@ -6,9 +6,7 @@ namespace SharpCompress.Common.Zip.Headers internal class LocalEntryHeader : ZipFileEntry { public LocalEntryHeader(ArchiveEncoding archiveEncoding) - : base(ZipHeaderType.LocalEntry, archiveEncoding) - { - } + : base(ZipHeaderType.LocalEntry, archiveEncoding) { } internal override void Read(BinaryReader reader) { @@ -44,13 +42,17 @@ namespace SharpCompress.Common.Zip.Headers 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) { Name = ((ExtraUnicodePathExtraField)unicodePathExtra).UnicodeName; } - var zip64ExtraData = Extra.OfType().FirstOrDefault(); + var zip64ExtraData = Extra + .OfType() + .FirstOrDefault(); if (zip64ExtraData != null) { zip64ExtraData.Process(UncompressedSize, CompressedSize, 0, 0); @@ -68,4 +70,4 @@ namespace SharpCompress.Common.Zip.Headers internal ushort Version { get; private set; } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/Zip/Headers/LocalEntryHeaderExtraFactory.cs b/src/SharpCompress/Common/Zip/Headers/LocalEntryHeaderExtraFactory.cs index efc7af3a..74d1b224 100644 --- a/src/SharpCompress/Common/Zip/Headers/LocalEntryHeaderExtraFactory.cs +++ b/src/SharpCompress/Common/Zip/Headers/LocalEntryHeaderExtraFactory.cs @@ -33,9 +33,7 @@ namespace SharpCompress.Common.Zip.Headers internal sealed class ExtraUnicodePathExtraField : ExtraData { public ExtraUnicodePathExtraField(ExtraDataType type, ushort length, byte[] dataBytes) - : base(type, length, dataBytes) - { - } + : base(type, length, dataBytes) { } internal byte Version => DataBytes[0]; @@ -63,10 +61,11 @@ namespace SharpCompress.Common.Zip.Headers internal sealed class Zip64ExtendedInformationExtraField : ExtraData { - public Zip64ExtendedInformationExtraField(ExtraDataType type, ushort length, byte[] dataBytes) - : base(type, length, dataBytes) - { - } + public Zip64ExtendedInformationExtraField( + ExtraDataType type, + ushort length, + byte[] dataBytes + ) : base(type, length, dataBytes) { } // From the spec, values are only in the extradata if the standard // value is set to 0xFFFFFFFF (or 0xFFFF for the Disk Start Number). @@ -75,9 +74,15 @@ namespace SharpCompress.Common.Zip.Headers // - Compressed Size // - Relative Header Offset // - Disk Start Number - public void Process(long uncompressedFileSize, long compressedFileSize, long relativeHeaderOffset, ushort diskNumber) + public void Process( + long uncompressedFileSize, + long compressedFileSize, + long relativeHeaderOffset, + ushort diskNumber + ) { - var bytesRequired = ((uncompressedFileSize == uint.MaxValue) ? 8 : 0) + var bytesRequired = + ((uncompressedFileSize == uint.MaxValue) ? 8 : 0) + ((compressedFileSize == uint.MaxValue) ? 8 : 0) + ((relativeHeaderOffset == uint.MaxValue) ? 8 : 0) + ((diskNumber == ushort.MaxValue) ? 4 : 0); @@ -85,30 +90,40 @@ namespace SharpCompress.Common.Zip.Headers if (bytesRequired > DataBytes.Length) { - throw new ArchiveException("Zip64 extended information extra field is not large enough for the required information"); + throw new ArchiveException( + "Zip64 extended information extra field is not large enough for the required information" + ); } if (uncompressedFileSize == uint.MaxValue) { - UncompressedSize = BinaryPrimitives.ReadInt64LittleEndian(DataBytes.AsSpan(currentIndex)); + UncompressedSize = BinaryPrimitives.ReadInt64LittleEndian( + DataBytes.AsSpan(currentIndex) + ); currentIndex += 8; } if (compressedFileSize == uint.MaxValue) { - CompressedSize = BinaryPrimitives.ReadInt64LittleEndian(DataBytes.AsSpan(currentIndex)); + CompressedSize = BinaryPrimitives.ReadInt64LittleEndian( + DataBytes.AsSpan(currentIndex) + ); currentIndex += 8; } if (relativeHeaderOffset == uint.MaxValue) { - RelativeOffsetOfEntryHeader = BinaryPrimitives.ReadInt64LittleEndian(DataBytes.AsSpan(currentIndex)); + RelativeOffsetOfEntryHeader = BinaryPrimitives.ReadInt64LittleEndian( + DataBytes.AsSpan(currentIndex) + ); currentIndex += 8; } if (diskNumber == ushort.MaxValue) { - VolumeNumber = BinaryPrimitives.ReadUInt32LittleEndian(DataBytes.AsSpan(currentIndex)); + VolumeNumber = BinaryPrimitives.ReadUInt32LittleEndian( + DataBytes.AsSpan(currentIndex) + ); } } @@ -143,8 +158,10 @@ namespace SharpCompress.Common.Zip.Headers { return type switch { - ExtraDataType.UnicodePathExtraField => new ExtraUnicodePathExtraField(type, length, extraData), - ExtraDataType.Zip64ExtendedInformationExtraField => new Zip64ExtendedInformationExtraField(type, length, extraData), + ExtraDataType.UnicodePathExtraField + => new ExtraUnicodePathExtraField(type, length, extraData), + ExtraDataType.Zip64ExtendedInformationExtraField + => new Zip64ExtendedInformationExtraField(type, length, extraData), _ => new ExtraData(type, length, extraData) }; } diff --git a/src/SharpCompress/Common/Zip/Headers/SplitHeader.cs b/src/SharpCompress/Common/Zip/Headers/SplitHeader.cs index ee7ca0b8..7a20430c 100644 --- a/src/SharpCompress/Common/Zip/Headers/SplitHeader.cs +++ b/src/SharpCompress/Common/Zip/Headers/SplitHeader.cs @@ -5,14 +5,11 @@ namespace SharpCompress.Common.Zip.Headers { internal class SplitHeader : ZipHeader { - public SplitHeader() - : base(ZipHeaderType.Split) - { - } + public SplitHeader() : base(ZipHeaderType.Split) { } internal override void Read(BinaryReader reader) { throw new NotImplementedException(); } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/Zip/Headers/Zip64DirectoryEndHeader.cs b/src/SharpCompress/Common/Zip/Headers/Zip64DirectoryEndHeader.cs index 0e0b72fb..fffbbabf 100644 --- a/src/SharpCompress/Common/Zip/Headers/Zip64DirectoryEndHeader.cs +++ b/src/SharpCompress/Common/Zip/Headers/Zip64DirectoryEndHeader.cs @@ -4,10 +4,7 @@ namespace SharpCompress.Common.Zip.Headers { internal class Zip64DirectoryEndHeader : ZipHeader { - public Zip64DirectoryEndHeader() - : base(ZipHeaderType.Zip64DirectoryEnd) - { - } + public Zip64DirectoryEndHeader() : base(ZipHeaderType.Zip64DirectoryEnd) { } internal override void Read(BinaryReader reader) { @@ -20,7 +17,12 @@ namespace SharpCompress.Common.Zip.Headers TotalNumberOfEntries = (long)reader.ReadUInt64(); DirectorySize = (long)reader.ReadUInt64(); DirectoryStartOffsetRelativeToDisk = (long)reader.ReadUInt64(); - DataSector = reader.ReadBytes((int)(SizeOfDirectoryEndRecord - SIZE_OF_FIXED_HEADER_DATA_EXCEPT_SIGNATURE_AND_SIZE_FIELDS)); + DataSector = reader.ReadBytes( + (int)( + SizeOfDirectoryEndRecord + - SIZE_OF_FIXED_HEADER_DATA_EXCEPT_SIGNATURE_AND_SIZE_FIELDS + ) + ); } private const int SIZE_OF_FIXED_HEADER_DATA_EXCEPT_SIGNATURE_AND_SIZE_FIELDS = 44; @@ -45,4 +47,4 @@ namespace SharpCompress.Common.Zip.Headers public byte[]? DataSector { get; private set; } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/Zip/Headers/Zip64DirectoryEndLocatorHeader.cs b/src/SharpCompress/Common/Zip/Headers/Zip64DirectoryEndLocatorHeader.cs index 82a6562e..16724668 100644 --- a/src/SharpCompress/Common/Zip/Headers/Zip64DirectoryEndLocatorHeader.cs +++ b/src/SharpCompress/Common/Zip/Headers/Zip64DirectoryEndLocatorHeader.cs @@ -4,10 +4,7 @@ namespace SharpCompress.Common.Zip.Headers { internal class Zip64DirectoryEndLocatorHeader : ZipHeader { - public Zip64DirectoryEndLocatorHeader() - : base(ZipHeaderType.Zip64DirectoryEndLocator) - { - } + public Zip64DirectoryEndLocatorHeader() : base(ZipHeaderType.Zip64DirectoryEndLocator) { } internal override void Read(BinaryReader reader) { @@ -22,4 +19,4 @@ namespace SharpCompress.Common.Zip.Headers public uint TotalNumberOfVolumes { get; private set; } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/Zip/Headers/ZipFileEntry.cs b/src/SharpCompress/Common/Zip/Headers/ZipFileEntry.cs index 5c72d54c..40d5c313 100644 --- a/src/SharpCompress/Common/Zip/Headers/ZipFileEntry.cs +++ b/src/SharpCompress/Common/Zip/Headers/ZipFileEntry.cs @@ -9,8 +9,7 @@ namespace SharpCompress.Common.Zip.Headers { internal abstract class ZipFileEntry : ZipHeader { - protected ZipFileEntry(ZipHeaderType type, ArchiveEncoding archiveEncoding) - : base(type) + protected ZipFileEntry(ZipHeaderType type, ArchiveEncoding archiveEncoding) : base(type) { Extra = new List(); ArchiveEncoding = archiveEncoding; @@ -26,9 +25,7 @@ namespace SharpCompress.Common.Zip.Headers } //.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('\\'); } } @@ -62,7 +59,8 @@ namespace SharpCompress.Common.Zip.Headers var buffer = new byte[12]; archiveStream.ReadFully(buffer); - PkwareTraditionalEncryptionData encryptionData = PkwareTraditionalEncryptionData.ForRead(Password!, this, buffer); + PkwareTraditionalEncryptionData encryptionData = + PkwareTraditionalEncryptionData.ForRead(Password!, this, buffer); return encryptionData; } @@ -77,9 +75,10 @@ namespace SharpCompress.Common.Zip.Headers protected void LoadExtra(byte[] extra) { - for (int i = 0; i < extra.Length - 4;) + for (int i = 0; i < extra.Length - 4; ) { - ExtraDataType type = (ExtraDataType)BinaryPrimitives.ReadUInt16LittleEndian(extra.AsSpan(i)); + ExtraDataType type = (ExtraDataType) + BinaryPrimitives.ReadUInt16LittleEndian(extra.AsSpan(i)); if (!Enum.IsDefined(typeof(ExtraDataType), type)) { type = ExtraDataType.NotImplementedExtraData; diff --git a/src/SharpCompress/Common/Zip/Headers/ZipHeader.cs b/src/SharpCompress/Common/Zip/Headers/ZipHeader.cs index d62513da..43042630 100644 --- a/src/SharpCompress/Common/Zip/Headers/ZipHeader.cs +++ b/src/SharpCompress/Common/Zip/Headers/ZipHeader.cs @@ -16,4 +16,4 @@ namespace SharpCompress.Common.Zip.Headers internal bool HasData { get; set; } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/Zip/Headers/ZipHeaderType.cs b/src/SharpCompress/Common/Zip/Headers/ZipHeaderType.cs index a4286ded..85f6c3b6 100644 --- a/src/SharpCompress/Common/Zip/Headers/ZipHeaderType.cs +++ b/src/SharpCompress/Common/Zip/Headers/ZipHeaderType.cs @@ -10,4 +10,4 @@ Zip64DirectoryEnd, Zip64DirectoryEndLocator } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/Zip/PkwareTraditionalCryptoStream.cs b/src/SharpCompress/Common/Zip/PkwareTraditionalCryptoStream.cs index bad5056d..71556292 100644 --- a/src/SharpCompress/Common/Zip/PkwareTraditionalCryptoStream.cs +++ b/src/SharpCompress/Common/Zip/PkwareTraditionalCryptoStream.cs @@ -16,7 +16,11 @@ namespace SharpCompress.Common.Zip private readonly Stream _stream; private bool _isDisposed; - public PkwareTraditionalCryptoStream(Stream stream, PkwareTraditionalEncryptionData encryptor, CryptoMode mode) + public PkwareTraditionalCryptoStream( + Stream stream, + PkwareTraditionalEncryptionData encryptor, + CryptoMode mode + ) { this._encryptor = encryptor; this._stream = stream; @@ -31,7 +35,11 @@ namespace SharpCompress.Common.Zip public override long Length => throw new NotSupportedException(); - public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); } + public override long Position + { + get => throw new NotSupportedException(); + set => throw new NotSupportedException(); + } public override int Read(byte[] buffer, int offset, int count) { @@ -105,4 +113,4 @@ namespace SharpCompress.Common.Zip _stream.Dispose(); } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/Zip/PkwareTraditionalEncryptionData.cs b/src/SharpCompress/Common/Zip/PkwareTraditionalEncryptionData.cs index 4021f957..96a88e94 100644 --- a/src/SharpCompress/Common/Zip/PkwareTraditionalEncryptionData.cs +++ b/src/SharpCompress/Common/Zip/PkwareTraditionalEncryptionData.cs @@ -25,8 +25,11 @@ namespace SharpCompress.Common.Zip } } - public static PkwareTraditionalEncryptionData ForRead(string password, ZipFileEntry header, - byte[] encryptionHeader) + public static PkwareTraditionalEncryptionData ForRead( + string password, + ZipFileEntry header, + byte[] encryptionHeader + ) { var encryptor = new PkwareTraditionalEncryptionData(password, header.ArchiveEncoding); byte[] plainTextHeader = encryptor.Decrypt(encryptionHeader, encryptionHeader.Length); @@ -48,8 +51,10 @@ namespace SharpCompress.Common.Zip { if (length > cipherText.Length) { - throw new ArgumentOutOfRangeException(nameof(length), - "Bad length during Decryption: the length parameter must be smaller than or equal to the size of the destination array."); + throw new ArgumentOutOfRangeException( + nameof(length), + "Bad length during Decryption: the length parameter must be smaller than or equal to the size of the destination array." + ); } var plainText = new byte[length]; @@ -71,8 +76,10 @@ namespace SharpCompress.Common.Zip if (length > plainText.Length) { - throw new ArgumentOutOfRangeException(nameof(length), - "Bad length during Encryption: The length parameter must be smaller than or equal to the size of the destination array."); + throw new ArgumentOutOfRangeException( + nameof(length), + "Bad length during Encryption: The length parameter must be smaller than or equal to the size of the destination array." + ); } var cipherText = new byte[length]; @@ -108,4 +115,4 @@ namespace SharpCompress.Common.Zip _keys[2] = (UInt32)CRC32.ComputeCrc32((int)_keys[2], (byte)(_keys[1] >> 24)); } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/Zip/SeekableZipFilePart.cs b/src/SharpCompress/Common/Zip/SeekableZipFilePart.cs index a2046190..02a40c38 100644 --- a/src/SharpCompress/Common/Zip/SeekableZipFilePart.cs +++ b/src/SharpCompress/Common/Zip/SeekableZipFilePart.cs @@ -10,8 +10,11 @@ namespace SharpCompress.Common.Zip private readonly SeekableZipHeaderFactory _headerFactory; private readonly DirectoryEntryHeader _directoryEntryHeader; - internal SeekableZipFilePart(SeekableZipHeaderFactory headerFactory, DirectoryEntryHeader header, Stream stream) - : base(header, stream) + internal SeekableZipFilePart( + SeekableZipHeaderFactory headerFactory, + DirectoryEntryHeader header, + Stream stream + ) : base(header, stream) { _headerFactory = headerFactory; _directoryEntryHeader = header; @@ -40,10 +43,12 @@ namespace SharpCompress.Common.Zip { BaseStream.Position = Header.DataStartPosition!.Value; - if ((Header.CompressedSize == 0) + if ( + (Header.CompressedSize == 0) && FlagUtility.HasFlag(Header.Flags, HeaderFlags.UsePostDataDescriptor) && (_directoryEntryHeader?.HasData == true) - && (_directoryEntryHeader?.CompressedSize != 0)) + && (_directoryEntryHeader?.CompressedSize != 0) + ) { return new ReadOnlySubStream(BaseStream, _directoryEntryHeader!.CompressedSize); } @@ -51,4 +56,4 @@ namespace SharpCompress.Common.Zip return BaseStream; } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/Zip/SeekableZipHeaderFactory.cs b/src/SharpCompress/Common/Zip/SeekableZipHeaderFactory.cs index 8f9fd879..ab730bf5 100644 --- a/src/SharpCompress/Common/Zip/SeekableZipHeaderFactory.cs +++ b/src/SharpCompress/Common/Zip/SeekableZipHeaderFactory.cs @@ -10,14 +10,13 @@ namespace SharpCompress.Common.Zip { private const int MINIMUM_EOCD_LENGTH = 22; private const int ZIP64_EOCD_LENGTH = 20; + // Comment may be within 64kb + structure 22 bytes private const int MAX_SEARCH_LENGTH_FOR_EOCD = 65557; private bool _zip64; internal SeekableZipHeaderFactory(string? password, ArchiveEncoding archiveEncoding) - : base(StreamingMode.Seekable, password, archiveEncoding) - { - } + : base(StreamingMode.Seekable, password, archiveEncoding) { } internal IEnumerable ReadSeekableHeader(Stream stream) { @@ -98,15 +97,21 @@ namespace SharpCompress.Common.Zip return true; } + private static void SeekBackToHeader(Stream stream, BinaryReader reader) { // Minimum EOCD length if (stream.Length < MINIMUM_EOCD_LENGTH) { - throw new ArchiveException("Could not find Zip file Directory at the end of the file. File may be corrupted."); + throw new ArchiveException( + "Could not find Zip file Directory at the end of the file. File may be corrupted." + ); } - int len = stream.Length < MAX_SEARCH_LENGTH_FOR_EOCD ? (int)stream.Length : MAX_SEARCH_LENGTH_FOR_EOCD; + int len = + stream.Length < MAX_SEARCH_LENGTH_FOR_EOCD + ? (int)stream.Length + : MAX_SEARCH_LENGTH_FOR_EOCD; // We search for marker in reverse to find the first occurance byte[] needle = { 0x06, 0x05, 0x4b, 0x50 }; @@ -132,7 +137,10 @@ namespace SharpCompress.Common.Zip throw new ArchiveException("Failed to locate the Zip Header"); } - internal LocalEntryHeader GetLocalHeader(Stream stream, DirectoryEntryHeader directoryEntryHeader) + internal LocalEntryHeader GetLocalHeader( + Stream stream, + DirectoryEntryHeader directoryEntryHeader + ) { stream.Seek(directoryEntryHeader.RelativeOffsetOfEntryHeader, SeekOrigin.Begin); BinaryReader reader = new BinaryReader(stream); @@ -145,4 +153,4 @@ namespace SharpCompress.Common.Zip return localEntryHeader; } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/Zip/StreamingZipFilePart.cs b/src/SharpCompress/Common/Zip/StreamingZipFilePart.cs index ee0c6be9..4dabc14d 100644 --- a/src/SharpCompress/Common/Zip/StreamingZipFilePart.cs +++ b/src/SharpCompress/Common/Zip/StreamingZipFilePart.cs @@ -9,10 +9,7 @@ namespace SharpCompress.Common.Zip { private Stream? _decompressionStream; - internal StreamingZipFilePart(ZipFileEntry header, Stream stream) - : base(header, stream) - { - } + internal StreamingZipFilePart(ZipFileEntry header, Stream stream) : base(header, stream) { } protected override Stream CreateBaseStream() { @@ -25,7 +22,10 @@ namespace SharpCompress.Common.Zip { return Stream.Null; } - _decompressionStream = CreateDecompressionStream(GetCryptoStream(CreateBaseStream()), Header.CompressionMethod); + _decompressionStream = CreateDecompressionStream( + GetCryptoStream(CreateBaseStream()), + Header.CompressionMethod + ); if (LeaveStreamOpen) { return NonDisposingStream.Create(_decompressionStream); @@ -43,7 +43,7 @@ namespace SharpCompress.Common.Zip { _decompressionStream ??= GetCompressedStream(); - if( Header.CompressionMethod != ZipCompressionMethod.None ) + if (Header.CompressionMethod != ZipCompressionMethod.None) { _decompressionStream.Skip(); @@ -60,7 +60,7 @@ namespace SharpCompress.Common.Zip // We would need to search for the magic word rewindableStream.Position -= 4; var pos = rewindableStream.Position; - while( Utility.Find(rewindableStream, new byte[] { 0x50,0x4b,0x07,0x08 } ) ) + while (Utility.Find(rewindableStream, new byte[] { 0x50, 0x4b, 0x07, 0x08 })) { // We should probably check CRC32 for positive matching as well var size = rewindableStream.Position - pos; @@ -73,7 +73,7 @@ namespace SharpCompress.Common.Zip long test_64bit = (long)uncompressed_size << 32 | (long)compressed_size; - if( test_64bit == size && test_64bit == uncompressed_64bit ) + if (test_64bit == size && test_64bit == uncompressed_64bit) { Header.CompressedSize = test_64bit; Header.UncompressedSize = uncompressed_64bit; @@ -81,7 +81,7 @@ namespace SharpCompress.Common.Zip break; } - if (compressed_size == size && compressed_size == uncompressed_size ) + if (compressed_size == size && compressed_size == uncompressed_size) { Header.CompressedSize = compressed_size; Header.UncompressedSize = uncompressed_size; diff --git a/src/SharpCompress/Common/Zip/StreamingZipHeaderFactory.cs b/src/SharpCompress/Common/Zip/StreamingZipHeaderFactory.cs index 836fb039..620e3885 100644 --- a/src/SharpCompress/Common/Zip/StreamingZipHeaderFactory.cs +++ b/src/SharpCompress/Common/Zip/StreamingZipHeaderFactory.cs @@ -8,9 +8,7 @@ namespace SharpCompress.Common.Zip internal class StreamingZipHeaderFactory : ZipHeaderFactory { internal StreamingZipHeaderFactory(string? password, ArchiveEncoding archiveEncoding) - : base(StreamingMode.Streaming, password, archiveEncoding) - { - } + : base(StreamingMode.Streaming, password, archiveEncoding) { } internal IEnumerable ReadStreamHeader(Stream stream) { @@ -29,10 +27,19 @@ namespace SharpCompress.Common.Zip ZipHeader? header; BinaryReader reader = new BinaryReader(rewindableStream); uint headerBytes = 0; - if (_lastEntryHeader != null && - (FlagUtility.HasFlag(_lastEntryHeader.Flags, HeaderFlags.UsePostDataDescriptor) || _lastEntryHeader.IsZip64)) + if ( + _lastEntryHeader != null + && ( + FlagUtility.HasFlag( + _lastEntryHeader.Flags, + HeaderFlags.UsePostDataDescriptor + ) || _lastEntryHeader.IsZip64 + ) + ) { - reader = ((StreamingZipFilePart)_lastEntryHeader.Part).FixStreamedFileLocation(ref rewindableStream); + reader = ((StreamingZipFilePart)_lastEntryHeader.Part).FixStreamedFileLocation( + ref rewindableStream + ); long? pos = rewindableStream.CanSeek ? (long?)rewindableStream.Position : null; uint crc = reader.ReadUInt32(); if (crc == POST_DATA_DESCRIPTOR) @@ -50,9 +57,10 @@ namespace SharpCompress.Common.Zip bool test_header = !(headerBytes == 0x04034b50 || headerBytes == 0x02014b50); long test_64bit = (long)uncompressed_size << 32 | (long)compressed_size; - if ( test_64bit == _lastEntryHeader.CompressedSize && test_header ) + if (test_64bit == _lastEntryHeader.CompressedSize && test_header) { - _lastEntryHeader.UncompressedSize = (long)reader.ReadUInt32() << 32 | (long)headerBytes; + _lastEntryHeader.UncompressedSize = + (long)reader.ReadUInt32() << 32 | (long)headerBytes; headerBytes = reader.ReadUInt32(); } else diff --git a/src/SharpCompress/Common/Zip/WinzipAesCryptoStream.cs b/src/SharpCompress/Common/Zip/WinzipAesCryptoStream.cs index ea8aea3f..00345a47 100644 --- a/src/SharpCompress/Common/Zip/WinzipAesCryptoStream.cs +++ b/src/SharpCompress/Common/Zip/WinzipAesCryptoStream.cs @@ -18,7 +18,11 @@ namespace SharpCompress.Common.Zip private long _totalBytesLeftToRead; private bool _isDisposed; - internal WinzipAesCryptoStream(Stream stream, WinzipAesEncryptionData winzipAesEncryptionData, long length) + internal WinzipAesCryptoStream( + Stream stream, + WinzipAesEncryptionData winzipAesEncryptionData, + long length + ) { this._stream = stream; _totalBytesLeftToRead = length; @@ -113,9 +117,8 @@ namespace SharpCompress.Common.Zip } int bytesRemaining = last - offset; - int bytesToRead = (bytesRemaining > BLOCK_SIZE_IN_BYTES) - ? BLOCK_SIZE_IN_BYTES - : bytesRemaining; + int bytesToRead = + (bytesRemaining > BLOCK_SIZE_IN_BYTES) ? BLOCK_SIZE_IN_BYTES : bytesRemaining; // update the counter BinaryPrimitives.WriteInt32LittleEndian(_counter, _nonce++); @@ -123,25 +126,24 @@ namespace SharpCompress.Common.Zip // Determine if this is the final block if ((bytesToRead == bytesRemaining) && (_totalBytesLeftToRead == 0)) { - _counterOut = _transform.TransformFinalBlock(_counter, - 0, - BLOCK_SIZE_IN_BYTES); + _counterOut = _transform.TransformFinalBlock(_counter, 0, BLOCK_SIZE_IN_BYTES); _isFinalBlock = true; } else { - _transform.TransformBlock(_counter, - 0, // offset - BLOCK_SIZE_IN_BYTES, - _counterOut, - 0); // offset + _transform.TransformBlock( + _counter, + 0, // offset + BLOCK_SIZE_IN_BYTES, + _counterOut, + 0 + ); // offset } XorInPlace(buffer, offset, bytesToRead); return bytesToRead; } - private void XorInPlace(byte[] buffer, int offset, int count) { for (int i = 0; i < count; i++) @@ -162,7 +164,6 @@ namespace SharpCompress.Common.Zip } } - public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); diff --git a/src/SharpCompress/Common/Zip/WinzipAesEncryptionData.cs b/src/SharpCompress/Common/Zip/WinzipAesEncryptionData.cs index 81c78503..cd5314c4 100644 --- a/src/SharpCompress/Common/Zip/WinzipAesEncryptionData.cs +++ b/src/SharpCompress/Common/Zip/WinzipAesEncryptionData.cs @@ -17,8 +17,12 @@ namespace SharpCompress.Common.Zip private byte[] _generatedVerifyValue; - internal WinzipAesEncryptionData(WinzipAesKeySize keySize, byte[] salt, byte[] passwordVerifyValue, - string password) + internal WinzipAesEncryptionData( + WinzipAesKeySize keySize, + byte[] salt, + byte[] passwordVerifyValue, + string password + ) { this._keySize = keySize; this._salt = salt; @@ -33,10 +37,7 @@ namespace SharpCompress.Common.Zip private int KeySizeInBytes { - get - { - return KeyLengthInBytes(_keySize); - } + get { return KeyLengthInBytes(_keySize); } } internal static int KeyLengthInBytes(WinzipAesKeySize keySize) @@ -52,11 +53,16 @@ namespace SharpCompress.Common.Zip private void Initialize() { - #if NET7_0 - var rfc2898 = new Rfc2898DeriveBytes(_password, _salt, RFC2898_ITERATIONS, HashAlgorithmName.SHA1); - #else +#if NET7_0 + var rfc2898 = new Rfc2898DeriveBytes( + _password, + _salt, + RFC2898_ITERATIONS, + HashAlgorithmName.SHA1 + ); +#else var rfc2898 = new Rfc2898DeriveBytes(_password, _salt, RFC2898_ITERATIONS); - #endif +#endif KeyBytes = rfc2898.GetBytes(KeySizeInBytes); // 16 or 24 or 32 ??? IvBytes = rfc2898.GetBytes(KeySizeInBytes); diff --git a/src/SharpCompress/Common/Zip/WinzipAesKeySize.cs b/src/SharpCompress/Common/Zip/WinzipAesKeySize.cs index 4a39f46d..07602338 100644 --- a/src/SharpCompress/Common/Zip/WinzipAesKeySize.cs +++ b/src/SharpCompress/Common/Zip/WinzipAesKeySize.cs @@ -6,4 +6,4 @@ KeySize192 = 2, KeySize256 = 3 } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/Zip/ZipCompressionMethod.cs b/src/SharpCompress/Common/Zip/ZipCompressionMethod.cs index bf7df040..87135269 100644 --- a/src/SharpCompress/Common/Zip/ZipCompressionMethod.cs +++ b/src/SharpCompress/Common/Zip/ZipCompressionMethod.cs @@ -10,4 +10,4 @@ PPMd = 98, WinzipAes = 0x63 //http://www.winzip.com/aes_info.htm } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/Zip/ZipEntry.cs b/src/SharpCompress/Common/Zip/ZipEntry.cs index d82335b5..f77f397d 100644 --- a/src/SharpCompress/Common/Zip/ZipEntry.cs +++ b/src/SharpCompress/Common/Zip/ZipEntry.cs @@ -15,8 +15,10 @@ namespace SharpCompress.Common.Zip if (filePart != null) { this._filePart = filePart; - LastModifiedTime = Utility.DosDateToDateTime(filePart.Header.LastModifiedDate, - filePart.Header.LastModifiedTime); + LastModifiedTime = Utility.DosDateToDateTime( + filePart.Header.LastModifiedDate, + filePart.Header.LastModifiedTime + ); } } @@ -27,33 +29,33 @@ namespace SharpCompress.Common.Zip switch (_filePart.Header.CompressionMethod) { case ZipCompressionMethod.BZip2: - { - return CompressionType.BZip2; - } + { + return CompressionType.BZip2; + } case ZipCompressionMethod.Deflate: - { - return CompressionType.Deflate; - } + { + return CompressionType.Deflate; + } case ZipCompressionMethod.Deflate64: - { - return CompressionType.Deflate64; - } + { + return CompressionType.Deflate64; + } case ZipCompressionMethod.LZMA: - { - return CompressionType.LZMA; - } + { + return CompressionType.LZMA; + } case ZipCompressionMethod.PPMd: - { - return CompressionType.PPMd; - } + { + return CompressionType.PPMd; + } case ZipCompressionMethod.None: - { - return CompressionType.None; - } + { + return CompressionType.None; + } default: - { - return CompressionType.Unknown; - } + { + return CompressionType.Unknown; + } } } } @@ -76,7 +78,8 @@ namespace SharpCompress.Common.Zip public override DateTime? ArchivedTime => null; - public override bool IsEncrypted => FlagUtility.HasFlag(_filePart.Header.Flags, HeaderFlags.Encrypted); + public override bool IsEncrypted => + FlagUtility.HasFlag(_filePart.Header.Flags, HeaderFlags.Encrypted); public override bool IsDirectory => _filePart.Header.IsDirectory; @@ -84,4 +87,4 @@ namespace SharpCompress.Common.Zip internal override IEnumerable Parts => _filePart.AsEnumerable(); } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/Zip/ZipFilePart.cs b/src/SharpCompress/Common/Zip/ZipFilePart.cs index 5fd6c4ac..c87ac3f1 100644 --- a/src/SharpCompress/Common/Zip/ZipFilePart.cs +++ b/src/SharpCompress/Common/Zip/ZipFilePart.cs @@ -15,8 +15,7 @@ namespace SharpCompress.Common.Zip { internal abstract class ZipFilePart : FilePart { - internal ZipFilePart(ZipFileEntry header, Stream stream) - : base(header.ArchiveEncoding) + internal ZipFilePart(ZipFileEntry header, Stream stream) : base(header.ArchiveEncoding) { Header = header; header.Part = this; @@ -34,7 +33,10 @@ namespace SharpCompress.Common.Zip { return Stream.Null; } - Stream decompressionStream = CreateDecompressionStream(GetCryptoStream(CreateBaseStream()), Header.CompressionMethod); + Stream decompressionStream = CreateDecompressionStream( + GetCryptoStream(CreateBaseStream()), + Header.CompressionMethod + ); if (LeaveStreamOpen) { return NonDisposingStream.Create(decompressionStream); @@ -53,79 +55,99 @@ namespace SharpCompress.Common.Zip protected abstract Stream CreateBaseStream(); - protected bool LeaveStreamOpen => FlagUtility.HasFlag(Header.Flags, HeaderFlags.UsePostDataDescriptor) || Header.IsZip64; + protected bool LeaveStreamOpen => + FlagUtility.HasFlag(Header.Flags, HeaderFlags.UsePostDataDescriptor) || Header.IsZip64; protected Stream CreateDecompressionStream(Stream stream, ZipCompressionMethod method) { switch (method) { case ZipCompressionMethod.None: - { - return stream; - } + { + return stream; + } case ZipCompressionMethod.Deflate: - { - return new DeflateStream(stream, CompressionMode.Decompress); - } + { + return new DeflateStream(stream, CompressionMode.Decompress); + } case ZipCompressionMethod.Deflate64: - { - return new Deflate64Stream(stream, CompressionMode.Decompress); - } + { + return new Deflate64Stream(stream, CompressionMode.Decompress); + } case ZipCompressionMethod.BZip2: - { - return new BZip2Stream(stream, CompressionMode.Decompress, false); - } + { + return new BZip2Stream(stream, CompressionMode.Decompress, false); + } case ZipCompressionMethod.LZMA: + { + if (FlagUtility.HasFlag(Header.Flags, HeaderFlags.Encrypted)) { - if (FlagUtility.HasFlag(Header.Flags, HeaderFlags.Encrypted)) - { - throw new NotSupportedException("LZMA with pkware encryption."); - } - var reader = new BinaryReader(stream); - reader.ReadUInt16(); //LZMA version - var props = new byte[reader.ReadUInt16()]; - reader.Read(props, 0, props.Length); - return new LzmaStream(props, stream, - Header.CompressedSize > 0 ? Header.CompressedSize - 4 - props.Length : -1, - FlagUtility.HasFlag(Header.Flags, HeaderFlags.Bit1) - ? -1 - : (long)Header.UncompressedSize); + throw new NotSupportedException("LZMA with pkware encryption."); } + var reader = new BinaryReader(stream); + reader.ReadUInt16(); //LZMA version + var props = new byte[reader.ReadUInt16()]; + reader.Read(props, 0, props.Length); + return new LzmaStream( + props, + stream, + Header.CompressedSize > 0 ? Header.CompressedSize - 4 - props.Length : -1, + FlagUtility.HasFlag(Header.Flags, HeaderFlags.Bit1) + ? -1 + : (long)Header.UncompressedSize + ); + } case ZipCompressionMethod.PPMd: - { - Span props = stackalloc byte[2]; - stream.ReadFully(props); - return new PpmdStream(new PpmdProperties(props), stream, false); - } + { + Span props = stackalloc byte[2]; + stream.ReadFully(props); + return new PpmdStream(new PpmdProperties(props), stream, false); + } case ZipCompressionMethod.WinzipAes: + { + ExtraData? data = Header.Extra.SingleOrDefault( + x => x.Type == ExtraDataType.WinZipAes + ); + if (data is null) { - ExtraData? data = Header.Extra.SingleOrDefault(x => x.Type == ExtraDataType.WinZipAes); - if (data is null) - { - throw new InvalidFormatException("No Winzip AES extra data found."); - } - if (data.Length != 7) - { - throw new InvalidFormatException("Winzip data length is not 7."); - } - ushort compressedMethod = BinaryPrimitives.ReadUInt16LittleEndian(data.DataBytes); - - if (compressedMethod != 0x01 && compressedMethod != 0x02) - { - throw new InvalidFormatException("Unexpected vendor version number for WinZip AES metadata"); - } - - ushort vendorId = BinaryPrimitives.ReadUInt16LittleEndian(data.DataBytes.AsSpan(2)); - if (vendorId != 0x4541) - { - throw new InvalidFormatException("Unexpected vendor ID for WinZip AES metadata"); - } - return CreateDecompressionStream(stream, (ZipCompressionMethod)BinaryPrimitives.ReadUInt16LittleEndian(data.DataBytes.AsSpan(5))); + throw new InvalidFormatException("No Winzip AES extra data found."); } + if (data.Length != 7) + { + throw new InvalidFormatException("Winzip data length is not 7."); + } + ushort compressedMethod = BinaryPrimitives.ReadUInt16LittleEndian( + data.DataBytes + ); + + if (compressedMethod != 0x01 && compressedMethod != 0x02) + { + throw new InvalidFormatException( + "Unexpected vendor version number for WinZip AES metadata" + ); + } + + ushort vendorId = BinaryPrimitives.ReadUInt16LittleEndian( + data.DataBytes.AsSpan(2) + ); + if (vendorId != 0x4541) + { + throw new InvalidFormatException( + "Unexpected vendor ID for WinZip AES metadata" + ); + } + return CreateDecompressionStream( + stream, + (ZipCompressionMethod) + BinaryPrimitives.ReadUInt16LittleEndian(data.DataBytes.AsSpan(5)) + ); + } default: - { - throw new NotSupportedException("CompressionMethod: " + Header.CompressionMethod); - } + { + throw new NotSupportedException( + "CompressionMethod: " + Header.CompressionMethod + ); + } } } @@ -138,9 +160,12 @@ namespace SharpCompress.Common.Zip throw new NotSupportedException("Cannot encrypt file with unknown size at start."); } - if ((Header.CompressedSize == 0 - && FlagUtility.HasFlag(Header.Flags, HeaderFlags.UsePostDataDescriptor)) - || Header.IsZip64) + if ( + ( + Header.CompressedSize == 0 + && FlagUtility.HasFlag(Header.Flags, HeaderFlags.UsePostDataDescriptor) + ) || Header.IsZip64 + ) { plainStream = NonDisposingStream.Create(plainStream); //make sure AES doesn't close } @@ -159,24 +184,31 @@ namespace SharpCompress.Common.Zip case ZipCompressionMethod.BZip2: case ZipCompressionMethod.LZMA: case ZipCompressionMethod.PPMd: - { - return new PkwareTraditionalCryptoStream(plainStream, Header.ComposeEncryptionData(plainStream), CryptoMode.Decrypt); - } + { + return new PkwareTraditionalCryptoStream( + plainStream, + Header.ComposeEncryptionData(plainStream), + CryptoMode.Decrypt + ); + } case ZipCompressionMethod.WinzipAes: + { + if (Header.WinzipAesEncryptionData != null) { - if (Header.WinzipAesEncryptionData != null) - { - return new WinzipAesCryptoStream(plainStream, Header.WinzipAesEncryptionData, Header.CompressedSize - 10); - } - return plainStream; + return new WinzipAesCryptoStream( + plainStream, + Header.WinzipAesEncryptionData, + Header.CompressedSize - 10 + ); } + return plainStream; + } default: - { - throw new InvalidOperationException("Header.CompressionMethod is invalid"); - } - + { + throw new InvalidOperationException("Header.CompressionMethod is invalid"); + } } } return plainStream; diff --git a/src/SharpCompress/Common/Zip/ZipHeaderFactory.cs b/src/SharpCompress/Common/Zip/ZipHeaderFactory.cs index fac558d2..bc490c7e 100644 --- a/src/SharpCompress/Common/Zip/ZipHeaderFactory.cs +++ b/src/SharpCompress/Common/Zip/ZipHeaderFactory.cs @@ -23,7 +23,11 @@ namespace SharpCompress.Common.Zip private readonly StreamingMode _mode; private readonly ArchiveEncoding _archiveEncoding; - protected ZipHeaderFactory(StreamingMode mode, string? password, ArchiveEncoding archiveEncoding) + protected ZipHeaderFactory( + StreamingMode mode, + string? password, + ArchiveEncoding archiveEncoding + ) { this._mode = mode; this._password = password; @@ -35,58 +39,67 @@ namespace SharpCompress.Common.Zip switch (headerBytes) { case ENTRY_HEADER_BYTES: - { - var entryHeader = new LocalEntryHeader(_archiveEncoding); - entryHeader.Read(reader); - LoadHeader(entryHeader, reader.BaseStream); + { + var entryHeader = new LocalEntryHeader(_archiveEncoding); + entryHeader.Read(reader); + LoadHeader(entryHeader, reader.BaseStream); - _lastEntryHeader = entryHeader; - return entryHeader; - } + _lastEntryHeader = entryHeader; + return entryHeader; + } case DIRECTORY_START_HEADER_BYTES: - { - var entry = new DirectoryEntryHeader(_archiveEncoding); - entry.Read(reader); - return entry; - } + { + var entry = new DirectoryEntryHeader(_archiveEncoding); + entry.Read(reader); + return entry; + } case POST_DATA_DESCRIPTOR: + { + if ( + FlagUtility.HasFlag( + _lastEntryHeader!.Flags, + HeaderFlags.UsePostDataDescriptor + ) + ) { - if (FlagUtility.HasFlag(_lastEntryHeader!.Flags, HeaderFlags.UsePostDataDescriptor)) - { - _lastEntryHeader.Crc = reader.ReadUInt32(); - _lastEntryHeader.CompressedSize = zip64 ? (long)reader.ReadUInt64() : reader.ReadUInt32(); - _lastEntryHeader.UncompressedSize = zip64 ? (long)reader.ReadUInt64() : reader.ReadUInt32(); - } - else - { - reader.ReadBytes(zip64 ? 20 : 12); - } - return null; + _lastEntryHeader.Crc = reader.ReadUInt32(); + _lastEntryHeader.CompressedSize = zip64 + ? (long)reader.ReadUInt64() + : reader.ReadUInt32(); + _lastEntryHeader.UncompressedSize = zip64 + ? (long)reader.ReadUInt64() + : reader.ReadUInt32(); } + else + { + reader.ReadBytes(zip64 ? 20 : 12); + } + return null; + } case DIGITAL_SIGNATURE: return null; case DIRECTORY_END_HEADER_BYTES: - { - var entry = new DirectoryEndHeader(); - entry.Read(reader); - return entry; - } + { + var entry = new DirectoryEndHeader(); + entry.Read(reader); + return entry; + } case SPLIT_ARCHIVE_HEADER_BYTES: - { - return new SplitHeader(); - } + { + return new SplitHeader(); + } case ZIP64_END_OF_CENTRAL_DIRECTORY: - { - var entry = new Zip64DirectoryEndHeader(); - entry.Read(reader); - return entry; - } + { + var entry = new Zip64DirectoryEndHeader(); + entry.Read(reader); + return entry; + } case ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR: - { - var entry = new Zip64DirectoryEndLocatorHeader(); - entry.Read(reader); - return entry; - } + { + var entry = new Zip64DirectoryEndLocatorHeader(); + entry.Read(reader); + return entry; + } default: return null; } @@ -114,10 +127,15 @@ namespace SharpCompress.Common.Zip { if (FlagUtility.HasFlag(entryHeader.Flags, HeaderFlags.Encrypted)) { - if (!entryHeader.IsDirectory && entryHeader.CompressedSize == 0 && - FlagUtility.HasFlag(entryHeader.Flags, HeaderFlags.UsePostDataDescriptor)) + if ( + !entryHeader.IsDirectory + && entryHeader.CompressedSize == 0 + && FlagUtility.HasFlag(entryHeader.Flags, HeaderFlags.UsePostDataDescriptor) + ) { - throw new NotSupportedException("SharpCompress cannot currently read non-seekable Zip Streams with encrypted data that has been written in a non-seekable manner."); + throw new NotSupportedException( + "SharpCompress cannot currently read non-seekable Zip Streams with encrypted data that has been written in a non-seekable manner." + ); } if (_password is null) @@ -129,7 +147,9 @@ namespace SharpCompress.Common.Zip if (entryHeader.CompressionMethod == ZipCompressionMethod.WinzipAes) { - ExtraData? data = entryHeader.Extra.SingleOrDefault(x => x.Type == ExtraDataType.WinZipAes); + ExtraData? data = entryHeader.Extra.SingleOrDefault( + x => x.Type == ExtraDataType.WinZipAes + ); if (data != null) { var keySize = (WinzipAesKeySize)data.DataBytes[4]; @@ -138,8 +158,12 @@ namespace SharpCompress.Common.Zip var passwordVerifyValue = new byte[2]; stream.Read(salt, 0, salt.Length); stream.Read(passwordVerifyValue, 0, 2); - entryHeader.WinzipAesEncryptionData = - new WinzipAesEncryptionData(keySize, salt, passwordVerifyValue, _password); + entryHeader.WinzipAesEncryptionData = new WinzipAesEncryptionData( + keySize, + salt, + passwordVerifyValue, + _password + ); entryHeader.CompressedSize -= (uint)(salt.Length + 2); } @@ -160,25 +184,25 @@ namespace SharpCompress.Common.Zip switch (_mode) { case StreamingMode.Seekable: - { - entryHeader.DataStartPosition = stream.Position; - stream.Position += entryHeader.CompressedSize; - break; - } + { + entryHeader.DataStartPosition = stream.Position; + stream.Position += entryHeader.CompressedSize; + break; + } case StreamingMode.Streaming: - { - entryHeader.PackedStream = stream; - break; - } + { + entryHeader.PackedStream = stream; + break; + } default: - { - throw new InvalidFormatException("Invalid StreamingMode"); - } + { + throw new InvalidFormatException("Invalid StreamingMode"); + } } //} } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Common/Zip/ZipVolume.cs b/src/SharpCompress/Common/Zip/ZipVolume.cs index 856a5836..f8843305 100644 --- a/src/SharpCompress/Common/Zip/ZipVolume.cs +++ b/src/SharpCompress/Common/Zip/ZipVolume.cs @@ -6,9 +6,7 @@ namespace SharpCompress.Common.Zip public class ZipVolume : Volume { public ZipVolume(Stream stream, ReaderOptions readerOptions, int index = 0) - : base(stream, readerOptions, index) - { - } + : base(stream, readerOptions, index) { } public string? Comment { get; internal set; } } diff --git a/src/SharpCompress/Compressors/ADC/ADCStream.cs b/src/SharpCompress/Compressors/ADC/ADCStream.cs index 8d973a98..02337d8f 100644 --- a/src/SharpCompress/Compressors/ADC/ADCStream.cs +++ b/src/SharpCompress/Compressors/ADC/ADCStream.cs @@ -66,7 +66,10 @@ namespace SharpCompress.Compressors.ADC /// /// Stream that contains the compressed data /// Must be set to because compression is not implemented - public ADCStream(Stream stream, CompressionMode compressionMode = CompressionMode.Decompress) + public ADCStream( + Stream stream, + CompressionMode compressionMode = CompressionMode.Decompress + ) { if (compressionMode == CompressionMode.Compress) { @@ -84,12 +87,14 @@ namespace SharpCompress.Compressors.ADC public override long Length => throw new NotSupportedException(); - public override long Position { get => _position; set => throw new NotSupportedException(); } - - public override void Flush() + public override long Position { + get => _position; + set => throw new NotSupportedException(); } + public override void Flush() { } + protected override void Dispose(bool disposing) { if (_isDisposed) @@ -173,4 +178,4 @@ namespace SharpCompress.Compressors.ADC throw new NotSupportedException(); } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/BZip2/BZip2Constants.cs b/src/SharpCompress/Compressors/BZip2/BZip2Constants.cs index ed506844..6644c278 100644 --- a/src/SharpCompress/Compressors/BZip2/BZip2Constants.cs +++ b/src/SharpCompress/Compressors/BZip2/BZip2Constants.cs @@ -44,58 +44,518 @@ namespace SharpCompress.Compressors.BZip2 public static int[] rNums = { - 619, 720, 127, 481, 931, 816, 813, 233, 566, 247, - 985, 724, 205, 454, 863, 491, 741, 242, 949, 214, - 733, 859, 335, 708, 621, 574, 73, 654, 730, 472, - 419, 436, 278, 496, 867, 210, 399, 680, 480, 51, - 878, 465, 811, 169, 869, 675, 611, 697, 867, 561, - 862, 687, 507, 283, 482, 129, 807, 591, 733, 623, - 150, 238, 59, 379, 684, 877, 625, 169, 643, 105, - 170, 607, 520, 932, 727, 476, 693, 425, 174, 647, - 73, 122, 335, 530, 442, 853, 695, 249, 445, 515, - 909, 545, 703, 919, 874, 474, 882, 500, 594, 612, - 641, 801, 220, 162, 819, 984, 589, 513, 495, 799, - 161, 604, 958, 533, 221, 400, 386, 867, 600, 782, - 382, 596, 414, 171, 516, 375, 682, 485, 911, 276, - 98, 553, 163, 354, 666, 933, 424, 341, 533, 870, - 227, 730, 475, 186, 263, 647, 537, 686, 600, 224, - 469, 68, 770, 919, 190, 373, 294, 822, 808, 206, - 184, 943, 795, 384, 383, 461, 404, 758, 839, 887, - 715, 67, 618, 276, 204, 918, 873, 777, 604, 560, - 951, 160, 578, 722, 79, 804, 96, 409, 713, 940, - 652, 934, 970, 447, 318, 353, 859, 672, 112, 785, - 645, 863, 803, 350, 139, 93, 354, 99, 820, 908, - 609, 772, 154, 274, 580, 184, 79, 626, 630, 742, - 653, 282, 762, 623, 680, 81, 927, 626, 789, 125, - 411, 521, 938, 300, 821, 78, 343, 175, 128, 250, - 170, 774, 972, 275, 999, 639, 495, 78, 352, 126, - 857, 956, 358, 619, 580, 124, 737, 594, 701, 612, - 669, 112, 134, 694, 363, 992, 809, 743, 168, 974, - 944, 375, 748, 52, 600, 747, 642, 182, 862, 81, - 344, 805, 988, 739, 511, 655, 814, 334, 249, 515, - 897, 955, 664, 981, 649, 113, 974, 459, 893, 228, - 433, 837, 553, 268, 926, 240, 102, 654, 459, 51, - 686, 754, 806, 760, 493, 403, 415, 394, 687, 700, - 946, 670, 656, 610, 738, 392, 760, 799, 887, 653, - 978, 321, 576, 617, 626, 502, 894, 679, 243, 440, - 680, 879, 194, 572, 640, 724, 926, 56, 204, 700, - 707, 151, 457, 449, 797, 195, 791, 558, 945, 679, - 297, 59, 87, 824, 713, 663, 412, 693, 342, 606, - 134, 108, 571, 364, 631, 212, 174, 643, 304, 329, - 343, 97, 430, 751, 497, 314, 983, 374, 822, 928, - 140, 206, 73, 263, 980, 736, 876, 478, 430, 305, - 170, 514, 364, 692, 829, 82, 855, 953, 676, 246, - 369, 970, 294, 750, 807, 827, 150, 790, 288, 923, - 804, 378, 215, 828, 592, 281, 565, 555, 710, 82, - 896, 831, 547, 261, 524, 462, 293, 465, 502, 56, - 661, 821, 976, 991, 658, 869, 905, 758, 745, 193, - 768, 550, 608, 933, 378, 286, 215, 979, 792, 961, - 61, 688, 793, 644, 986, 403, 106, 366, 905, 644, - 372, 567, 466, 434, 645, 210, 389, 550, 919, 135, - 780, 773, 635, 389, 707, 100, 626, 958, 165, 504, - 920, 176, 193, 713, 857, 265, 203, 50, 668, 108, - 645, 990, 626, 197, 510, 357, 358, 850, 858, 364, - 936, 638 + 619, + 720, + 127, + 481, + 931, + 816, + 813, + 233, + 566, + 247, + 985, + 724, + 205, + 454, + 863, + 491, + 741, + 242, + 949, + 214, + 733, + 859, + 335, + 708, + 621, + 574, + 73, + 654, + 730, + 472, + 419, + 436, + 278, + 496, + 867, + 210, + 399, + 680, + 480, + 51, + 878, + 465, + 811, + 169, + 869, + 675, + 611, + 697, + 867, + 561, + 862, + 687, + 507, + 283, + 482, + 129, + 807, + 591, + 733, + 623, + 150, + 238, + 59, + 379, + 684, + 877, + 625, + 169, + 643, + 105, + 170, + 607, + 520, + 932, + 727, + 476, + 693, + 425, + 174, + 647, + 73, + 122, + 335, + 530, + 442, + 853, + 695, + 249, + 445, + 515, + 909, + 545, + 703, + 919, + 874, + 474, + 882, + 500, + 594, + 612, + 641, + 801, + 220, + 162, + 819, + 984, + 589, + 513, + 495, + 799, + 161, + 604, + 958, + 533, + 221, + 400, + 386, + 867, + 600, + 782, + 382, + 596, + 414, + 171, + 516, + 375, + 682, + 485, + 911, + 276, + 98, + 553, + 163, + 354, + 666, + 933, + 424, + 341, + 533, + 870, + 227, + 730, + 475, + 186, + 263, + 647, + 537, + 686, + 600, + 224, + 469, + 68, + 770, + 919, + 190, + 373, + 294, + 822, + 808, + 206, + 184, + 943, + 795, + 384, + 383, + 461, + 404, + 758, + 839, + 887, + 715, + 67, + 618, + 276, + 204, + 918, + 873, + 777, + 604, + 560, + 951, + 160, + 578, + 722, + 79, + 804, + 96, + 409, + 713, + 940, + 652, + 934, + 970, + 447, + 318, + 353, + 859, + 672, + 112, + 785, + 645, + 863, + 803, + 350, + 139, + 93, + 354, + 99, + 820, + 908, + 609, + 772, + 154, + 274, + 580, + 184, + 79, + 626, + 630, + 742, + 653, + 282, + 762, + 623, + 680, + 81, + 927, + 626, + 789, + 125, + 411, + 521, + 938, + 300, + 821, + 78, + 343, + 175, + 128, + 250, + 170, + 774, + 972, + 275, + 999, + 639, + 495, + 78, + 352, + 126, + 857, + 956, + 358, + 619, + 580, + 124, + 737, + 594, + 701, + 612, + 669, + 112, + 134, + 694, + 363, + 992, + 809, + 743, + 168, + 974, + 944, + 375, + 748, + 52, + 600, + 747, + 642, + 182, + 862, + 81, + 344, + 805, + 988, + 739, + 511, + 655, + 814, + 334, + 249, + 515, + 897, + 955, + 664, + 981, + 649, + 113, + 974, + 459, + 893, + 228, + 433, + 837, + 553, + 268, + 926, + 240, + 102, + 654, + 459, + 51, + 686, + 754, + 806, + 760, + 493, + 403, + 415, + 394, + 687, + 700, + 946, + 670, + 656, + 610, + 738, + 392, + 760, + 799, + 887, + 653, + 978, + 321, + 576, + 617, + 626, + 502, + 894, + 679, + 243, + 440, + 680, + 879, + 194, + 572, + 640, + 724, + 926, + 56, + 204, + 700, + 707, + 151, + 457, + 449, + 797, + 195, + 791, + 558, + 945, + 679, + 297, + 59, + 87, + 824, + 713, + 663, + 412, + 693, + 342, + 606, + 134, + 108, + 571, + 364, + 631, + 212, + 174, + 643, + 304, + 329, + 343, + 97, + 430, + 751, + 497, + 314, + 983, + 374, + 822, + 928, + 140, + 206, + 73, + 263, + 980, + 736, + 876, + 478, + 430, + 305, + 170, + 514, + 364, + 692, + 829, + 82, + 855, + 953, + 676, + 246, + 369, + 970, + 294, + 750, + 807, + 827, + 150, + 790, + 288, + 923, + 804, + 378, + 215, + 828, + 592, + 281, + 565, + 555, + 710, + 82, + 896, + 831, + 547, + 261, + 524, + 462, + 293, + 465, + 502, + 56, + 661, + 821, + 976, + 991, + 658, + 869, + 905, + 758, + 745, + 193, + 768, + 550, + 608, + 933, + 378, + 286, + 215, + 979, + 792, + 961, + 61, + 688, + 793, + 644, + 986, + 403, + 106, + 366, + 905, + 644, + 372, + 567, + 466, + 434, + 645, + 210, + 389, + 550, + 919, + 135, + 780, + 773, + 635, + 389, + 707, + 100, + 626, + 958, + 165, + 504, + 920, + 176, + 193, + 713, + 857, + 265, + 203, + 50, + 668, + 108, + 645, + 990, + 626, + 197, + 510, + 357, + 358, + 850, + 858, + 364, + 936, + 638 }; } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/BZip2/BZip2Stream.cs b/src/SharpCompress/Compressors/BZip2/BZip2Stream.cs index a65ca51f..ea54e7e9 100644 --- a/src/SharpCompress/Compressors/BZip2/BZip2Stream.cs +++ b/src/SharpCompress/Compressors/BZip2/BZip2Stream.cs @@ -14,8 +14,11 @@ namespace SharpCompress.Compressors.BZip2 /// The stream to read from /// Compression Mode /// Decompress Concatenated - public BZip2Stream(Stream stream, CompressionMode compressionMode, - bool decompressConcatenated) + public BZip2Stream( + Stream stream, + CompressionMode compressionMode, + bool decompressConcatenated + ) { Mode = compressionMode; if (Mode == CompressionMode.Compress) @@ -61,7 +64,11 @@ namespace SharpCompress.Compressors.BZip2 public override long Length => stream.Length; - public override long Position { get => stream.Position; set => stream.Position = value; } + public override long Position + { + get => stream.Position; + set => stream.Position = value; + } public override int Read(byte[] buffer, int offset, int count) { @@ -94,7 +101,6 @@ namespace SharpCompress.Compressors.BZip2 { stream.Write(buffer); } - #endif public override void Write(byte[] buffer, int offset, int count) diff --git a/src/SharpCompress/Compressors/BZip2/CBZip2InputStream.cs b/src/SharpCompress/Compressors/BZip2/CBZip2InputStream.cs index 62c928ab..1b77ed84 100644 --- a/src/SharpCompress/Compressors/BZip2/CBZip2InputStream.cs +++ b/src/SharpCompress/Compressors/BZip2/CBZip2InputStream.cs @@ -116,9 +116,18 @@ namespace SharpCompress.Compressors.BZip2 */ private readonly int[] unzftab = new int[256]; - private readonly int[][] limit = InitIntArray(BZip2Constants.N_GROUPS, BZip2Constants.MAX_ALPHA_SIZE); - private readonly int[][] basev = InitIntArray(BZip2Constants.N_GROUPS, BZip2Constants.MAX_ALPHA_SIZE); - private readonly int[][] perm = InitIntArray(BZip2Constants.N_GROUPS, BZip2Constants.MAX_ALPHA_SIZE); + private readonly int[][] limit = InitIntArray( + BZip2Constants.N_GROUPS, + BZip2Constants.MAX_ALPHA_SIZE + ); + private readonly int[][] basev = InitIntArray( + BZip2Constants.N_GROUPS, + BZip2Constants.MAX_ALPHA_SIZE + ); + private readonly int[][] perm = InitIntArray( + BZip2Constants.N_GROUPS, + BZip2Constants.MAX_ALPHA_SIZE + ); private readonly int[] minLens = new int[BZip2Constants.N_GROUPS]; private Stream bsStream; @@ -137,12 +146,18 @@ namespace SharpCompress.Compressors.BZip2 private int currentState = START_BLOCK_STATE; - private int storedBlockCRC, storedCombinedCRC; - private int computedBlockCRC, computedCombinedCRC; + private int storedBlockCRC, + storedCombinedCRC; + private int computedBlockCRC, + computedCombinedCRC; private readonly bool decompressConcatenated; - private int i2, count, chPrev, ch2; - private int i, tPos; + private int i2, + count, + chPrev, + ch2; + private int i, + tPos; private int rNToGo; private int rTPos; private int j2; @@ -256,8 +271,12 @@ namespace SharpCompress.Compressors.BZip2 private void InitBlock() { - char magic1, magic2, magic3, magic4; - char magic5, magic6; + char magic1, + magic2, + magic3, + magic4; + char magic5, + magic6; while (true) { @@ -267,8 +286,14 @@ namespace SharpCompress.Compressors.BZip2 magic4 = BsGetUChar(); magic5 = BsGetUChar(); magic6 = BsGetUChar(); - if (magic1 != 0x17 || magic2 != 0x72 || magic3 != 0x45 - || magic4 != 0x38 || magic5 != 0x50 || magic6 != 0x90) + if ( + magic1 != 0x17 + || magic2 != 0x72 + || magic3 != 0x45 + || magic4 != 0x38 + || magic5 != 0x50 + || magic6 != 0x90 + ) { break; } @@ -279,8 +304,14 @@ namespace SharpCompress.Compressors.BZip2 } } - if (magic1 != 0x31 || magic2 != 0x41 || magic3 != 0x59 - || magic4 != 0x26 || magic5 != 0x53 || magic6 != 0x59) + if ( + magic1 != 0x31 + || magic2 != 0x41 + || magic3 != 0x59 + || magic4 != 0x26 + || magic5 != 0x53 + || magic6 != 0x59 + ) { BadBlockHeader(); streamEnd = true; @@ -314,8 +345,8 @@ namespace SharpCompress.Compressors.BZip2 CrcError(); } - computedCombinedCRC = (computedCombinedCRC << 1) - | (int)(((uint)computedCombinedCRC) >> 31); + computedCombinedCRC = + (computedCombinedCRC << 1) | (int)(((uint)computedCombinedCRC) >> 31); computedCombinedCRC ^= computedBlockCRC; } @@ -421,11 +452,20 @@ namespace SharpCompress.Compressors.BZip2 return BsGetint(); } - private void HbCreateDecodeTables(int[] limit, int[] basev, - int[] perm, char[] length, - int minLen, int maxLen, int alphaSize) + private void HbCreateDecodeTables( + int[] limit, + int[] basev, + int[] perm, + char[] length, + int minLen, + int maxLen, + int alphaSize + ) { - int pp, i, j, vec; + int pp, + i, + j, + vec; pp = 0; for (i = minLen; i <= maxLen; i++) @@ -475,8 +515,14 @@ namespace SharpCompress.Compressors.BZip2 private void RecvDecodingTables() { char[][] len = InitCharArray(BZip2Constants.N_GROUPS, BZip2Constants.MAX_ALPHA_SIZE); - int i, j, t, nGroups, nSelectors, alphaSize; - int minLen, maxLen; + int i, + j, + t, + nGroups, + nSelectors, + alphaSize; + int minLen, + maxLen; bool[] inUse16 = new bool[16]; /* Receive the mapping table */ @@ -530,7 +576,8 @@ namespace SharpCompress.Compressors.BZip2 /* Undo the MTF values for the selectors. */ { char[] pos = new char[BZip2Constants.N_GROUPS]; - char tmp, v; + char tmp, + v; for (v = '\0'; v < nGroups; v++) { pos[v] = v; @@ -587,8 +634,15 @@ namespace SharpCompress.Compressors.BZip2 minLen = len[t][i]; } } - HbCreateDecodeTables(limit[t], basev[t], perm[t], len[t], minLen, - maxLen, alphaSize); + HbCreateDecodeTables( + limit[t], + basev[t], + perm[t], + len[t], + minLen, + maxLen, + alphaSize + ); minLens[t] = minLen; } } @@ -596,8 +650,13 @@ namespace SharpCompress.Compressors.BZip2 private void GetAndMoveToFrontDecode() { char[] yy = new char[256]; - int i, j, nextSym, limitLast; - int EOB, groupNo, groupPos; + int i, + j, + nextSym, + limitLast; + int EOB, + groupNo, + groupPos; limitLast = BZip2Constants.baseBlockSize * blockSize100k; origPtr = BsGetIntVS(24); @@ -626,7 +685,10 @@ namespace SharpCompress.Compressors.BZip2 last = -1; { - int zt, zn, zvec, zj; + int zt, + zn, + zvec, + zj; if (groupPos == 0) { groupNo++; @@ -694,7 +756,10 @@ namespace SharpCompress.Compressors.BZip2 } N = N * 2; { - int zt, zn, zvec, zj; + int zt, + zn, + zvec, + zj; if (groupPos == 0) { groupNo++; @@ -737,8 +802,7 @@ namespace SharpCompress.Compressors.BZip2 } nextSym = perm[zt][zvec - basev[zt][zn]]; } - } - while (nextSym == BZip2Constants.RUNA || nextSym == BZip2Constants.RUNB); + } while (nextSym == BZip2Constants.RUNA || nextSym == BZip2Constants.RUNB); s++; ch = seqToUnseq[yy[0]]; @@ -791,7 +855,10 @@ namespace SharpCompress.Compressors.BZip2 yy[0] = tmp; { - int zt, zn, zvec, zj; + int zt, + zn, + zvec, + zj; if (groupPos == 0) { groupNo++; @@ -1028,8 +1095,7 @@ namespace SharpCompress.Compressors.BZip2 private void SetDecompressStructureSizes(int newSize100k) { - if (!(0 <= newSize100k && newSize100k <= 9 && 0 <= blockSize100k - && blockSize100k <= 9)) + if (!(0 <= newSize100k && newSize100k <= 9 && 0 <= blockSize100k && blockSize100k <= 9)) { // throw new IOException("Invalid block size"); } @@ -1046,9 +1112,7 @@ namespace SharpCompress.Compressors.BZip2 tt = new int[n]; } - public override void Flush() - { - } + public override void Flush() { } public override int Read(byte[] buffer, int offset, int count) { @@ -1071,17 +1135,11 @@ namespace SharpCompress.Compressors.BZip2 return 0; } - public override void SetLength(long value) - { - } + public override void SetLength(long value) { } - public override void Write(byte[] buffer, int offset, int count) - { - } + public override void Write(byte[] buffer, int offset, int count) { } - public override void WriteByte(byte value) - { - } + public override void WriteByte(byte value) { } public override bool CanRead => true; @@ -1091,6 +1149,10 @@ namespace SharpCompress.Compressors.BZip2 public override long Length => 0; - public override long Position { get { return 0; } set { } } + public override long Position + { + get { return 0; } + set { } + } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/BZip2/CBZip2OutputStream.cs b/src/SharpCompress/Compressors/BZip2/CBZip2OutputStream.cs index b86695bd..2e0f8005 100644 --- a/src/SharpCompress/Compressors/BZip2/CBZip2OutputStream.cs +++ b/src/SharpCompress/Compressors/BZip2/CBZip2OutputStream.cs @@ -79,19 +79,24 @@ namespace SharpCompress.Compressors.BZip2 } } - private static void HbMakeCodeLengths(char[] len, int[] freq, - int alphaSize, int maxLen) + private static void HbMakeCodeLengths(char[] len, int[] freq, int alphaSize, int maxLen) { /* Nodes and heap entries run from 1. Entry 0 for both the heap and nodes is a sentinel. */ - int nNodes, nHeap, n1, n2, i, j, k; + int nNodes, + nHeap, + n1, + n2, + i, + j, + k; bool tooLong; Span heap = stackalloc int[BZip2Constants.MAX_ALPHA_SIZE + 2]; // 1040 bytes - Span weight = stackalloc int[BZip2Constants.MAX_ALPHA_SIZE * 2]; // 1040 bytes - Span parent = stackalloc int[BZip2Constants.MAX_ALPHA_SIZE * 2]; // 1040 bytes + Span weight = stackalloc int[BZip2Constants.MAX_ALPHA_SIZE * 2]; // 1040 bytes + Span parent = stackalloc int[BZip2Constants.MAX_ALPHA_SIZE * 2]; // 1040 bytes for (i = 0; i < alphaSize; i++) { @@ -113,7 +118,8 @@ namespace SharpCompress.Compressors.BZip2 nHeap++; heap[nHeap] = i; { - int zz, tmp; + int zz, + tmp; zz = nHeap; tmp = heap[zz]; while (weight[tmp] < weight[heap[zz >> 1]]) @@ -135,7 +141,9 @@ namespace SharpCompress.Compressors.BZip2 heap[1] = heap[nHeap]; nHeap--; { - int zz = 0, yy = 0, tmp = 0; + int zz = 0, + yy = 0, + tmp = 0; zz = 1; tmp = heap[zz]; while (true) @@ -145,8 +153,7 @@ namespace SharpCompress.Compressors.BZip2 { break; } - if (yy < nHeap - && weight[heap[yy + 1]] < weight[heap[yy]]) + if (yy < nHeap && weight[heap[yy + 1]] < weight[heap[yy]]) { yy++; } @@ -163,7 +170,9 @@ namespace SharpCompress.Compressors.BZip2 heap[1] = heap[nHeap]; nHeap--; { - int zz = 0, yy = 0, tmp = 0; + int zz = 0, + yy = 0, + tmp = 0; zz = 1; tmp = heap[zz]; while (true) @@ -173,8 +182,7 @@ namespace SharpCompress.Compressors.BZip2 { break; } - if (yy < nHeap - && weight[heap[yy + 1]] < weight[heap[yy]]) + if (yy < nHeap && weight[heap[yy + 1]] < weight[heap[yy]]) { yy++; } @@ -190,18 +198,24 @@ namespace SharpCompress.Compressors.BZip2 nNodes++; parent[n1] = parent[n2] = nNodes; - weight[nNodes] = (int)((uint)((weight[n1] & 0xffffff00) - + (weight[n2] & 0xffffff00)) - | (uint)(1 + (((weight[n1] & 0x000000ff) > - (weight[n2] & 0x000000ff)) - ? (weight[n1] & 0x000000ff) - : (weight[n2] & 0x000000ff)))); + weight[nNodes] = (int)( + (uint)((weight[n1] & 0xffffff00) + (weight[n2] & 0xffffff00)) + | (uint)( + 1 + + ( + ((weight[n1] & 0x000000ff) > (weight[n2] & 0x000000ff)) + ? (weight[n1] & 0x000000ff) + : (weight[n2] & 0x000000ff) + ) + ) + ); parent[nNodes] = -1; nHeap++; heap[nHeap] = nNodes; { - int zz = 0, tmp = 0; + int zz = 0, + tmp = 0; zz = nHeap; tmp = heap[zz]; while (weight[tmp] < weight[heap[zz >> 1]]) @@ -305,10 +319,7 @@ namespace SharpCompress.Compressors.BZip2 private int currentChar = -1; private int runLength; - public CBZip2OutputStream(Stream inStream) - : this(inStream, 9) - { - } + public CBZip2OutputStream(Stream inStream) : this(inStream, 9) { } public CBZip2OutputStream(Stream inStream, int inBlockSize) { @@ -467,7 +478,8 @@ namespace SharpCompress.Compressors.BZip2 bsStream.Flush(); } - private int blockCRC, combinedCRC; + private int blockCRC, + combinedCRC; private void Initialize() { @@ -570,10 +582,11 @@ namespace SharpCompress.Compressors.BZip2 BsFinishedWithStream(); } - private void HbAssignCodes(int[] code, char[] length, int minLen, - int maxLen, int alphaSize) + private void HbAssignCodes(int[] code, char[] length, int minLen, int maxLen, int alphaSize) { - int n, vec, i; + int n, + vec, + i; vec = 0; for (n = minLen; n <= maxLen; n++) @@ -645,10 +658,26 @@ namespace SharpCompress.Compressors.BZip2 private void SendMTFValues() { - char[][] len = CBZip2InputStream.InitCharArray(BZip2Constants.N_GROUPS, BZip2Constants.MAX_ALPHA_SIZE); + char[][] len = CBZip2InputStream.InitCharArray( + BZip2Constants.N_GROUPS, + BZip2Constants.MAX_ALPHA_SIZE + ); - int v, t, i, j, gs, ge, totc, bt, bc, iter; - int nSelectors = 0, alphaSize, minLen, maxLen, selCtr; + int v, + t, + i, + j, + gs, + ge, + totc, + bt, + bc, + iter; + int nSelectors = 0, + alphaSize, + minLen, + maxLen, + selCtr; int nGroups; //, nBytes; alphaSize = nInUse + 2; @@ -689,7 +718,10 @@ namespace SharpCompress.Compressors.BZip2 /* Generate an initial set of coding tables */ { - int nPart, remF, tFreq, aFreq; + int nPart, + remF, + tFreq, + aFreq; nPart = nGroups; remF = nMTF; @@ -705,8 +737,7 @@ namespace SharpCompress.Compressors.BZip2 aFreq += mtfFreq[ge]; } - if (ge > gs && nPart != nGroups && nPart != 1 - && ((nGroups - nPart) % 2 == 1)) + if (ge > gs && nPart != nGroups && nPart != 1 && ((nGroups - nPart) % 2 == 1)) { aFreq -= mtfFreq[ge]; ge--; @@ -730,7 +761,10 @@ namespace SharpCompress.Compressors.BZip2 } } - int[][] rfreq = CBZip2InputStream.InitIntArray(BZip2Constants.N_GROUPS, BZip2Constants.MAX_ALPHA_SIZE); + int[][] rfreq = CBZip2InputStream.InitIntArray( + BZip2Constants.N_GROUPS, + BZip2Constants.MAX_ALPHA_SIZE + ); int[] fave = new int[BZip2Constants.N_GROUPS]; short[] cost = new short[BZip2Constants.N_GROUPS]; /* @@ -778,7 +812,12 @@ namespace SharpCompress.Compressors.BZip2 if (nGroups == 6) { - short cost0, cost1, cost2, cost3, cost4, cost5; + short cost0, + cost1, + cost2, + cost3, + cost4, + cost5; cost0 = cost1 = cost2 = cost3 = cost4 = cost5 = 0; for (i = gs; i <= ge; i++) { @@ -865,7 +904,9 @@ namespace SharpCompress.Compressors.BZip2 /* Compute MTF values for the selectors. */ { char[] pos = new char[BZip2Constants.N_GROUPS]; - char ll_i, tmp2, tmp; + char ll_i, + tmp2, + tmp; for (i = 0; i < nGroups; i++) { pos[i] = (char)i; @@ -887,7 +928,10 @@ namespace SharpCompress.Compressors.BZip2 } } - int[][] code = CBZip2InputStream.InitIntArray(BZip2Constants.N_GROUPS, BZip2Constants.MAX_ALPHA_SIZE); + int[][] code = CBZip2InputStream.InitIntArray( + BZip2Constants.N_GROUPS, + BZip2Constants.MAX_ALPHA_SIZE + ); /* Assign actual codes for the tables. */ for (t = 0; t < nGroups; t++) @@ -1016,8 +1060,7 @@ namespace SharpCompress.Compressors.BZip2 } for (i = gs; i <= ge; i++) { - BsW(len[selector[selCtr]][szptr[i]], - code[selector[selCtr]][szptr[i]]); + BsW(len[selector[selCtr]][szptr[i]], code[selector[selCtr]][szptr[i]]); } gs = ge + 1; @@ -1040,7 +1083,11 @@ namespace SharpCompress.Compressors.BZip2 private void SimpleSort(int lo, int hi, int d) { - int i, j, h, bigN, hp; + int i, + j, + h, + bigN, + hp; int v; bigN = hi - lo + 1; @@ -1173,8 +1220,17 @@ namespace SharpCompress.Compressors.BZip2 private void QSort3(int loSt, int hiSt, int dSt) { - int unLo, unHi, ltLo, gtHi, med, n, m; - int sp, lo, hi, d; + int unLo, + unHi, + ltLo, + gtHi, + med, + n, + m; + int sp, + lo, + hi, + d; StackElem[] stack = new StackElem[QSORT_STACK_SIZE]; for (int count = 0; count < QSORT_STACK_SIZE; count++) { @@ -1210,9 +1266,11 @@ namespace SharpCompress.Compressors.BZip2 continue; } - med = Med3(block[zptr[lo] + d + 1], - block[zptr[hi] + d + 1], - block[zptr[(lo + hi) >> 1] + d + 1]); + med = Med3( + block[zptr[lo] + d + 1], + block[zptr[hi] + d + 1], + block[zptr[(lo + hi) >> 1] + d + 1] + ); unLo = ltLo = lo; unHi = gtHi = hi; @@ -1314,11 +1372,15 @@ namespace SharpCompress.Compressors.BZip2 private void MainSort() { - int i, j, ss, sb; + int i, + j, + ss, + sb; Span runningOrder = stackalloc int[256]; Span copy = stackalloc int[256]; bool[] bigDone = new bool[256]; - int c1, c2; + int c1, + c2; int numQSorted; /* @@ -1410,8 +1472,7 @@ namespace SharpCompress.Compressors.BZip2 do { h = 3 * h + 1; - } - while (h <= 256); + } while (h <= 256); do { h = h / 3; @@ -1419,9 +1480,12 @@ namespace SharpCompress.Compressors.BZip2 { vv = runningOrder[i]; j = i; - while ((ftab[((runningOrder[j - h]) + 1) << 8] - - ftab[(runningOrder[j - h]) << 8]) > - (ftab[((vv) + 1) << 8] - ftab[(vv) << 8])) + while ( + ( + ftab[((runningOrder[j - h]) + 1) << 8] + - ftab[(runningOrder[j - h]) << 8] + ) > (ftab[((vv) + 1) << 8] - ftab[(vv) << 8]) + ) { runningOrder[j] = runningOrder[j - h]; j = j - h; @@ -1432,8 +1496,7 @@ namespace SharpCompress.Compressors.BZip2 } runningOrder[j] = vv; } - } - while (h != 1); + } while (h != 1); } /* @@ -1520,9 +1583,7 @@ namespace SharpCompress.Compressors.BZip2 copy[j] = ftab[(j << 8) + ss] & CLEARMASK; } - for (j = ftab[ss << 8] & CLEARMASK; - j < (ftab[(ss + 1) << 8] & CLEARMASK); - j++) + for (j = ftab[ss << 8] & CLEARMASK; j < (ftab[(ss + 1) << 8] & CLEARMASK); j++) { c1 = block[zptr[j]]; if (!bigDone[c1]) @@ -1611,8 +1672,10 @@ namespace SharpCompress.Compressors.BZip2 private bool FullGtU(int i1, int i2) { int k; - char c1, c2; - int s1, s2; + char c1, + c2; + int s1, + s2; c1 = block[i1 + 1]; c2 = block[i2 + 1]; @@ -1747,8 +1810,7 @@ namespace SharpCompress.Compressors.BZip2 k -= 4; workDone++; - } - while (k >= 0); + } while (k >= 0); return false; } @@ -1762,9 +1824,20 @@ namespace SharpCompress.Compressors.BZip2 private readonly int[] incs = { - 1, 4, 13, 40, 121, 364, 1093, 3280, - 9841, 29524, 88573, 265720, - 797161, 2391484 + 1, + 4, + 13, + 40, + 121, + 364, + 1093, + 3280, + 9841, + 29524, + 88573, + 265720, + 797161, + 2391484 }; private void AllocateCompressStructures() @@ -1799,7 +1872,8 @@ namespace SharpCompress.Compressors.BZip2 private void GenerateMTFValues() { char[] yy = new char[256]; - int i, j; + int i, + j; char tmp; char tmp2; int zPend; @@ -1927,9 +2001,7 @@ namespace SharpCompress.Compressors.BZip2 return 0; } - public override void SetLength(long value) - { - } + public override void SetLength(long value) { } public override void Write(byte[] buffer, int offset, int count) { @@ -1947,6 +2019,10 @@ namespace SharpCompress.Compressors.BZip2 public override long Length => 0; - public override long Position { get { return 0; } set { } } + public override long Position + { + get { return 0; } + set { } + } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/BZip2/CRC.cs b/src/SharpCompress/Compressors/BZip2/CRC.cs index 7ac42130..d9b268cb 100644 --- a/src/SharpCompress/Compressors/BZip2/CRC.cs +++ b/src/SharpCompress/Compressors/BZip2/CRC.cs @@ -33,133 +33,261 @@ namespace SharpCompress.Compressors.BZip2 { public static int[] crc32Table = { - 0x00000000, 0x04c11db7, 0x09823b6e, + 0x00000000, + 0x04c11db7, + 0x09823b6e, 0x0d4326d9, - 0x130476dc, 0x17c56b6b, 0x1a864db2, + 0x130476dc, + 0x17c56b6b, + 0x1a864db2, 0x1e475005, - 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, + 0x2608edb8, + 0x22c9f00f, + 0x2f8ad6d6, 0x2b4bcb61, - 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, + 0x350c9b64, + 0x31cd86d3, + 0x3c8ea00a, 0x384fbdbd, - 0x4c11db70, 0x48d0c6c7, 0x4593e01e, + 0x4c11db70, + 0x48d0c6c7, + 0x4593e01e, 0x4152fda9, - 0x5f15adac, 0x5bd4b01b, 0x569796c2, + 0x5f15adac, + 0x5bd4b01b, + 0x569796c2, 0x52568b75, - 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, + 0x6a1936c8, + 0x6ed82b7f, + 0x639b0da6, 0x675a1011, - 0x791d4014, 0x7ddc5da3, 0x709f7b7a, + 0x791d4014, + 0x7ddc5da3, + 0x709f7b7a, 0x745e66cd, - unchecked((int)0x9823b6e0), unchecked((int)0x9ce2ab57), unchecked((int)0x91a18d8e), + unchecked((int)0x9823b6e0), + unchecked((int)0x9ce2ab57), + unchecked((int)0x91a18d8e), unchecked((int)0x95609039), - unchecked((int)0x8b27c03c), unchecked((int)0x8fe6dd8b), unchecked((int)0x82a5fb52), + unchecked((int)0x8b27c03c), + unchecked((int)0x8fe6dd8b), + unchecked((int)0x82a5fb52), unchecked((int)0x8664e6e5), - unchecked((int)0xbe2b5b58), unchecked((int)0xbaea46ef), unchecked((int)0xb7a96036), + unchecked((int)0xbe2b5b58), + unchecked((int)0xbaea46ef), + unchecked((int)0xb7a96036), unchecked((int)0xb3687d81), - unchecked((int)0xad2f2d84), unchecked((int)0xa9ee3033), unchecked((int)0xa4ad16ea), + unchecked((int)0xad2f2d84), + unchecked((int)0xa9ee3033), + unchecked((int)0xa4ad16ea), unchecked((int)0xa06c0b5d), - unchecked((int)0xd4326d90), unchecked((int)0xd0f37027), unchecked((int)0xddb056fe), + unchecked((int)0xd4326d90), + unchecked((int)0xd0f37027), + unchecked((int)0xddb056fe), unchecked((int)0xd9714b49), - unchecked((int)0xc7361b4c), unchecked((int)0xc3f706fb), unchecked((int)0xceb42022), + unchecked((int)0xc7361b4c), + unchecked((int)0xc3f706fb), + unchecked((int)0xceb42022), unchecked((int)0xca753d95), - unchecked((int)0xf23a8028), unchecked((int)0xf6fb9d9f), unchecked((int)0xfbb8bb46), + unchecked((int)0xf23a8028), + unchecked((int)0xf6fb9d9f), + unchecked((int)0xfbb8bb46), unchecked((int)0xff79a6f1), - unchecked((int)0xe13ef6f4), unchecked((int)0xe5ffeb43), unchecked((int)0xe8bccd9a), + unchecked((int)0xe13ef6f4), + unchecked((int)0xe5ffeb43), + unchecked((int)0xe8bccd9a), unchecked((int)0xec7dd02d), - 0x34867077, 0x30476dc0, 0x3d044b19, + 0x34867077, + 0x30476dc0, + 0x3d044b19, 0x39c556ae, - 0x278206ab, 0x23431b1c, 0x2e003dc5, + 0x278206ab, + 0x23431b1c, + 0x2e003dc5, 0x2ac12072, - 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, + 0x128e9dcf, + 0x164f8078, + 0x1b0ca6a1, 0x1fcdbb16, - 0x018aeb13, 0x054bf6a4, 0x0808d07d, + 0x018aeb13, + 0x054bf6a4, + 0x0808d07d, 0x0cc9cdca, - 0x7897ab07, 0x7c56b6b0, 0x71159069, + 0x7897ab07, + 0x7c56b6b0, + 0x71159069, 0x75d48dde, - 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, + 0x6b93dddb, + 0x6f52c06c, + 0x6211e6b5, 0x66d0fb02, - 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, + 0x5e9f46bf, + 0x5a5e5b08, + 0x571d7dd1, 0x53dc6066, - 0x4d9b3063, 0x495a2dd4, 0x44190b0d, + 0x4d9b3063, + 0x495a2dd4, + 0x44190b0d, 0x40d816ba, - unchecked((int)0xaca5c697), unchecked((int)0xa864db20), unchecked((int)0xa527fdf9), + unchecked((int)0xaca5c697), + unchecked((int)0xa864db20), + unchecked((int)0xa527fdf9), unchecked((int)0xa1e6e04e), - unchecked((int)0xbfa1b04b), unchecked((int)0xbb60adfc), unchecked((int)0xb6238b25), + unchecked((int)0xbfa1b04b), + unchecked((int)0xbb60adfc), + unchecked((int)0xb6238b25), unchecked((int)0xb2e29692), - unchecked((int)0x8aad2b2f), unchecked((int)0x8e6c3698), unchecked((int)0x832f1041), + unchecked((int)0x8aad2b2f), + unchecked((int)0x8e6c3698), + unchecked((int)0x832f1041), unchecked((int)0x87ee0df6), - unchecked((int)0x99a95df3), unchecked((int)0x9d684044), unchecked((int)0x902b669d), + unchecked((int)0x99a95df3), + unchecked((int)0x9d684044), + unchecked((int)0x902b669d), unchecked((int)0x94ea7b2a), - unchecked((int)0xe0b41de7), unchecked((int)0xe4750050), unchecked((int)0xe9362689), + unchecked((int)0xe0b41de7), + unchecked((int)0xe4750050), + unchecked((int)0xe9362689), unchecked((int)0xedf73b3e), - unchecked((int)0xf3b06b3b), unchecked((int)0xf771768c), unchecked((int)0xfa325055), + unchecked((int)0xf3b06b3b), + unchecked((int)0xf771768c), + unchecked((int)0xfa325055), unchecked((int)0xfef34de2), - unchecked((int)0xc6bcf05f), unchecked((int)0xc27dede8), unchecked((int)0xcf3ecb31), + unchecked((int)0xc6bcf05f), + unchecked((int)0xc27dede8), + unchecked((int)0xcf3ecb31), unchecked((int)0xcbffd686), - unchecked((int)0xd5b88683), unchecked((int)0xd1799b34), unchecked((int)0xdc3abded), + unchecked((int)0xd5b88683), + unchecked((int)0xd1799b34), + unchecked((int)0xdc3abded), unchecked((int)0xd8fba05a), - 0x690ce0ee, 0x6dcdfd59, 0x608edb80, + 0x690ce0ee, + 0x6dcdfd59, + 0x608edb80, 0x644fc637, - 0x7a089632, 0x7ec98b85, 0x738aad5c, + 0x7a089632, + 0x7ec98b85, + 0x738aad5c, 0x774bb0eb, - 0x4f040d56, 0x4bc510e1, 0x46863638, + 0x4f040d56, + 0x4bc510e1, + 0x46863638, 0x42472b8f, - 0x5c007b8a, 0x58c1663d, 0x558240e4, + 0x5c007b8a, + 0x58c1663d, + 0x558240e4, 0x51435d53, - 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, + 0x251d3b9e, + 0x21dc2629, + 0x2c9f00f0, 0x285e1d47, - 0x36194d42, 0x32d850f5, 0x3f9b762c, + 0x36194d42, + 0x32d850f5, + 0x3f9b762c, 0x3b5a6b9b, - 0x0315d626, 0x07d4cb91, 0x0a97ed48, + 0x0315d626, + 0x07d4cb91, + 0x0a97ed48, 0x0e56f0ff, - 0x1011a0fa, 0x14d0bd4d, 0x19939b94, + 0x1011a0fa, + 0x14d0bd4d, + 0x19939b94, 0x1d528623, - unchecked((int)0xf12f560e), unchecked((int)0xf5ee4bb9), unchecked((int)0xf8ad6d60), + unchecked((int)0xf12f560e), + unchecked((int)0xf5ee4bb9), + unchecked((int)0xf8ad6d60), unchecked((int)0xfc6c70d7), - unchecked((int)0xe22b20d2), unchecked((int)0xe6ea3d65), unchecked((int)0xeba91bbc), + unchecked((int)0xe22b20d2), + unchecked((int)0xe6ea3d65), + unchecked((int)0xeba91bbc), unchecked((int)0xef68060b), - unchecked((int)0xd727bbb6), unchecked((int)0xd3e6a601), unchecked((int)0xdea580d8), + unchecked((int)0xd727bbb6), + unchecked((int)0xd3e6a601), + unchecked((int)0xdea580d8), unchecked((int)0xda649d6f), - unchecked((int)0xc423cd6a), unchecked((int)0xc0e2d0dd), unchecked((int)0xcda1f604), + unchecked((int)0xc423cd6a), + unchecked((int)0xc0e2d0dd), + unchecked((int)0xcda1f604), unchecked((int)0xc960ebb3), - unchecked((int)0xbd3e8d7e), unchecked((int)0xb9ff90c9), unchecked((int)0xb4bcb610), + unchecked((int)0xbd3e8d7e), + unchecked((int)0xb9ff90c9), + unchecked((int)0xb4bcb610), unchecked((int)0xb07daba7), - unchecked((int)0xae3afba2), unchecked((int)0xaafbe615), unchecked((int)0xa7b8c0cc), + unchecked((int)0xae3afba2), + unchecked((int)0xaafbe615), + unchecked((int)0xa7b8c0cc), unchecked((int)0xa379dd7b), - unchecked((int)0x9b3660c6), unchecked((int)0x9ff77d71), unchecked((int)0x92b45ba8), + unchecked((int)0x9b3660c6), + unchecked((int)0x9ff77d71), + unchecked((int)0x92b45ba8), unchecked((int)0x9675461f), - unchecked((int)0x8832161a), unchecked((int)0x8cf30bad), unchecked((int)0x81b02d74), + unchecked((int)0x8832161a), + unchecked((int)0x8cf30bad), + unchecked((int)0x81b02d74), unchecked((int)0x857130c3), - 0x5d8a9099, 0x594b8d2e, 0x5408abf7, + 0x5d8a9099, + 0x594b8d2e, + 0x5408abf7, 0x50c9b640, - 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, + 0x4e8ee645, + 0x4a4ffbf2, + 0x470cdd2b, 0x43cdc09c, - 0x7b827d21, 0x7f436096, 0x7200464f, + 0x7b827d21, + 0x7f436096, + 0x7200464f, 0x76c15bf8, - 0x68860bfd, 0x6c47164a, 0x61043093, + 0x68860bfd, + 0x6c47164a, + 0x61043093, 0x65c52d24, - 0x119b4be9, 0x155a565e, 0x18197087, + 0x119b4be9, + 0x155a565e, + 0x18197087, 0x1cd86d30, - 0x029f3d35, 0x065e2082, 0x0b1d065b, + 0x029f3d35, + 0x065e2082, + 0x0b1d065b, 0x0fdc1bec, - 0x3793a651, 0x3352bbe6, 0x3e119d3f, + 0x3793a651, + 0x3352bbe6, + 0x3e119d3f, 0x3ad08088, - 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, + 0x2497d08d, + 0x2056cd3a, + 0x2d15ebe3, 0x29d4f654, - unchecked((int)0xc5a92679), unchecked((int)0xc1683bce), unchecked((int)0xcc2b1d17), + unchecked((int)0xc5a92679), + unchecked((int)0xc1683bce), + unchecked((int)0xcc2b1d17), unchecked((int)0xc8ea00a0), - unchecked((int)0xd6ad50a5), unchecked((int)0xd26c4d12), unchecked((int)0xdf2f6bcb), + unchecked((int)0xd6ad50a5), + unchecked((int)0xd26c4d12), + unchecked((int)0xdf2f6bcb), unchecked((int)0xdbee767c), - unchecked((int)0xe3a1cbc1), unchecked((int)0xe760d676), unchecked((int)0xea23f0af), + unchecked((int)0xe3a1cbc1), + unchecked((int)0xe760d676), + unchecked((int)0xea23f0af), unchecked((int)0xeee2ed18), - unchecked((int)0xf0a5bd1d), unchecked((int)0xf464a0aa), unchecked((int)0xf9278673), + unchecked((int)0xf0a5bd1d), + unchecked((int)0xf464a0aa), + unchecked((int)0xf9278673), unchecked((int)0xfde69bc4), - unchecked((int)0x89b8fd09), unchecked((int)0x8d79e0be), unchecked((int)0x803ac667), + unchecked((int)0x89b8fd09), + unchecked((int)0x8d79e0be), + unchecked((int)0x803ac667), unchecked((int)0x84fbdbd0), - unchecked((int)0x9abc8bd5), unchecked((int)0x9e7d9662), unchecked((int)0x933eb0bb), + unchecked((int)0x9abc8bd5), + unchecked((int)0x9e7d9662), + unchecked((int)0x933eb0bb), unchecked((int)0x97ffad0c), - unchecked((int)0xafb010b1), unchecked((int)0xab710d06), unchecked((int)0xa6322bdf), + unchecked((int)0xafb010b1), + unchecked((int)0xab710d06), + unchecked((int)0xa6322bdf), unchecked((int)0xa2f33668), - unchecked((int)0xbcb4666d), unchecked((int)0xb8757bda), unchecked((int)0xb5365d03), + unchecked((int)0xbcb4666d), + unchecked((int)0xb8757bda), + unchecked((int)0xb5365d03), unchecked((int)0xb1f740b4) }; @@ -200,4 +328,4 @@ namespace SharpCompress.Compressors.BZip2 internal int globalCrc; } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/CompressionMode.cs b/src/SharpCompress/Compressors/CompressionMode.cs index 0d288bc5..a886c441 100644 --- a/src/SharpCompress/Compressors/CompressionMode.cs +++ b/src/SharpCompress/Compressors/CompressionMode.cs @@ -5,4 +5,4 @@ Compress = 0, Decompress = 1 } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/Deflate/CRC32.cs b/src/SharpCompress/Compressors/Deflate/CRC32.cs index ac73e843..c1f3a0e2 100644 --- a/src/SharpCompress/Compressors/Deflate/CRC32.cs +++ b/src/SharpCompress/Compressors/Deflate/CRC32.cs @@ -60,7 +60,8 @@ namespace SharpCompress.Compressors.Deflate // Often the polynomial is shown reversed as 0x04C11DB7. // For more details, see http://en.wikipedia.org/wiki/Cyclic_redundancy_check UInt32 dwPolynomial = 0xEDB88320; - UInt32 i, j; + UInt32 i, + j; crc32Table = new UInt32[256]; @@ -118,7 +119,6 @@ namespace SharpCompress.Compressors.Deflate { throw new ZlibException("The input stream must not be null."); } - unchecked { //UInt32 crc32Result; @@ -182,8 +182,9 @@ namespace SharpCompress.Compressors.Deflate for (int i = 0; i < count; i++) { int x = offset + i; - runningCrc32Result = ((runningCrc32Result) >> 8) ^ - crc32Table[(block[x]) ^ ((runningCrc32Result) & 0x000000FF)]; + runningCrc32Result = + ((runningCrc32Result) >> 8) + ^ crc32Table[(block[x]) ^ ((runningCrc32Result) & 0x000000FF)]; } TotalBytesRead += count; } @@ -279,8 +280,7 @@ namespace SharpCompress.Compressors.Deflate crc1 = gf2_matrix_times(odd, crc1); } len2 >>= 1; - } - while (len2 != 0); + } while (len2 != 0); crc1 ^= crc2; diff --git a/src/SharpCompress/Compressors/Deflate/DeflateManager.cs b/src/SharpCompress/Compressors/Deflate/DeflateManager.cs index 0abc4564..e6dd441d 100644 --- a/src/SharpCompress/Compressors/Deflate/DeflateManager.cs +++ b/src/SharpCompress/Compressors/Deflate/DeflateManager.cs @@ -3,52 +3,52 @@ // Deflate.cs // ------------------------------------------------------------------ // -// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation. +// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation. // All rights reserved. // // This code module is part of DotNetZip, a zipfile class library. // // ------------------------------------------------------------------ // -// This code is licensed under the Microsoft Public License. +// This code is licensed under the Microsoft Public License. // See the file License.txt for the license details. // More info on: http://dotnetzip.codeplex.com // // ------------------------------------------------------------------ // -// last saved (in emacs): +// last saved (in emacs): // Time-stamp: <2009-October-28 13:44:59> // // ------------------------------------------------------------------ // // This module defines logic for handling the Deflate or compression. // -// This code is based on multiple sources: +// This code is based on multiple sources: // - the original zlib v1.2.3 source, which is Copyright (C) 1995-2005 Jean-loup Gailly. -// - the original jzlib, which is Copyright (c) 2000-2003 ymnk, JCraft,Inc. +// - the original jzlib, which is Copyright (c) 2000-2003 ymnk, JCraft,Inc. // -// However, this code is significantly different from both. +// However, this code is significantly different from both. // The object model is not the same, and many of the behaviors are different. // -// In keeping with the license for these other works, the copyrights for +// In keeping with the license for these other works, the copyrights for // jzlib and zlib are here. // // ----------------------------------------------------------------------- // Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. -// +// // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: -// +// // 1. Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in // the documentation and/or other materials provided with the distribution. -// +// // 3. The names of the authors may not be used to endorse or promote products // derived from this software without specific prior written permission. -// +// // THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, @@ -59,7 +59,7 @@ // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, // EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// +// // ----------------------------------------------------------------------- // // This program is based on zlib-1.1.3; credit to authors @@ -79,15 +79,70 @@ namespace SharpCompress.Compressors.Deflate // extra bits for each length code internal static readonly int[] ExtraLengthBits = { - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, - 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 4, + 4, + 4, + 4, + 5, + 5, + 5, + 5, + 0 }; // extra bits for each distance code internal static readonly int[] ExtraDistanceBits = { - 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, - 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13 + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 2, + 3, + 3, + 4, + 4, + 5, + 5, + 6, + 6, + 7, + 7, + 8, + 8, + 9, + 9, + 10, + 10, + 11, + 11, + 12, + 12, + 13, + 13 }; internal enum BlockState @@ -131,7 +186,13 @@ namespace SharpCompress.Compressors.Deflate internal DeflateFlavor Flavor; - private Config(int goodLength, int maxLazy, int niceLength, int maxChainLength, DeflateFlavor flavor) + private Config( + int goodLength, + int maxLazy, + int niceLength, + int maxChainLength, + DeflateFlavor flavor + ) { GoodLength = goodLength; MaxLazy = maxLazy; @@ -148,18 +209,18 @@ namespace SharpCompress.Compressors.Deflate static Config() { Table = new[] - { - new Config(0, 0, 0, 0, DeflateFlavor.Store), - new Config(4, 4, 8, 4, DeflateFlavor.Fast), - new Config(4, 5, 16, 8, DeflateFlavor.Fast), - new Config(4, 6, 32, 32, DeflateFlavor.Fast), - new Config(4, 4, 16, 16, DeflateFlavor.Slow), - new Config(8, 16, 32, 32, DeflateFlavor.Slow), - new Config(8, 16, 128, 128, DeflateFlavor.Slow), - new Config(8, 32, 128, 256, DeflateFlavor.Slow), - new Config(32, 128, 258, 1024, DeflateFlavor.Slow), - new Config(32, 258, 258, 4096, DeflateFlavor.Slow) - }; + { + new Config(0, 0, 0, 0, DeflateFlavor.Store), + new Config(4, 4, 8, 4, DeflateFlavor.Fast), + new Config(4, 5, 16, 8, DeflateFlavor.Fast), + new Config(4, 6, 32, 32, DeflateFlavor.Fast), + new Config(4, 4, 16, 16, DeflateFlavor.Slow), + new Config(8, 16, 32, 32, DeflateFlavor.Slow), + new Config(8, 16, 128, 128, DeflateFlavor.Slow), + new Config(8, 32, 128, 256, DeflateFlavor.Slow), + new Config(32, 128, 258, 1024, DeflateFlavor.Slow), + new Config(32, 258, 258, 4096, DeflateFlavor.Slow) + }; } private static readonly Config[] Table; @@ -231,7 +292,7 @@ namespace SharpCompress.Compressors.Deflate // and move to the first half later to keep a dictionary of at least wSize // bytes. With this organization, matches are limited to a distance of // wSize-MAX_MATCH bytes, but this ensures that IO is always - // performed with a length multiple of the block size. + // performed with a length multiple of the block size. // // To do: use the user input buffer as sliding window. @@ -306,7 +367,7 @@ namespace SharpCompress.Compressors.Deflate // Depth of each subtree used as tie breaker for trees of equal frequency private readonly sbyte[] depth = new sbyte[2 * InternalConstants.L_CODES + 1]; - private int _lengthOffset; // index for literals or lengths + private int _lengthOffset; // index for literals or lengths // Size of match buffer for literals/lengths. There are 4 reasons for // limiting lit_bufsize to 64K: @@ -605,8 +666,7 @@ namespace SharpCompress.Compressors.Deflate do { send_code(curlen, bl_tree); - } - while (--count != 0); + } while (--count != 0); } else if (curlen != 0) { @@ -656,11 +716,12 @@ namespace SharpCompress.Compressors.Deflate pendingCount += len; } -#if NOTNEEDED +#if NOTNEEDED private void put_byte(byte c) { pending[pendingCount++] = c; } + internal void put_short(int b) { unchecked @@ -669,6 +730,7 @@ namespace SharpCompress.Compressors.Deflate pending[pendingCount++] = (byte)(b >> 8); } } + internal void putShortMSB(int b) { unchecked @@ -776,8 +838,9 @@ namespace SharpCompress.Compressors.Deflate int dcode; for (dcode = 0; dcode < InternalConstants.D_CODES; dcode++) { - out_length = - (int)(out_length + dyn_dtree[dcode * 2] * (5L + ExtraDistanceBits[dcode])); + out_length = (int)( + out_length + dyn_dtree[dcode * 2] * (5L + ExtraDistanceBits[dcode]) + ); } out_length >>= 3; if ((matches < (last_lit / 2)) && out_length < in_length / 2) @@ -808,8 +871,7 @@ namespace SharpCompress.Compressors.Deflate do { int ix = _distanceOffset + lx * 2; - distance = ((pending[ix] << 8) & 0xff00) | - (pending[ix + 1] & 0xff); + distance = ((pending[ix] << 8) & 0xff00) | (pending[ix + 1] & 0xff); lc = (pending[_lengthOffset + lx]) & 0xff; lx++; @@ -819,7 +881,7 @@ namespace SharpCompress.Compressors.Deflate } else { - // literal or match pair + // literal or match pair // Here, lc is the match length - MIN_MATCH code = Tree.LengthCode[lc]; @@ -848,8 +910,7 @@ namespace SharpCompress.Compressors.Deflate } // Check that the overlay between pending and d_buf+l_buf is ok: - } - while (lx < last_lit); + } while (lx < last_lit); } send_code(END_BLOCK, ltree); @@ -1037,7 +1098,8 @@ namespace SharpCompress.Compressors.Deflate // trees or store, and output the encoded block to the zip file. internal void _tr_flush_block(int buf, int stored_len, bool eof) { - int opt_lenb, static_lenb; // opt_len and static_len in bytes + int opt_lenb, + static_lenb; // opt_len and static_len in bytes int max_blindex = 0; // index of last bit length code of non zero freq // Build the Huffman trees unless a stored block is forced @@ -1088,12 +1150,19 @@ namespace SharpCompress.Compressors.Deflate else if (static_lenb == opt_lenb) { send_bits((STATIC_TREES << 1) + (eof ? 1 : 0), 3); - send_compressed_block(StaticTree.lengthAndLiteralsTreeCodes, StaticTree.distTreeCodes); + send_compressed_block( + StaticTree.lengthAndLiteralsTreeCodes, + StaticTree.distTreeCodes + ); } else { send_bits((DYN_TREES << 1) + (eof ? 1 : 0), 3); - send_all_trees(treeLiterals.max_code + 1, treeDistances.max_code + 1, max_blindex + 1); + send_all_trees( + treeLiterals.max_code + 1, + treeDistances.max_code + 1, + max_blindex + 1 + ); send_compressed_block(dyn_ltree, dyn_dtree); } @@ -1118,7 +1187,8 @@ namespace SharpCompress.Compressors.Deflate // option -- not supported here). private void _fillWindow() { - int n, m; + int n, + m; int p; int more; // Amount of free space at the end of the window. @@ -1159,8 +1229,7 @@ namespace SharpCompress.Compressors.Deflate { m = (head[--p] & 0xffff); head[p] = (short)((m >= w_size) ? (m - w_size) : 0); - } - while (--n != 0); + } while (--n != 0); n = w_size; p = n; @@ -1171,8 +1240,7 @@ namespace SharpCompress.Compressors.Deflate // If n is not on any hash chain, prev[n] is garbage but // its value will never be used. - } - while (--n != 0); + } while (--n != 0); more += w_size; } @@ -1204,8 +1272,7 @@ namespace SharpCompress.Compressors.Deflate // If the whole input has less than MIN_MATCH bytes, ins_h is garbage, // but this is not important since only literal bytes will be emitted. - } - while (lookahead < MIN_LOOKAHEAD && _codec.AvailableBytesIn != 0); + } while (lookahead < MIN_LOOKAHEAD && _codec.AvailableBytesIn != 0); } // Compress as much as possible from the input stream, return the current @@ -1242,7 +1309,9 @@ namespace SharpCompress.Compressors.Deflate // dictionary, and set hash_head to the head of the hash chain: if (lookahead >= MIN_MATCH) { - ins_h = (((ins_h) << hash_shift) ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff)) & hash_mask; + ins_h = + (((ins_h) << hash_shift) ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff)) + & hash_mask; // prev[strstart&w_mask]=hash_head=head[ins_h]; hash_head = (head[ins_h] & 0xffff); @@ -1282,7 +1351,11 @@ namespace SharpCompress.Compressors.Deflate { strstart++; - ins_h = ((ins_h << hash_shift) ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff)) & hash_mask; + ins_h = + ( + (ins_h << hash_shift) + ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff) + ) & hash_mask; // prev[strstart&w_mask]=hash_head=head[ins_h]; hash_head = (head[ins_h] & 0xffff); @@ -1291,8 +1364,7 @@ namespace SharpCompress.Compressors.Deflate // strstart never exceeds WSIZE-MAX_MATCH, so there are // always MIN_MATCH bytes ahead. - } - while (--match_length != 0); + } while (--match_length != 0); strstart++; } else @@ -1301,7 +1373,8 @@ namespace SharpCompress.Compressors.Deflate match_length = 0; ins_h = window[strstart] & 0xff; - ins_h = (((ins_h) << hash_shift) ^ (window[strstart + 1] & 0xff)) & hash_mask; + ins_h = + (((ins_h) << hash_shift) ^ (window[strstart + 1] & 0xff)) & hash_mask; // If lookahead < MIN_MATCH, ins_h is garbage, but it does not // matter since it will be recomputed at next deflate call. @@ -1373,7 +1446,9 @@ namespace SharpCompress.Compressors.Deflate if (lookahead >= MIN_MATCH) { - ins_h = (((ins_h) << hash_shift) ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff)) & hash_mask; + ins_h = + (((ins_h) << hash_shift) ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff)) + & hash_mask; // prev[strstart&w_mask]=hash_head=head[ins_h]; hash_head = (head[ins_h] & 0xffff); @@ -1386,8 +1461,11 @@ namespace SharpCompress.Compressors.Deflate prev_match = match_start; match_length = MIN_MATCH - 1; - if (hash_head != 0 && prev_length < config.MaxLazy && - ((strstart - hash_head) & 0xffff) <= w_size - MIN_LOOKAHEAD) + if ( + hash_head != 0 + && prev_length < config.MaxLazy + && ((strstart - hash_head) & 0xffff) <= w_size - MIN_LOOKAHEAD + ) { // To simplify the code, we prevent matches with the string // of window index 0 (in particular we have to avoid a match @@ -1400,8 +1478,13 @@ namespace SharpCompress.Compressors.Deflate // longest_match() sets match_start - if (match_length <= 5 && (compressionStrategy == CompressionStrategy.Filtered || - (match_length == MIN_MATCH && strstart - match_start > 4096))) + if ( + match_length <= 5 + && ( + compressionStrategy == CompressionStrategy.Filtered + || (match_length == MIN_MATCH && strstart - match_start > 4096) + ) + ) { // If prev_match is also MIN_MATCH, match_start is garbage // but we will ignore the current match anyway. @@ -1431,16 +1514,18 @@ namespace SharpCompress.Compressors.Deflate { if (++strstart <= max_insert) { - ins_h = (((ins_h) << hash_shift) ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff)) & - hash_mask; + ins_h = + ( + ((ins_h) << hash_shift) + ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff) + ) & hash_mask; //prev[strstart&w_mask]=hash_head=head[ins_h]; hash_head = (head[ins_h] & 0xffff); prev[strstart & w_mask] = head[ins_h]; head[ins_h] = unchecked((short)strstart); } - } - while (--prev_length != 0); + } while (--prev_length != 0); match_available = 0; match_length = MIN_MATCH - 1; strstart++; @@ -1510,7 +1595,8 @@ namespace SharpCompress.Compressors.Deflate int match; // matched string int len; // length of current match int best_len = prev_length; // best match length so far - int limit = strstart > (w_size - MIN_LOOKAHEAD) ? strstart - (w_size - MIN_LOOKAHEAD) : 0; + int limit = + strstart > (w_size - MIN_LOOKAHEAD) ? strstart - (w_size - MIN_LOOKAHEAD) : 0; int niceLength = config.NiceLength; @@ -1545,10 +1631,12 @@ namespace SharpCompress.Compressors.Deflate // Skip to next match if the match length cannot increase // or if the match length is less than 2: - if (window[match + best_len] != scan_end || - window[match + best_len - 1] != scan_end1 || - window[match] != window[scan] || - window[++match] != window[scan + 1]) + if ( + window[match + best_len] != scan_end + || window[match + best_len - 1] != scan_end1 + || window[match] != window[scan] + || window[++match] != window[scan + 1] + ) { continue; } @@ -1563,17 +1651,17 @@ namespace SharpCompress.Compressors.Deflate // We check for insufficient lookahead only every 8th comparison; // the 256th check will be made at strstart+258. - do - { - } - while (window[++scan] == window[++match] && - window[++scan] == window[++match] && - window[++scan] == window[++match] && - window[++scan] == window[++match] && - window[++scan] == window[++match] && - window[++scan] == window[++match] && - window[++scan] == window[++match] && - window[++scan] == window[++match] && scan < strend); + do { } while ( + window[++scan] == window[++match] + && window[++scan] == window[++match] + && window[++scan] == window[++match] + && window[++scan] == window[++match] + && window[++scan] == window[++match] + && window[++scan] == window[++match] + && window[++scan] == window[++match] + && window[++scan] == window[++match] + && scan < strend + ); len = MAX_MATCH - (strend - scan); scan = strend - MAX_MATCH; @@ -1589,8 +1677,9 @@ namespace SharpCompress.Compressors.Deflate scan_end1 = window[scan + best_len - 1]; scan_end = window[scan + best_len]; } - } - while ((cur_match = (prev[cur_match & wmask] & 0xffff)) > limit && --chain_length != 0); + } while ( + (cur_match = (prev[cur_match & wmask] & 0xffff)) > limit && --chain_length != 0 + ); if (best_len <= lookahead) { @@ -1613,14 +1702,23 @@ namespace SharpCompress.Compressors.Deflate return Initialize(codec, level, bits, MEM_LEVEL_DEFAULT, CompressionStrategy.Default); } - internal int Initialize(ZlibCodec codec, CompressionLevel level, int bits, - CompressionStrategy compressionStrategy) + internal int Initialize( + ZlibCodec codec, + CompressionLevel level, + int bits, + CompressionStrategy compressionStrategy + ) { return Initialize(codec, level, bits, MEM_LEVEL_DEFAULT, compressionStrategy); } - internal int Initialize(ZlibCodec codec, CompressionLevel level, int windowBits, int memLevel, - CompressionStrategy strategy) + internal int Initialize( + ZlibCodec codec, + CompressionLevel level, + int windowBits, + int memLevel, + CompressionStrategy strategy + ) { _codec = codec; _codec.Message = null; @@ -1633,7 +1731,9 @@ namespace SharpCompress.Compressors.Deflate if (memLevel < 1 || memLevel > MEM_LEVEL_MAX) { - throw new ZlibException(String.Format("memLevel must be in the range 1.. {0}", MEM_LEVEL_MAX)); + throw new ZlibException( + String.Format("memLevel must be in the range 1.. {0}", MEM_LEVEL_MAX) + ); } _codec.dstate = this; @@ -1655,7 +1755,7 @@ namespace SharpCompress.Compressors.Deflate lit_bufsize = 1 << (memLevel + 6); // Use a single array as the buffer for data pending compression, - // the output distance codes, and the output length codes (aka tree). + // the output distance codes, and the output length codes (aka tree). // orig comment: This works just fine since the average // output size for (length,distance) codes is <= 24 bits. pending = new byte[lit_bufsize * 4]; @@ -1664,7 +1764,7 @@ namespace SharpCompress.Compressors.Deflate // So, for memLevel 8, the length of the pending buffer is 65536. 64k. // The first 16k are pending bytes. - // The middle slice, of 32k, is used for distance codes. + // The middle slice, of 32k, is used for distance codes. // The final 16k are length codes. compressionLevel = level; @@ -1749,7 +1849,7 @@ namespace SharpCompress.Compressors.Deflate SetDeflater(); } - // no need to flush with change in strategy? Really? + // no need to flush with change in strategy? Really? compressionStrategy = strategy; return result; @@ -1789,7 +1889,8 @@ namespace SharpCompress.Compressors.Deflate for (int n = 0; n <= length - MIN_MATCH; n++) { - ins_h = (((ins_h) << hash_shift) ^ (window[(n) + (MIN_MATCH - 1)] & 0xff)) & hash_mask; + ins_h = + (((ins_h) << hash_shift) ^ (window[(n) + (MIN_MATCH - 1)] & 0xff)) & hash_mask; prev[n & w_mask] = head[ins_h]; head[ins_h] = (short)n; } @@ -1800,18 +1901,24 @@ namespace SharpCompress.Compressors.Deflate { int old_flush; - if (_codec.OutputBuffer is null || - (_codec.InputBuffer is null && _codec.AvailableBytesIn != 0) || - (status == FINISH_STATE && flush != FlushType.Finish)) + if ( + _codec.OutputBuffer is null + || (_codec.InputBuffer is null && _codec.AvailableBytesIn != 0) + || (status == FINISH_STATE && flush != FlushType.Finish) + ) { - _codec.Message = _ErrorMessage[ZlibConstants.Z_NEED_DICT - (ZlibConstants.Z_STREAM_ERROR)]; + _codec.Message = _ErrorMessage[ + ZlibConstants.Z_NEED_DICT - (ZlibConstants.Z_STREAM_ERROR) + ]; throw new ZlibException(String.Format("Something is fishy. [{0}]", _codec.Message)); //return ZlibConstants.Z_STREAM_ERROR; } if (_codec.AvailableBytesOut == 0) { - _codec.Message = _ErrorMessage[ZlibConstants.Z_NEED_DICT - (ZlibConstants.Z_BUF_ERROR)]; + _codec.Message = _ErrorMessage[ + ZlibConstants.Z_NEED_DICT - (ZlibConstants.Z_BUF_ERROR) + ]; throw new ZlibException("OutputBuffer is full (AvailableBytesOut == 0)"); //return ZlibConstants.Z_BUF_ERROR; @@ -1838,7 +1945,6 @@ namespace SharpCompress.Compressors.Deflate header += 31 - (header % 31); status = BUSY_STATE; - //putShortMSB(header); unchecked { @@ -1880,9 +1986,9 @@ namespace SharpCompress.Compressors.Deflate // flushes. For repeated and useless calls with Z_FINISH, we keep // returning Z_STREAM_END instead of Z_BUFF_ERROR. } - else if (_codec.AvailableBytesIn == 0 && - (int)flush <= old_flush && - flush != FlushType.Finish) + else if ( + _codec.AvailableBytesIn == 0 && (int)flush <= old_flush && flush != FlushType.Finish + ) { // workitem 8557 // Not sure why this needs to be an error. @@ -1899,12 +2005,18 @@ namespace SharpCompress.Compressors.Deflate // User must not provide more input after the first FINISH: if (status == FINISH_STATE && _codec.AvailableBytesIn != 0) { - _codec.Message = _ErrorMessage[ZlibConstants.Z_NEED_DICT - (ZlibConstants.Z_BUF_ERROR)]; + _codec.Message = _ErrorMessage[ + ZlibConstants.Z_NEED_DICT - (ZlibConstants.Z_BUF_ERROR) + ]; throw new ZlibException("status == FINISH_STATE && _codec.AvailableBytesIn != 0"); } // Start a new block or continue the current one. - if (_codec.AvailableBytesIn != 0 || lookahead != 0 || (flush != FlushType.None && status != FINISH_STATE)) + if ( + _codec.AvailableBytesIn != 0 + || lookahead != 0 + || (flush != FlushType.None && status != FINISH_STATE) + ) { BlockState bstate = DeflateFunction(flush); @@ -1988,4 +2100,4 @@ namespace SharpCompress.Compressors.Deflate return pendingCount != 0 ? ZlibConstants.Z_OK : ZlibConstants.Z_STREAM_END; } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/Deflate/DeflateStream.cs b/src/SharpCompress/Compressors/Deflate/DeflateStream.cs index e3b18f6a..c34b8282 100644 --- a/src/SharpCompress/Compressors/Deflate/DeflateStream.cs +++ b/src/SharpCompress/Compressors/Deflate/DeflateStream.cs @@ -35,11 +35,20 @@ namespace SharpCompress.Compressors.Deflate private readonly ZlibBaseStream _baseStream; private bool _disposed; - public DeflateStream(Stream stream, CompressionMode mode, - CompressionLevel level = CompressionLevel.Default, - Encoding? forceEncoding = null) + public DeflateStream( + Stream stream, + CompressionMode mode, + CompressionLevel level = CompressionLevel.Default, + Encoding? forceEncoding = null + ) { - _baseStream = new ZlibBaseStream(stream, mode, level, ZlibStreamFlavor.DEFLATE, forceEncoding); + _baseStream = new ZlibBaseStream( + stream, + mode, + level, + ZlibStreamFlavor.DEFLATE, + forceEncoding + ); } #region Zlib properties @@ -95,8 +104,12 @@ namespace SharpCompress.Compressors.Deflate if (value < ZlibConstants.WorkingBufferSizeMin) { throw new ZlibException( - String.Format("Don't be silly. {0} bytes?? Use a bigger buffer, at least {1}.", value, - ZlibConstants.WorkingBufferSizeMin)); + String.Format( + "Don't be silly. {0} bytes?? Use a bigger buffer, at least {1}.", + value, + ZlibConstants.WorkingBufferSizeMin + ) + ); } _baseStream._bufferSize = value; } @@ -360,7 +373,11 @@ namespace SharpCompress.Compressors.Deflate #endregion - public MemoryStream InputBuffer => new MemoryStream(_baseStream._z.InputBuffer, _baseStream._z.NextIn, - _baseStream._z.AvailableBytesIn); + public MemoryStream InputBuffer => + new MemoryStream( + _baseStream._z.InputBuffer, + _baseStream._z.NextIn, + _baseStream._z.AvailableBytesIn + ); } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/Deflate/FlushType.cs b/src/SharpCompress/Compressors/Deflate/FlushType.cs index 9a3cc774..1cb4eb06 100644 --- a/src/SharpCompress/Compressors/Deflate/FlushType.cs +++ b/src/SharpCompress/Compressors/Deflate/FlushType.cs @@ -1,7 +1,7 @@ namespace SharpCompress.Compressors.Deflate { /// - /// Describes how to flush the current deflate operation. + /// Describes how to flush the current deflate operation. /// /// /// The different FlushType values are useful when using a Deflate in a streaming application. @@ -14,7 +14,7 @@ /// Closes the current block, but doesn't flush it to /// the output. Used internally only in hypothetical /// scenarios. This was supposed to be removed by Zlib, but it is - /// still in use in some edge cases. + /// still in use in some edge cases. /// Partial, @@ -41,4 +41,4 @@ /// Signals the end of the compression/decompression stream. Finish } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/Deflate/GZipStream.cs b/src/SharpCompress/Compressors/Deflate/GZipStream.cs index ffc4759d..572f677e 100644 --- a/src/SharpCompress/Compressors/Deflate/GZipStream.cs +++ b/src/SharpCompress/Compressors/Deflate/GZipStream.cs @@ -35,7 +35,15 @@ 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 DateTime( + 1970, + 1, + 1, + 0, + 0, + 0, + DateTimeKind.Utc + ); private string? _comment; private string? _fileName; @@ -49,16 +57,17 @@ namespace SharpCompress.Compressors.Deflate private readonly Encoding _encoding; public GZipStream(Stream stream, CompressionMode mode) - : this(stream, mode, CompressionLevel.Default, Encoding.UTF8) - { - } + : this(stream, mode, CompressionLevel.Default, Encoding.UTF8) { } public GZipStream(Stream stream, CompressionMode mode, CompressionLevel level) - : this(stream, mode, level, Encoding.UTF8) - { - } + : this(stream, mode, level, Encoding.UTF8) { } - public GZipStream(Stream stream, CompressionMode mode, CompressionLevel level, Encoding encoding) + public GZipStream( + Stream stream, + CompressionMode mode, + CompressionLevel level, + Encoding encoding + ) { BaseStream = new ZlibBaseStream(stream, mode, level, ZlibStreamFlavor.GZIP, encoding); _encoding = encoding; @@ -95,8 +104,12 @@ namespace SharpCompress.Compressors.Deflate if (value < ZlibConstants.WorkingBufferSizeMin) { throw new ZlibException( - String.Format("Don't be silly. {0} bytes?? Use a bigger buffer, at least {1}.", value, - ZlibConstants.WorkingBufferSizeMin)); + String.Format( + "Don't be silly. {0} bytes?? Use a bigger buffer, at least {1}.", + value, + ZlibConstants.WorkingBufferSizeMin + ) + ); } BaseStream._bufferSize = value; } @@ -184,7 +197,6 @@ namespace SharpCompress.Compressors.Deflate } return 0; } - set => throw new NotSupportedException(); } @@ -358,7 +370,6 @@ namespace SharpCompress.Compressors.Deflate } } - public DateTime? LastModified { get => _lastModified; @@ -407,10 +418,8 @@ namespace SharpCompress.Compressors.Deflate private int EmitHeader() { - byte[]? commentBytes = (Comment is null) ? null - : _encoding.GetBytes(Comment); - byte[]? filenameBytes = (FileName is null) ? null - : _encoding.GetBytes(FileName); + byte[]? commentBytes = (Comment is null) ? null : _encoding.GetBytes(Comment); + byte[]? filenameBytes = (FileName is null) ? null : _encoding.GetBytes(FileName); int cbLength = commentBytes?.Length + 1 ?? 0; int fnLength = filenameBytes?.Length + 1 ?? 0; diff --git a/src/SharpCompress/Compressors/Deflate/InfTree.cs b/src/SharpCompress/Compressors/Deflate/InfTree.cs index ccbc37bc..9d8e4fe6 100644 --- a/src/SharpCompress/Compressors/Deflate/InfTree.cs +++ b/src/SharpCompress/Compressors/Deflate/InfTree.cs @@ -1,45 +1,45 @@ // Inftree.cs // ------------------------------------------------------------------ // -// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation. +// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation. // All rights reserved. // // This code module is part of DotNetZip, a zipfile class library. // // ------------------------------------------------------------------ // -// This code is licensed under the Microsoft Public License. +// This code is licensed under the Microsoft Public License. // See the file License.txt for the license details. // More info on: http://dotnetzip.codeplex.com // // ------------------------------------------------------------------ // -// last saved (in emacs): +// last saved (in emacs): // Time-stamp: <2009-October-28 12:43:54> // // ------------------------------------------------------------------ // // This module defines classes used in decompression. This code is derived -// from the jzlib implementation of zlib. In keeping with the license for jzlib, +// from the jzlib implementation of zlib. In keeping with the license for jzlib, // the copyright to that code is below. // // ------------------------------------------------------------------ -// +// // Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. -// +// // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: -// +// // 1. Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in // the documentation and/or other materials provided with the distribution. -// +// // 3. The names of the authors may not be used to endorse or promote products // derived from this software without specific prior written permission. -// +// // THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, @@ -50,7 +50,7 @@ // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, // EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// +// // ----------------------------------------------------------------------- // // This program is based on zlib-1.1.3; credit to authors @@ -86,135 +86,1750 @@ namespace SharpCompress.Compressors.Deflate //UPGRADE_NOTE: Final was removed from the declaration of 'fixed_tl'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" internal static readonly int[] fixed_tl = { - 96, 7, 256, 0, 8, 80, 0, 8, 16, 84, 8, 115, 82, 7, 31, 0, 8, - 112, 0, 8, 48, 0, 9, 192, 80, 7, 10, 0, 8, 96, 0, 8, 32, 0, 9, - 160, 0, 8, 0, 0, 8, 128, 0, 8, 64, 0, 9, 224, 80, 7, 6, 0, 8, - 88, 0, 8, 24, 0, 9, 144, 83, 7, 59, 0, 8, 120, 0, 8, 56, 0, 9, - 208, 81, 7, 17, 0, 8, 104, 0, 8, 40, 0, 9, 176, 0, 8, 8, 0, 8, - 136, 0, 8, 72, 0, 9, 240, 80, 7, 4, 0, 8, 84, 0, 8, 20, 85, 8, - 227, 83, 7, 43, 0, 8, 116, 0, 8, 52, 0, 9, 200, 81, 7, 13, 0, - 8, 100, 0, 8, 36, 0, 9, 168, 0, 8, 4, 0, 8, 132, 0, 8, 68, 0, - 9, 232, 80, 7, 8, 0, 8, 92, 0, 8, 28, 0, 9, 152, 84, 7, 83, 0, - 8, 124, 0, 8, 60, 0, 9, 216, 82, 7, 23, 0, 8, 108, 0, 8, 44, 0 - , 9, 184, 0, 8, 12, 0, 8, 140, 0, 8, 76, 0, 9, 248, 80, 7, 3, - 0, 8, 82, 0, 8, 18, 85, 8, 163, 83, 7, 35, 0, 8, 114, 0, 8, 50 - , 0, 9, 196, 81, 7, 11, 0, 8, 98, 0, 8, 34, 0, 9, 164, 0, 8, 2 - , 0, 8, 130, 0, 8, 66, 0, 9, 228, 80, 7, 7, 0, 8, 90, 0, 8, 26 - , 0, 9, 148, 84, 7, 67, 0, 8, 122, 0, 8, 58, 0, 9, 212, 82, 7, - 19, 0, 8, 106, 0, 8, 42, 0, 9, 180, 0, 8, 10, 0, 8, 138, 0, 8, - 74, 0, 9, 244, 80, 7, 5, 0, 8, 86, 0, 8, 22, 192, 8, 0, 83, 7, - 51, 0, 8, 118, 0, 8, 54, 0, 9, 204, 81, 7, 15, 0, 8, 102, 0, 8 - , 38, 0, 9, 172, 0, 8, 6, 0, 8, 134, 0, 8, 70, 0, 9, 236, 80, - 7, 9, 0, 8, 94, 0, 8, 30, 0, 9, 156, 84, 7, 99, 0, 8, 126, 0, - 8, 62, 0, 9, 220, 82, 7, 27, 0, 8, 110, 0, 8, 46, 0, 9, 188, 0 - , 8, 14, 0, 8, 142, 0, 8, 78, 0, 9, 252, 96, 7, 256, 0, 8, 81, - 0, 8, 17, 85, 8, 131, 82, 7, 31, 0, 8, 113, 0, 8, 49, 0, 9, - 194, 80, 7, 10, 0, 8, 97, 0, 8, 33, 0, 9, 162, 0, 8, 1, 0, 8, - 129, 0, 8, 65, 0, 9, 226, 80, 7, 6, 0, 8, 89, 0, 8, 25, 0, 9, - 146, 83, 7, 59, 0, 8, 121, 0, 8, 57, 0, 9, 210, 81, 7, 17, 0, - 8, 105, 0, 8, 41, 0, 9, 178, 0, 8, 9, 0, 8, 137, 0, 8, 73, 0, - 9, 242, 80, 7, 4, 0, 8, 85, 0, 8, 21, 80, 8, 258, 83, 7, 43, 0 - , 8, 117, 0, 8, 53, 0, 9, 202, 81, 7, 13, 0, 8, 101, 0, 8, 37, - 0, 9, 170, 0, 8, 5, 0, 8, 133, 0, 8, 69, 0, 9, 234, 80, 7, 8, - 0, 8, 93, 0, 8, 29, 0, 9, 154, 84, 7, 83, 0, 8, 125, 0, 8, 61, - 0, 9, 218, 82, 7, 23, 0, 8, 109, 0, 8, 45, 0, 9, 186, - 0, 8, 13, 0, 8, 141, 0, 8, 77, 0, 9, 250, 80, 7, 3, 0, 8, 83, - 0, 8, 19, 85, 8, 195, 83, 7, 35, 0, 8, 115, 0, 8, 51, 0, 9, - 198, 81, 7, 11, 0, 8, 99, 0, 8, 35, 0, 9, 166, 0, 8, 3, 0, 8, - 131, 0, 8, 67, 0, 9, 230, 80, 7, 7, 0, 8, 91, 0, 8, 27, 0, 9, - 150, 84, 7, 67, 0, 8, 123, 0, 8, 59, 0, 9, 214, 82, 7, 19, 0, - 8, 107, 0, 8, 43, 0, 9, 182, 0, 8, 11, 0, 8, 139, 0, 8, 75, 0, - 9, 246, 80, 7, 5, 0, 8, 87, 0, 8, 23, 192, 8, 0, 83, 7, 51, 0, - 8, 119, 0, 8, 55, 0, 9, 206, 81, 7, 15, 0, 8, 103, 0, 8, 39, 0 - , 9, 174, 0, 8, 7, 0, 8, 135, 0, 8, 71, 0, 9, 238, 80, 7, 9, 0 - , 8, 95, 0, 8, 31, 0, 9, 158, 84, 7, 99, 0, 8, 127, 0, 8, 63, - 0, 9, 222, 82, 7, 27, 0, 8, 111, 0, 8, 47, 0, 9, 190, 0, 8, 15 - , 0, 8, 143, 0, 8, 79, 0, 9, 254, 96, 7, 256, 0, 8, 80, 0, 8, - 16, 84, 8, 115, 82, 7, 31, 0, 8, 112, 0, 8, 48, 0, 9, 193, 80, - 7, 10, 0, 8, 96, 0, 8, 32, 0, 9, 161, 0, 8, 0, 0, 8, 128, 0, 8 - , 64, 0, 9, 225, 80, 7, 6, 0, 8, 88, 0, 8, 24, 0, 9, 145, 83, - 7, 59, 0, 8, 120, 0, 8, 56, 0, 9, 209, 81, 7, 17, 0, 8, 104, 0 - , 8, 40, 0, 9, 177, 0, 8, 8, 0, 8, 136, 0, 8, 72, 0, 9, 241, - 80, 7, 4, 0, 8, 84, 0, 8, 20, 85, 8, 227, 83, 7, 43, 0, 8, 116 - , 0, 8, 52, 0, 9, 201, 81, 7, 13, 0, 8, 100, 0, 8, 36, 0, 9, - 169, 0, 8, 4, 0, 8, 132, 0, 8, 68, 0, 9, 233, 80, 7, 8, 0, 8, - 92, 0, 8, 28, 0, 9, 153, 84, 7, 83, 0, 8, 124, 0, 8, 60, 0, 9, - 217, 82, 7, 23, 0, 8, 108, 0, 8, 44, 0, 9, 185, 0, 8, 12, 0, 8 - , 140, 0, 8, 76, 0, 9, 249, 80, 7, 3, 0, 8, 82, 0, 8, 18, 85, - 8, 163, 83, 7, 35, 0, 8, 114, 0, 8, 50, 0, 9, 197, 81, 7, 11, - 0, 8, 98, 0, 8, 34, 0, 9, 165, 0, 8, 2, 0, 8, 130, 0, 8, 66, 0 - , 9, 229, 80, 7, 7, 0, 8, 90, 0, 8, 26, 0, 9, 149, 84, 7, 67, - 0, 8, 122, 0, 8, 58, 0, 9, 213, 82, 7, 19, 0, 8, 106, 0, 8, 42 - , 0, 9, 181, 0, 8, 10, 0, 8, 138, 0, 8, 74, 0, 9, 245, 80, 7, - 5, 0, 8, 86, 0, 8, 22, 192, 8, 0, 83, 7, 51, 0, 8, 118, 0, 8, - 54, 0, 9, 205, 81, 7, 15, 0, 8, 102, 0, 8, 38, 0, 9, 173, 0, 8 - , 6, 0, 8, 134, 0, 8, 70, 0, 9, 237, 80, 7, 9, 0, 8, 94, 0, 8, - 30, 0, 9, 157, 84, 7, 99, 0, 8, 126, 0, 8, 62, 0, 9, 221, 82, - 7, 27, 0, 8, 110, 0, 8, 46, 0, 9, 189, 0, 8, - 14, 0, 8, 142, 0, 8, 78, 0, 9, 253, 96, 7, 256, 0, 8, 81, 0, 8 - , 17, 85, 8, 131, 82, 7, 31, 0, 8, 113, 0, 8, 49, 0, 9, 195, - 80, 7, 10, 0, 8, 97, 0, 8, 33, 0, 9, 163, 0, 8, 1, 0, 8, 129, - 0, 8, 65, 0, 9, 227, 80, 7, 6, 0, 8, 89, 0, 8, 25, 0, 9, 147, - 83, 7, 59, 0, 8, 121, 0, 8, 57, 0, 9, 211, 81, 7, 17, 0, 8, - 105, 0, 8, 41, 0, 9, 179, 0, 8, 9, 0, 8, 137, 0, 8, 73, 0, 9, - 243, 80, 7, 4, 0, 8, 85, 0, 8, 21, 80, 8, 258, 83, 7, 43, 0, 8 - , 117, 0, 8, 53, 0, 9, 203, 81, 7, 13, 0, 8, 101, 0, 8, 37, 0, - 9, 171, 0, 8, 5, 0, 8, 133, 0, 8, 69, 0, 9, 235, 80, 7, 8, 0, - 8, 93, 0, 8, 29, 0, 9, 155, 84, 7, 83, 0, 8, 125, 0, 8, 61, 0, - 9, 219, 82, 7, 23, 0, 8, 109, 0, 8, 45, 0, 9, 187, 0, 8, 13, 0 - , 8, 141, 0, 8, 77, 0, 9, 251, 80, 7, 3, 0, 8, 83, 0, 8, 19, - 85, 8, 195, 83, 7, 35, 0, 8, 115, 0, 8, 51, 0, 9, 199, 81, 7, - 11, 0, 8, 99, 0, 8, 35, 0, 9, 167, 0, 8, 3, 0, 8, 131, 0, 8, - 67, 0, 9, 231, 80, 7, 7, 0, 8, 91, 0, 8, 27, 0, 9, 151, 84, 7, - 67, 0, 8, 123, 0, 8, 59, 0, 9, 215, 82, 7, 19, 0, 8, 107, 0, 8 - , 43, 0, 9, 183, 0, 8, 11, 0, 8, 139, 0, 8, 75, 0, 9, 247, 80, - 7, 5, 0, 8, 87, 0, 8, 23, 192, 8, 0, 83, 7, 51, 0, 8, 119, 0, - 8, 55, 0, 9, 207, 81, 7, 15, 0, 8, 103, 0, 8, 39, 0, 9, 175, 0 - , 8, 7, 0, 8, 135, 0, 8, 71, 0, 9, 239, 80, 7, 9, 0, 8, 95, 0, - 8, 31, 0, 9, 159, 84, 7, 99, 0, 8, 127, 0, 8, 63, 0, 9, 223, - 82, 7, 27, 0, 8, 111, 0, 8, 47, 0, 9, 191, 0, 8, 15, 0, 8, 143 - , 0, 8, 79, 0, 9, 255 + 96, + 7, + 256, + 0, + 8, + 80, + 0, + 8, + 16, + 84, + 8, + 115, + 82, + 7, + 31, + 0, + 8, + 112, + 0, + 8, + 48, + 0, + 9, + 192, + 80, + 7, + 10, + 0, + 8, + 96, + 0, + 8, + 32, + 0, + 9, + 160, + 0, + 8, + 0, + 0, + 8, + 128, + 0, + 8, + 64, + 0, + 9, + 224, + 80, + 7, + 6, + 0, + 8, + 88, + 0, + 8, + 24, + 0, + 9, + 144, + 83, + 7, + 59, + 0, + 8, + 120, + 0, + 8, + 56, + 0, + 9, + 208, + 81, + 7, + 17, + 0, + 8, + 104, + 0, + 8, + 40, + 0, + 9, + 176, + 0, + 8, + 8, + 0, + 8, + 136, + 0, + 8, + 72, + 0, + 9, + 240, + 80, + 7, + 4, + 0, + 8, + 84, + 0, + 8, + 20, + 85, + 8, + 227, + 83, + 7, + 43, + 0, + 8, + 116, + 0, + 8, + 52, + 0, + 9, + 200, + 81, + 7, + 13, + 0, + 8, + 100, + 0, + 8, + 36, + 0, + 9, + 168, + 0, + 8, + 4, + 0, + 8, + 132, + 0, + 8, + 68, + 0, + 9, + 232, + 80, + 7, + 8, + 0, + 8, + 92, + 0, + 8, + 28, + 0, + 9, + 152, + 84, + 7, + 83, + 0, + 8, + 124, + 0, + 8, + 60, + 0, + 9, + 216, + 82, + 7, + 23, + 0, + 8, + 108, + 0, + 8, + 44, + 0, + 9, + 184, + 0, + 8, + 12, + 0, + 8, + 140, + 0, + 8, + 76, + 0, + 9, + 248, + 80, + 7, + 3, + 0, + 8, + 82, + 0, + 8, + 18, + 85, + 8, + 163, + 83, + 7, + 35, + 0, + 8, + 114, + 0, + 8, + 50, + 0, + 9, + 196, + 81, + 7, + 11, + 0, + 8, + 98, + 0, + 8, + 34, + 0, + 9, + 164, + 0, + 8, + 2, + 0, + 8, + 130, + 0, + 8, + 66, + 0, + 9, + 228, + 80, + 7, + 7, + 0, + 8, + 90, + 0, + 8, + 26, + 0, + 9, + 148, + 84, + 7, + 67, + 0, + 8, + 122, + 0, + 8, + 58, + 0, + 9, + 212, + 82, + 7, + 19, + 0, + 8, + 106, + 0, + 8, + 42, + 0, + 9, + 180, + 0, + 8, + 10, + 0, + 8, + 138, + 0, + 8, + 74, + 0, + 9, + 244, + 80, + 7, + 5, + 0, + 8, + 86, + 0, + 8, + 22, + 192, + 8, + 0, + 83, + 7, + 51, + 0, + 8, + 118, + 0, + 8, + 54, + 0, + 9, + 204, + 81, + 7, + 15, + 0, + 8, + 102, + 0, + 8, + 38, + 0, + 9, + 172, + 0, + 8, + 6, + 0, + 8, + 134, + 0, + 8, + 70, + 0, + 9, + 236, + 80, + 7, + 9, + 0, + 8, + 94, + 0, + 8, + 30, + 0, + 9, + 156, + 84, + 7, + 99, + 0, + 8, + 126, + 0, + 8, + 62, + 0, + 9, + 220, + 82, + 7, + 27, + 0, + 8, + 110, + 0, + 8, + 46, + 0, + 9, + 188, + 0, + 8, + 14, + 0, + 8, + 142, + 0, + 8, + 78, + 0, + 9, + 252, + 96, + 7, + 256, + 0, + 8, + 81, + 0, + 8, + 17, + 85, + 8, + 131, + 82, + 7, + 31, + 0, + 8, + 113, + 0, + 8, + 49, + 0, + 9, + 194, + 80, + 7, + 10, + 0, + 8, + 97, + 0, + 8, + 33, + 0, + 9, + 162, + 0, + 8, + 1, + 0, + 8, + 129, + 0, + 8, + 65, + 0, + 9, + 226, + 80, + 7, + 6, + 0, + 8, + 89, + 0, + 8, + 25, + 0, + 9, + 146, + 83, + 7, + 59, + 0, + 8, + 121, + 0, + 8, + 57, + 0, + 9, + 210, + 81, + 7, + 17, + 0, + 8, + 105, + 0, + 8, + 41, + 0, + 9, + 178, + 0, + 8, + 9, + 0, + 8, + 137, + 0, + 8, + 73, + 0, + 9, + 242, + 80, + 7, + 4, + 0, + 8, + 85, + 0, + 8, + 21, + 80, + 8, + 258, + 83, + 7, + 43, + 0, + 8, + 117, + 0, + 8, + 53, + 0, + 9, + 202, + 81, + 7, + 13, + 0, + 8, + 101, + 0, + 8, + 37, + 0, + 9, + 170, + 0, + 8, + 5, + 0, + 8, + 133, + 0, + 8, + 69, + 0, + 9, + 234, + 80, + 7, + 8, + 0, + 8, + 93, + 0, + 8, + 29, + 0, + 9, + 154, + 84, + 7, + 83, + 0, + 8, + 125, + 0, + 8, + 61, + 0, + 9, + 218, + 82, + 7, + 23, + 0, + 8, + 109, + 0, + 8, + 45, + 0, + 9, + 186, + 0, + 8, + 13, + 0, + 8, + 141, + 0, + 8, + 77, + 0, + 9, + 250, + 80, + 7, + 3, + 0, + 8, + 83, + 0, + 8, + 19, + 85, + 8, + 195, + 83, + 7, + 35, + 0, + 8, + 115, + 0, + 8, + 51, + 0, + 9, + 198, + 81, + 7, + 11, + 0, + 8, + 99, + 0, + 8, + 35, + 0, + 9, + 166, + 0, + 8, + 3, + 0, + 8, + 131, + 0, + 8, + 67, + 0, + 9, + 230, + 80, + 7, + 7, + 0, + 8, + 91, + 0, + 8, + 27, + 0, + 9, + 150, + 84, + 7, + 67, + 0, + 8, + 123, + 0, + 8, + 59, + 0, + 9, + 214, + 82, + 7, + 19, + 0, + 8, + 107, + 0, + 8, + 43, + 0, + 9, + 182, + 0, + 8, + 11, + 0, + 8, + 139, + 0, + 8, + 75, + 0, + 9, + 246, + 80, + 7, + 5, + 0, + 8, + 87, + 0, + 8, + 23, + 192, + 8, + 0, + 83, + 7, + 51, + 0, + 8, + 119, + 0, + 8, + 55, + 0, + 9, + 206, + 81, + 7, + 15, + 0, + 8, + 103, + 0, + 8, + 39, + 0, + 9, + 174, + 0, + 8, + 7, + 0, + 8, + 135, + 0, + 8, + 71, + 0, + 9, + 238, + 80, + 7, + 9, + 0, + 8, + 95, + 0, + 8, + 31, + 0, + 9, + 158, + 84, + 7, + 99, + 0, + 8, + 127, + 0, + 8, + 63, + 0, + 9, + 222, + 82, + 7, + 27, + 0, + 8, + 111, + 0, + 8, + 47, + 0, + 9, + 190, + 0, + 8, + 15, + 0, + 8, + 143, + 0, + 8, + 79, + 0, + 9, + 254, + 96, + 7, + 256, + 0, + 8, + 80, + 0, + 8, + 16, + 84, + 8, + 115, + 82, + 7, + 31, + 0, + 8, + 112, + 0, + 8, + 48, + 0, + 9, + 193, + 80, + 7, + 10, + 0, + 8, + 96, + 0, + 8, + 32, + 0, + 9, + 161, + 0, + 8, + 0, + 0, + 8, + 128, + 0, + 8, + 64, + 0, + 9, + 225, + 80, + 7, + 6, + 0, + 8, + 88, + 0, + 8, + 24, + 0, + 9, + 145, + 83, + 7, + 59, + 0, + 8, + 120, + 0, + 8, + 56, + 0, + 9, + 209, + 81, + 7, + 17, + 0, + 8, + 104, + 0, + 8, + 40, + 0, + 9, + 177, + 0, + 8, + 8, + 0, + 8, + 136, + 0, + 8, + 72, + 0, + 9, + 241, + 80, + 7, + 4, + 0, + 8, + 84, + 0, + 8, + 20, + 85, + 8, + 227, + 83, + 7, + 43, + 0, + 8, + 116, + 0, + 8, + 52, + 0, + 9, + 201, + 81, + 7, + 13, + 0, + 8, + 100, + 0, + 8, + 36, + 0, + 9, + 169, + 0, + 8, + 4, + 0, + 8, + 132, + 0, + 8, + 68, + 0, + 9, + 233, + 80, + 7, + 8, + 0, + 8, + 92, + 0, + 8, + 28, + 0, + 9, + 153, + 84, + 7, + 83, + 0, + 8, + 124, + 0, + 8, + 60, + 0, + 9, + 217, + 82, + 7, + 23, + 0, + 8, + 108, + 0, + 8, + 44, + 0, + 9, + 185, + 0, + 8, + 12, + 0, + 8, + 140, + 0, + 8, + 76, + 0, + 9, + 249, + 80, + 7, + 3, + 0, + 8, + 82, + 0, + 8, + 18, + 85, + 8, + 163, + 83, + 7, + 35, + 0, + 8, + 114, + 0, + 8, + 50, + 0, + 9, + 197, + 81, + 7, + 11, + 0, + 8, + 98, + 0, + 8, + 34, + 0, + 9, + 165, + 0, + 8, + 2, + 0, + 8, + 130, + 0, + 8, + 66, + 0, + 9, + 229, + 80, + 7, + 7, + 0, + 8, + 90, + 0, + 8, + 26, + 0, + 9, + 149, + 84, + 7, + 67, + 0, + 8, + 122, + 0, + 8, + 58, + 0, + 9, + 213, + 82, + 7, + 19, + 0, + 8, + 106, + 0, + 8, + 42, + 0, + 9, + 181, + 0, + 8, + 10, + 0, + 8, + 138, + 0, + 8, + 74, + 0, + 9, + 245, + 80, + 7, + 5, + 0, + 8, + 86, + 0, + 8, + 22, + 192, + 8, + 0, + 83, + 7, + 51, + 0, + 8, + 118, + 0, + 8, + 54, + 0, + 9, + 205, + 81, + 7, + 15, + 0, + 8, + 102, + 0, + 8, + 38, + 0, + 9, + 173, + 0, + 8, + 6, + 0, + 8, + 134, + 0, + 8, + 70, + 0, + 9, + 237, + 80, + 7, + 9, + 0, + 8, + 94, + 0, + 8, + 30, + 0, + 9, + 157, + 84, + 7, + 99, + 0, + 8, + 126, + 0, + 8, + 62, + 0, + 9, + 221, + 82, + 7, + 27, + 0, + 8, + 110, + 0, + 8, + 46, + 0, + 9, + 189, + 0, + 8, + 14, + 0, + 8, + 142, + 0, + 8, + 78, + 0, + 9, + 253, + 96, + 7, + 256, + 0, + 8, + 81, + 0, + 8, + 17, + 85, + 8, + 131, + 82, + 7, + 31, + 0, + 8, + 113, + 0, + 8, + 49, + 0, + 9, + 195, + 80, + 7, + 10, + 0, + 8, + 97, + 0, + 8, + 33, + 0, + 9, + 163, + 0, + 8, + 1, + 0, + 8, + 129, + 0, + 8, + 65, + 0, + 9, + 227, + 80, + 7, + 6, + 0, + 8, + 89, + 0, + 8, + 25, + 0, + 9, + 147, + 83, + 7, + 59, + 0, + 8, + 121, + 0, + 8, + 57, + 0, + 9, + 211, + 81, + 7, + 17, + 0, + 8, + 105, + 0, + 8, + 41, + 0, + 9, + 179, + 0, + 8, + 9, + 0, + 8, + 137, + 0, + 8, + 73, + 0, + 9, + 243, + 80, + 7, + 4, + 0, + 8, + 85, + 0, + 8, + 21, + 80, + 8, + 258, + 83, + 7, + 43, + 0, + 8, + 117, + 0, + 8, + 53, + 0, + 9, + 203, + 81, + 7, + 13, + 0, + 8, + 101, + 0, + 8, + 37, + 0, + 9, + 171, + 0, + 8, + 5, + 0, + 8, + 133, + 0, + 8, + 69, + 0, + 9, + 235, + 80, + 7, + 8, + 0, + 8, + 93, + 0, + 8, + 29, + 0, + 9, + 155, + 84, + 7, + 83, + 0, + 8, + 125, + 0, + 8, + 61, + 0, + 9, + 219, + 82, + 7, + 23, + 0, + 8, + 109, + 0, + 8, + 45, + 0, + 9, + 187, + 0, + 8, + 13, + 0, + 8, + 141, + 0, + 8, + 77, + 0, + 9, + 251, + 80, + 7, + 3, + 0, + 8, + 83, + 0, + 8, + 19, + 85, + 8, + 195, + 83, + 7, + 35, + 0, + 8, + 115, + 0, + 8, + 51, + 0, + 9, + 199, + 81, + 7, + 11, + 0, + 8, + 99, + 0, + 8, + 35, + 0, + 9, + 167, + 0, + 8, + 3, + 0, + 8, + 131, + 0, + 8, + 67, + 0, + 9, + 231, + 80, + 7, + 7, + 0, + 8, + 91, + 0, + 8, + 27, + 0, + 9, + 151, + 84, + 7, + 67, + 0, + 8, + 123, + 0, + 8, + 59, + 0, + 9, + 215, + 82, + 7, + 19, + 0, + 8, + 107, + 0, + 8, + 43, + 0, + 9, + 183, + 0, + 8, + 11, + 0, + 8, + 139, + 0, + 8, + 75, + 0, + 9, + 247, + 80, + 7, + 5, + 0, + 8, + 87, + 0, + 8, + 23, + 192, + 8, + 0, + 83, + 7, + 51, + 0, + 8, + 119, + 0, + 8, + 55, + 0, + 9, + 207, + 81, + 7, + 15, + 0, + 8, + 103, + 0, + 8, + 39, + 0, + 9, + 175, + 0, + 8, + 7, + 0, + 8, + 135, + 0, + 8, + 71, + 0, + 9, + 239, + 80, + 7, + 9, + 0, + 8, + 95, + 0, + 8, + 31, + 0, + 9, + 159, + 84, + 7, + 99, + 0, + 8, + 127, + 0, + 8, + 63, + 0, + 9, + 223, + 82, + 7, + 27, + 0, + 8, + 111, + 0, + 8, + 47, + 0, + 9, + 191, + 0, + 8, + 15, + 0, + 8, + 143, + 0, + 8, + 79, + 0, + 9, + 255 }; //UPGRADE_NOTE: Final was removed from the declaration of 'fixed_td'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" internal static readonly int[] fixed_td = { - 80, 5, 1, 87, 5, 257, 83, 5, 17, 91, 5, 4097, 81, 5, 5, 89, 5, - 1025, 85, 5, 65, 93, 5, 16385, 80, 5, 3, 88, 5, 513, 84, 5, 33 - , - 92, 5, 8193, 82, 5, 9, 90, 5, 2049, 86, 5, 129, 192, 5, 24577, - 80 - , 5, 2, 87, 5, 385, 83, 5, 25, 91, 5, 6145, 81, 5, 7, 89, 5, - 1537 - , 85, 5, 97, 93, 5, 24577, 80, 5, 4, 88, 5, 769, 84, 5, 49, 92 - , 5 - , 12289, 82, 5, 13, 90, 5, 3073, 86, 5, 193, 192, 5, 24577 + 80, + 5, + 1, + 87, + 5, + 257, + 83, + 5, + 17, + 91, + 5, + 4097, + 81, + 5, + 5, + 89, + 5, + 1025, + 85, + 5, + 65, + 93, + 5, + 16385, + 80, + 5, + 3, + 88, + 5, + 513, + 84, + 5, + 33, + 92, + 5, + 8193, + 82, + 5, + 9, + 90, + 5, + 2049, + 86, + 5, + 129, + 192, + 5, + 24577, + 80, + 5, + 2, + 87, + 5, + 385, + 83, + 5, + 25, + 91, + 5, + 6145, + 81, + 5, + 7, + 89, + 5, + 1537, + 85, + 5, + 97, + 93, + 5, + 24577, + 80, + 5, + 4, + 88, + 5, + 769, + 84, + 5, + 49, + 92, + 5, + 12289, + 82, + 5, + 13, + 90, + 5, + 3073, + 86, + 5, + 193, + 192, + 5, + 24577 }; // Tables for deflate from PKZIP's appnote.txt. //UPGRADE_NOTE: Final was removed from the declaration of 'cplens'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" internal static readonly int[] cplens = { - 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, - 51 - , 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 13, + 15, + 17, + 19, + 23, + 27, + 31, + 35, + 43, + 51, + 59, + 67, + 83, + 99, + 115, + 131, + 163, + 195, + 227, + 258, + 0, + 0 }; // see note #13 above about 258 //UPGRADE_NOTE: Final was removed from the declaration of 'cplext'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" internal static readonly int[] cplext = { - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4 - , 4 - , 4, 5, 5, 5, 5, 0, 112, 112 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 4, + 4, + 4, + 4, + 5, + 5, + 5, + 5, + 0, + 112, + 112 }; //UPGRADE_NOTE: Final was removed from the declaration of 'cpdist'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" internal static readonly int[] cpdist = { - 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, - 385 - , 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, + 1, + 2, + 3, + 4, + 5, + 7, + 9, + 13, + 17, + 25, + 33, + 49, + 65, + 97, + 129, + 193, + 257, + 385, + 513, + 769, + 1025, + 1537, + 2049, + 3073, + 4097, + 6145, + 8193, + 12289, 16385, 24577 }; @@ -222,9 +1837,36 @@ namespace SharpCompress.Compressors.Deflate //UPGRADE_NOTE: Final was removed from the declaration of 'cpdext'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" internal static readonly int[] cpdext = { - 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9 - , - 10, 10, 11, 11, 12, 12, 13, 13 + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 2, + 3, + 3, + 4, + 4, + 5, + 5, + 6, + 6, + 7, + 7, + 8, + 8, + 9, + 9, + 10, + 10, + 11, + 11, + 12, + 12, + 13, + 13 }; // If BMAX needs to be larger than 16, then h and x[] should be uLong. @@ -232,11 +1874,22 @@ namespace SharpCompress.Compressors.Deflate internal int[] hn; // hufts used in space internal int[] r; // table entry for structure assignment internal int[] u; // table stack - internal int[] v; // work area for huft_build + internal int[] v; // work area for huft_build internal int[] x; // bit offsets, then code stack - private int huft_build(int[] b, int bindex, int n, int s, int[] d, int[] e, int[] t, int[] m, int[] hp, int[] hn, - int[] v) + private int huft_build( + int[] b, + int bindex, + int n, + int s, + int[] d, + int[] e, + int[] t, + int[] m, + int[] hp, + int[] hn, + int[] v + ) { // Given a list of code lengths and a maximum table size, make a set of // tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR @@ -269,8 +1922,7 @@ namespace SharpCompress.Compressors.Deflate c[b[bindex + p]]++; p++; i--; // assume all entries <= BMAX - } - while (i != 0); + } while (i != 0); if (c[0] == n) { @@ -344,8 +1996,7 @@ namespace SharpCompress.Compressors.Deflate v[x[j]++] = i; } p++; - } - while (++i < n); + } while (++i < n); n = x[g]; // set n to length of v // Generate the Huffman codes and for each, make the table entries @@ -484,8 +2135,17 @@ namespace SharpCompress.Compressors.Deflate return result; } - internal int inflate_trees_dynamic(int nl, int nd, int[] c, int[] bl, int[] bd, int[] tl, int[] td, int[] hp, - ZlibCodec z) + internal int inflate_trees_dynamic( + int nl, + int nd, + int[] c, + int[] bl, + int[] bd, + int[] tl, + int[] td, + int[] hp, + ZlibCodec z + ) { int result; @@ -533,7 +2193,13 @@ namespace SharpCompress.Compressors.Deflate return Z_OK; } - internal static int inflate_trees_fixed(int[] bl, int[] bd, int[][] tl, int[][] td, ZlibCodec z) + internal static int inflate_trees_fixed( + int[] bl, + int[] bd, + int[][] tl, + int[][] td, + ZlibCodec z + ) { bl[0] = fixed_bl; bd[0] = fixed_bd; @@ -575,4 +2241,4 @@ namespace SharpCompress.Compressors.Deflate } } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/Deflate/Inflate.cs b/src/SharpCompress/Compressors/Deflate/Inflate.cs index a0672f28..dcab54e2 100644 --- a/src/SharpCompress/Compressors/Deflate/Inflate.cs +++ b/src/SharpCompress/Compressors/Deflate/Inflate.cs @@ -74,7 +74,28 @@ namespace SharpCompress.Compressors.Deflate private const int MANY = 1440; // Table for deflate from PKZIP's appnote.txt. - internal static readonly int[] border = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; + internal static readonly int[] border = + { + 16, + 17, + 18, + 0, + 8, + 7, + 9, + 6, + 10, + 5, + 11, + 4, + 12, + 3, + 13, + 2, + 14, + 1, + 15 + }; internal ZlibCodec _codec; // pointer back to this zlib stream internal int[] bb = new int[1]; // bit length tree depth @@ -261,9 +282,10 @@ namespace SharpCompress.Compressors.Deflate } left = (b & 0xffff); b = k = 0; // dump bits - mode = left != 0 - ? InflateBlockMode.STORED - : (last != 0 ? InflateBlockMode.DRY : InflateBlockMode.TYPE); + mode = + left != 0 + ? InflateBlockMode.STORED + : (last != 0 ? InflateBlockMode.DRY : InflateBlockMode.TYPE); break; case InflateBlockMode.STORED: @@ -461,7 +483,9 @@ namespace SharpCompress.Compressors.Deflate break; } - int i, j, c; + int i, + j, + c; t = bb[0]; @@ -487,8 +511,12 @@ namespace SharpCompress.Compressors.Deflate k += 8; } - t = hufts[(tb[0] + (b & InternalInflateConstants.InflateMask[t])) * 3 + 1]; - c = hufts[(tb[0] + (b & InternalInflateConstants.InflateMask[t])) * 3 + 2]; + t = hufts[ + (tb[0] + (b & InternalInflateConstants.InflateMask[t])) * 3 + 1 + ]; + c = hufts[ + (tb[0] + (b & InternalInflateConstants.InflateMask[t])) * 3 + 2 + ]; if (c < 16) { @@ -534,7 +562,10 @@ namespace SharpCompress.Compressors.Deflate i = index; t = table; - if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) || (c == 16 && i < 1)) + if ( + i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) + || (c == 16 && i < 1) + ) { blens = null; mode = InflateBlockMode.BAD; @@ -554,13 +585,13 @@ namespace SharpCompress.Compressors.Deflate do { blens[i++] = c; - } - while (--j != 0); + } while (--j != 0); index = i; } } tb[0] = -1; + { var bl = new[] { 9 }; // must be <= 9 for lookahead assumptions var bd = new[] { 6 }; // must be <= 9 for lookahead assumptions @@ -568,8 +599,17 @@ namespace SharpCompress.Compressors.Deflate var td = new int[1]; t = table; - t = inftree.inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f), blens, bl, bd, tl, - td, hufts, _codec); + t = inftree.inflate_trees_dynamic( + 257 + (t & 0x1f), + 1 + ((t >> 5) & 0x1f), + blens, + bl, + bd, + tl, + td, + hufts, + _codec + ); if (t != ZlibConstants.Z_OK) { @@ -741,7 +781,10 @@ namespace SharpCompress.Compressors.Deflate // update check information if (checkfn != null) { - _codec._adler32 = check = Adler32.Calculate(check, window.AsSpan(readAt, nBytes)); + _codec._adler32 = check = Adler32.Calculate( + check, + window.AsSpan(readAt, nBytes) + ); } // copy as far as end of window @@ -793,10 +836,23 @@ namespace SharpCompress.Compressors.Deflate // And'ing with mask[n] masks the lower n bits internal static readonly int[] InflateMask = { - 0x00000000, 0x00000001, 0x00000003, 0x00000007, - 0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f, - 0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff, - 0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff + 0x00000000, + 0x00000001, + 0x00000003, + 0x00000007, + 0x0000000f, + 0x0000001f, + 0x0000003f, + 0x0000007f, + 0x000000ff, + 0x000001ff, + 0x000003ff, + 0x000007ff, + 0x00000fff, + 0x00001fff, + 0x00003fff, + 0x00007fff, + 0x0000ffff }; } @@ -883,7 +939,16 @@ namespace SharpCompress.Compressors.Deflate z.TotalBytesIn += p - z.NextIn; z.NextIn = p; blocks.writeAt = q; - r = InflateFast(lbits, dbits, ltree, ltree_index, dtree, dtree_index, blocks, z); + r = InflateFast( + lbits, + dbits, + ltree, + ltree_index, + dtree, + dtree_index, + blocks, + z + ); p = z.NextIn; n = z.AvailableBytesIn; @@ -917,7 +982,9 @@ namespace SharpCompress.Compressors.Deflate else { // Handling missing trailing bit(s) - var tmp_tindex = (tree_index + (b & InternalInflateConstants.InflateMask[k])) * 3; + var tmp_tindex = + (tree_index + (b & InternalInflateConstants.InflateMask[k])) + * 3; if (k >= tree[tmp_tindex + 1]) { break; @@ -1030,7 +1097,9 @@ namespace SharpCompress.Compressors.Deflate else { // Handling missing trailing bit(s) - var tmp_tindex = (tree_index + (b & InternalInflateConstants.InflateMask[k])) * 3; + var tmp_tindex = + (tree_index + (b & InternalInflateConstants.InflateMask[k])) + * 3; if (k >= tree[tmp_tindex + 1]) { break; @@ -1140,7 +1209,10 @@ namespace SharpCompress.Compressors.Deflate if (q == blocks.end && blocks.readAt != 0) { q = 0; - m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q; + m = + q < blocks.readAt + ? blocks.readAt - q - 1 + : blocks.end - q; } if (m == 0) @@ -1276,8 +1348,16 @@ namespace SharpCompress.Compressors.Deflate // at least ten. The ten bytes are six bytes for the longest length/ // distance pair plus four bytes for overloading the bit buffer. - internal int InflateFast(int bl, int bd, int[] tl, int tl_index, int[] td, int td_index, InflateBlocks s, - ZlibCodec z) + internal int InflateFast( + int bl, + int bd, + int[] tl, + int tl_index, + int[] td, + int td_index, + InflateBlocks s, + ZlibCodec z + ) { int t; // temporary pointer int[] tp; // temporary pointer @@ -1380,7 +1460,9 @@ namespace SharpCompress.Compressors.Deflate k += 8; } - d = tp[tp_index_t_3 + 2] + (b & InternalInflateConstants.InflateMask[e]); + d = + tp[tp_index_t_3 + 2] + + (b & InternalInflateConstants.InflateMask[e]); b >>= e; k -= e; @@ -1413,8 +1495,7 @@ namespace SharpCompress.Compressors.Deflate do { r += s.end; // force pointer in window - } - while (r < 0); // covers invalid distances + } while (r < 0); // covers invalid distances e = s.end - r; if (c > e) { @@ -1425,8 +1506,7 @@ namespace SharpCompress.Compressors.Deflate do { s.window[q++] = s.window[r++]; - } - while (--e != 0); + } while (--e != 0); } else { @@ -1445,8 +1525,7 @@ namespace SharpCompress.Compressors.Deflate do { s.window[q++] = s.window[r++]; - } - while (--c != 0); + } while (--c != 0); } else { @@ -1483,8 +1562,7 @@ namespace SharpCompress.Compressors.Deflate return ZlibConstants.Z_DATA_ERROR; } - } - while (true); + } while (true); break; } @@ -1538,10 +1616,8 @@ namespace SharpCompress.Compressors.Deflate return ZlibConstants.Z_DATA_ERROR; } - } - while (true); - } - while (m >= 258 && n >= 10); + } while (true); + } while (m >= 258 && n >= 10); // not enough input or output--restore pointers and return c = z.AvailableBytesIn - n; @@ -1588,9 +1664,7 @@ namespace SharpCompress.Compressors.Deflate internal int wbits; // log2(window size) (8..15, defaults to 15) - public InflateManager() - { - } + public InflateManager() { } public InflateManager(bool expectRfc1950HeaderBytes) { @@ -1642,9 +1716,7 @@ namespace SharpCompress.Compressors.Deflate } wbits = w; - blocks = new InflateBlocks(codec, - HandleRfc1950HeaderBytes ? this : null, - 1 << w); + blocks = new InflateBlocks(codec, HandleRfc1950HeaderBytes ? this : null, 1 << w); // reset state Reset(); @@ -1683,14 +1755,20 @@ namespace SharpCompress.Compressors.Deflate if (((method = _codec.InputBuffer[_codec.NextIn++]) & 0xf) != Z_DEFLATED) { mode = InflateManagerMode.BAD; - _codec.Message = String.Format("unknown compression method (0x{0:X2})", method); + _codec.Message = String.Format( + "unknown compression method (0x{0:X2})", + method + ); marker = 5; // can't try inflateSync break; } if ((method >> 4) + 8 > wbits) { mode = InflateManagerMode.BAD; - _codec.Message = String.Format("invalid window size ({0})", (method >> 4) + 8); + _codec.Message = String.Format( + "invalid window size ({0})", + (method >> 4) + 8 + ); marker = 5; // can't try inflateSync break; } @@ -1715,9 +1793,10 @@ namespace SharpCompress.Compressors.Deflate break; } - mode = ((b & PRESET_DICT) == 0) - ? InflateManagerMode.BLOCKS - : InflateManagerMode.DICT4; + mode = + ((b & PRESET_DICT) == 0) + ? InflateManagerMode.BLOCKS + : InflateManagerMode.DICT4; break; case InflateManagerMode.DICT4: @@ -1728,7 +1807,9 @@ namespace SharpCompress.Compressors.Deflate r = f; _codec.AvailableBytesIn--; _codec.TotalBytesIn++; - expectedCheck = (uint)((_codec.InputBuffer[_codec.NextIn++] << 24) & 0xff000000); + expectedCheck = (uint)( + (_codec.InputBuffer[_codec.NextIn++] << 24) & 0xff000000 + ); mode = InflateManagerMode.DICT3; break; @@ -1740,7 +1821,9 @@ namespace SharpCompress.Compressors.Deflate r = f; _codec.AvailableBytesIn--; _codec.TotalBytesIn++; - expectedCheck += (uint)((_codec.InputBuffer[_codec.NextIn++] << 16) & 0x00ff0000); + expectedCheck += (uint)( + (_codec.InputBuffer[_codec.NextIn++] << 16) & 0x00ff0000 + ); mode = InflateManagerMode.DICT2; break; @@ -1753,7 +1836,9 @@ namespace SharpCompress.Compressors.Deflate r = f; _codec.AvailableBytesIn--; _codec.TotalBytesIn++; - expectedCheck += (uint)((_codec.InputBuffer[_codec.NextIn++] << 8) & 0x0000ff00); + expectedCheck += (uint)( + (_codec.InputBuffer[_codec.NextIn++] << 8) & 0x0000ff00 + ); mode = InflateManagerMode.DICT1; break; @@ -1813,7 +1898,9 @@ namespace SharpCompress.Compressors.Deflate r = f; _codec.AvailableBytesIn--; _codec.TotalBytesIn++; - expectedCheck = (uint)((_codec.InputBuffer[_codec.NextIn++] << 24) & 0xff000000); + expectedCheck = (uint)( + (_codec.InputBuffer[_codec.NextIn++] << 24) & 0xff000000 + ); mode = InflateManagerMode.CHECK3; break; @@ -1825,7 +1912,9 @@ namespace SharpCompress.Compressors.Deflate r = f; _codec.AvailableBytesIn--; _codec.TotalBytesIn++; - expectedCheck += (uint)((_codec.InputBuffer[_codec.NextIn++] << 16) & 0x00ff0000); + expectedCheck += (uint)( + (_codec.InputBuffer[_codec.NextIn++] << 16) & 0x00ff0000 + ); mode = InflateManagerMode.CHECK2; break; @@ -1837,7 +1926,9 @@ namespace SharpCompress.Compressors.Deflate r = f; _codec.AvailableBytesIn--; _codec.TotalBytesIn++; - expectedCheck += (uint)((_codec.InputBuffer[_codec.NextIn++] << 8) & 0x0000ff00); + expectedCheck += (uint)( + (_codec.InputBuffer[_codec.NextIn++] << 8) & 0x0000ff00 + ); mode = InflateManagerMode.CHECK1; break; @@ -1903,7 +1994,8 @@ namespace SharpCompress.Compressors.Deflate int n; // number of bytes to look at int p; // pointer to bytes int m; // number of marker bytes found in a row - long r, w; // temporaries to save total_in and total_out + long r, + w; // temporaries to save total_in and total_out // set up if (mode != InflateManagerMode.BAD) @@ -1990,4 +2082,4 @@ namespace SharpCompress.Compressors.Deflate #endregion } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/Deflate/Tree.cs b/src/SharpCompress/Compressors/Deflate/Tree.cs index 54c1620e..3804679d 100644 --- a/src/SharpCompress/Compressors/Deflate/Tree.cs +++ b/src/SharpCompress/Compressors/Deflate/Tree.cs @@ -3,20 +3,20 @@ // Tree.cs // ------------------------------------------------------------------ // -// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation. +// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation. // All rights reserved. // // This code module is part of DotNetZip, a zipfile class library. // // ------------------------------------------------------------------ // -// This code is licensed under the Microsoft Public License. +// This code is licensed under the Microsoft Public License. // See the file License.txt for the license details. // More info on: http://dotnetzip.codeplex.com // // ------------------------------------------------------------------ // -// last saved (in emacs): +// last saved (in emacs): // Time-stamp: <2009-October-28 13:29:50> // // ------------------------------------------------------------------ @@ -27,22 +27,22 @@ // code is below. // // ------------------------------------------------------------------ -// +// // Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. -// +// // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: -// +// // 1. Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in // the documentation and/or other materials provided with the distribution. -// +// // 3. The names of the authors may not be used to endorse or promote products // derived from this software without specific prior written permission. -// +// // THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, @@ -53,7 +53,7 @@ // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, // EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// +// // ----------------------------------------------------------------------- // // This program is based on zlib-1.1.3; credit to authors @@ -77,9 +77,25 @@ namespace SharpCompress.Compressors.Deflate internal static readonly sbyte[] bl_order = { - 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, + 16, + 17, + 18, + 0, + 8, + 7, + 9, + 6, + 10, + 5, + 11, + 4, + 12, + 3, + 13, + 2, 14, - 1, 15 + 1, + 15 }; // The lengths of the bit length codes are sent in order of decreasing @@ -91,117 +107,845 @@ namespace SharpCompress.Compressors.Deflate private static readonly sbyte[] _dist_code = { - 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, - 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, - 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, - 0, 0, 16, 17, 18, 18, 19, 19, 20, 20, 20, 20, 21, 21, - 21, 21, - 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, - 23, 23, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, - 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, - 25, 25, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, - 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, - 27, 27, - 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, - 27, 27, - 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, - 28, 28, - 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, - 28, 28, - 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, - 28, 28, - 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, - 28, 28, - 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, - 29, 29, - 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, - 29, 29, - 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, - 29, 29, - 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, - 29, 29 + 0, + 1, + 2, + 3, + 4, + 4, + 5, + 5, + 6, + 6, + 6, + 6, + 7, + 7, + 7, + 7, + 8, + 8, + 8, + 8, + 8, + 8, + 8, + 8, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 10, + 10, + 10, + 10, + 10, + 10, + 10, + 10, + 10, + 10, + 10, + 10, + 10, + 10, + 10, + 10, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 0, + 0, + 16, + 17, + 18, + 18, + 19, + 19, + 20, + 20, + 20, + 20, + 21, + 21, + 21, + 21, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29 }; internal static readonly sbyte[] LengthCode = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, - 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15 - , 15, 15, - 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17 - , 17, 17, - 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19 - , 19, 19, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20 - , 20, 20, - 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21 - , 21, 21, - 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22 - , 22, 22, - 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23 - , 23, 23, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24 - , 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24 - , 24, 24, - 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25 - , 25, 25, - 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25 - , 25, 25, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26 - , 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26 - , 26, 26, - 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27 - , 27, 27, - 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27 - , 27, 28 + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 8, + 9, + 9, + 10, + 10, + 11, + 11, + 12, + 12, + 12, + 12, + 13, + 13, + 13, + 13, + 14, + 14, + 14, + 14, + 15, + 15, + 15, + 15, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 17, + 17, + 17, + 17, + 17, + 17, + 17, + 17, + 18, + 18, + 18, + 18, + 18, + 18, + 18, + 18, + 19, + 19, + 19, + 19, + 19, + 19, + 19, + 19, + 20, + 20, + 20, + 20, + 20, + 20, + 20, + 20, + 20, + 20, + 20, + 20, + 20, + 20, + 20, + 20, + 21, + 21, + 21, + 21, + 21, + 21, + 21, + 21, + 21, + 21, + 21, + 21, + 21, + 21, + 21, + 21, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 28 }; internal static readonly int[] LengthBase = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, - 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 0 + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 10, + 12, + 14, + 16, + 20, + 24, + 28, + 32, + 40, + 48, + 56, + 64, + 80, + 96, + 112, + 128, + 160, + 192, + 224, + 0 }; internal static readonly int[] DistanceBase = { - 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, + 0, + 1, + 2, + 3, + 4, + 6, + 8, + 12, + 16, + 24, + 32, + 48, + 64, + 96, + 128, 192, - 256, 384, 512, 768, 1024, 1536, 2048, 3072, 4096, 6144 - , 8192, 12288, 16384, 24576 + 256, + 384, + 512, + 768, + 1024, + 1536, + 2048, + 3072, + 4096, + 6144, + 8192, + 12288, + 16384, + 24576 }; internal short[] dyn_tree; // the dynamic tree @@ -211,14 +955,14 @@ namespace SharpCompress.Compressors.Deflate /// /// Map from a distance to a distance code. /// - /// + /// /// No side effects. _dist_code[256] and _dist_code[257] are never used. /// internal static int DistanceCode(int dist) { return (dist < 256) - ? _dist_code[dist] - : _dist_code[256 + SharedUtils.URShift(dist, 7)]; + ? _dist_code[dist] + : _dist_code[256 + SharedUtils.URShift(dist, 7)]; } // Compute the optimal bit lengths for a tree and update the total bit length @@ -237,7 +981,8 @@ namespace SharpCompress.Compressors.Deflate int base_Renamed = staticTree.extraBase; int max_length = staticTree.maxLength; int h; // heap index - int n, m; // iterate over the tree elements + int n, + m; // iterate over the tree elements int bits; // bit length int xbits; // extra bits short f; // frequency @@ -304,8 +1049,7 @@ namespace SharpCompress.Compressors.Deflate // The brother of the overflow item also moves one step up, // but this does not affect bl_count[max_length] overflow -= 2; - } - while (overflow > 0); + } while (overflow > 0); for (bits = max_length; bits != 0; bits--) { @@ -319,7 +1063,9 @@ namespace SharpCompress.Compressors.Deflate } if (tree[m * 2 + 1] != bits) { - s.opt_len = (int)(s.opt_len + (bits - (long)tree[m * 2 + 1]) * tree[m * 2]); + s.opt_len = (int)( + s.opt_len + (bits - (long)tree[m * 2 + 1]) * tree[m * 2] + ); tree[m * 2 + 1] = (short)bits; } n--; @@ -338,7 +1084,8 @@ namespace SharpCompress.Compressors.Deflate short[] tree = dyn_tree; short[] stree = staticTree.treeCodes; int elems = staticTree.elems; - int n, m; // iterate over heap elements + int n, + m; // iterate over heap elements int max_code = -1; // largest code with non zero frequency int node; // new node being created @@ -411,8 +1158,7 @@ namespace SharpCompress.Compressors.Deflate // and insert the new node in the heap s.heap[1] = node++; s.pqdownheap(tree, 1); - } - while (s.heap_len >= 2); + } while (s.heap_len >= 2); s.heap[--s.heap_max] = s.heap[1]; @@ -478,12 +1224,11 @@ namespace SharpCompress.Compressors.Deflate res |= code & 1; code >>= 1; //SharedUtils.URShift(code, 1); res <<= 1; - } - while (--len > 0); + } while (--len > 0); return res >> 1; } } #endregion } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/Deflate/Zlib.cs b/src/SharpCompress/Compressors/Deflate/Zlib.cs index 036d65f5..b8cab22c 100644 --- a/src/SharpCompress/Compressors/Deflate/Zlib.cs +++ b/src/SharpCompress/Compressors/Deflate/Zlib.cs @@ -183,18 +183,13 @@ namespace SharpCompress.Compressors.Deflate /// The ZlibException class captures exception information generated /// by the Zlib library. /// - public ZlibException() - { - } + public ZlibException() { } /// /// This ctor collects a message attached to the exception. /// /// - public ZlibException(String s) - : base(s) - { - } + public ZlibException(String s) : base(s) { } } internal class SharedUtils @@ -212,15 +207,15 @@ namespace SharpCompress.Compressors.Deflate #if NOT -/// -/// Performs an unsigned bitwise right shift with the specified number -/// -/// Number to operate on -/// Ammount of bits to shift -/// The resulting number from the shift operation + /// + /// Performs an unsigned bitwise right shift with the specified number + /// + /// Number to operate on + /// Ammount of bits to shift + /// The resulting number from the shift operation public static long URShift(long number, int bits) { - return (long) ((UInt64)number >> bits); + return (long)((UInt64)number >> bits); } #endif @@ -239,7 +234,12 @@ namespace SharpCompress.Compressors.Deflate /// count depending on the data available in the source TextReader. Returns -1 /// if the end of the stream is reached. /// - public static Int32 ReadInput(TextReader sourceTextReader, byte[] target, int start, int count) + public static Int32 ReadInput( + TextReader sourceTextReader, + byte[] target, + int start, + int count + ) { // Returns 0 bytes if not enough space in target if (target.Length == 0) @@ -291,90 +291,671 @@ namespace SharpCompress.Compressors.Deflate { internal static readonly short[] lengthAndLiteralsTreeCodes = { - 12, 8, 140, 8, 76, 8, 204, 8, 44, 8, 172, - 8, 108, 8, 236, 8, - 28, 8, 156, 8, 92, 8, 220, 8, 60, 8, 188, - 8, 124, 8, 252, 8, - 2, 8, 130, 8, 66, 8, 194, 8, 34, 8, 162, 8 - , 98, 8, 226, 8, - 18, 8, 146, 8, 82, 8, 210, 8, 50, 8, 178, - 8, 114, 8, 242, 8, - 10, 8, 138, 8, 74, 8, 202, 8, 42, 8, 170, - 8, 106, 8, 234, 8, - 26, 8, 154, 8, 90, 8, 218, 8, 58, 8, 186, - 8, 122, 8, 250, 8, - 6, 8, 134, 8, 70, 8, 198, 8, 38, 8, 166, 8 - , 102, 8, 230, 8, - 22, 8, 150, 8, 86, 8, 214, 8, 54, 8, 182, - 8, 118, 8, 246, 8, - 14, 8, 142, 8, 78, 8, 206, 8, 46, 8, 174, - 8, 110, 8, 238, 8, - 30, 8, 158, 8, 94, 8, 222, 8, 62, 8, 190, - 8, 126, 8, 254, 8, - 1, 8, 129, 8, 65, 8, 193, 8, 33, 8, 161, 8 - , 97, 8, 225, 8, - 17, 8, 145, 8, 81, 8, 209, 8, 49, 8, 177, - 8, 113, 8, 241, 8, - 9, 8, 137, 8, 73, 8, 201, 8, 41, 8, 169, 8 - , 105, 8, 233, 8, - 25, 8, 153, 8, 89, 8, 217, 8, 57, 8, 185, - 8, 121, 8, 249, 8, - 5, 8, 133, 8, 69, 8, 197, 8, 37, 8, 165, 8 - , 101, 8, 229, 8, - 21, 8, 149, 8, 85, 8, 213, 8, 53, 8, 181, - 8, 117, 8, 245, 8, - 13, 8, 141, 8, 77, 8, 205, 8, 45, 8, 173, - 8, 109, 8, 237, 8, - 29, 8, 157, 8, 93, 8, 221, 8, 61, 8, 189, - 8, 125, 8, 253, 8, - 19, 9, 275, 9, 147, 9, 403, 9, 83, 9, 339, - 9, 211, 9, 467, 9, - 51, 9, 307, 9, 179, 9, 435, 9, 115, 9, 371 - , 9, 243, 9, 499, 9, - 11, 9, 267, 9, 139, 9, 395, 9, 75, 9, 331, - 9, 203, 9, 459, 9, - 43, 9, 299, 9, 171, 9, 427, 9, 107, 9, 363 - , 9, 235, 9, 491, 9, - 27, 9, 283, 9, 155, 9, 411, 9, 91, 9, 347, - 9, 219, 9, 475, 9, - 59, 9, 315, 9, 187, 9, 443, 9, 123, 9, 379 - , 9, 251, 9, 507, 9, - 7, 9, 263, 9, 135, 9, 391, 9, 71, 9, 327, - 9, 199, 9, 455, 9, - 39, 9, 295, 9, 167, 9, 423, 9, 103, 9, 359 - , 9, 231, 9, 487, 9, - 23, 9, 279, 9, 151, 9, 407, 9, 87, 9, 343, - 9, 215, 9, 471, 9, - 55, 9, 311, 9, 183, 9, 439, 9, 119, 9, 375 - , 9, 247, 9, 503, 9, - 15, 9, 271, 9, 143, 9, 399, 9, 79, 9, 335, - 9, 207, 9, 463, 9, - 47, 9, 303, 9, 175, 9, 431, 9, 111, 9, 367 - , 9, 239, 9, 495, 9, - 31, 9, 287, 9, 159, 9, 415, 9, 95, 9, 351, - 9, 223, 9, 479, 9, - 63, 9, 319, 9, 191, 9, 447, 9, 127, 9, 383 - , 9, 255, 9, 511, 9, - 0, 7, 64, 7, 32, 7, 96, 7, 16, 7, 80, 7, - 48, 7, 112, 7, - 8, 7, 72, 7, 40, 7, 104, 7, 24, 7, 88, 7, - 56, 7, 120, 7, - 4, 7, 68, 7, 36, 7, 100, 7, 20, 7, 84, 7, - 52, 7, 116, 7, - 3, 8, 131, 8, 67, 8, 195, 8, 35, 8, 163, 8 - , 99, 8, 227, 8 + 12, + 8, + 140, + 8, + 76, + 8, + 204, + 8, + 44, + 8, + 172, + 8, + 108, + 8, + 236, + 8, + 28, + 8, + 156, + 8, + 92, + 8, + 220, + 8, + 60, + 8, + 188, + 8, + 124, + 8, + 252, + 8, + 2, + 8, + 130, + 8, + 66, + 8, + 194, + 8, + 34, + 8, + 162, + 8, + 98, + 8, + 226, + 8, + 18, + 8, + 146, + 8, + 82, + 8, + 210, + 8, + 50, + 8, + 178, + 8, + 114, + 8, + 242, + 8, + 10, + 8, + 138, + 8, + 74, + 8, + 202, + 8, + 42, + 8, + 170, + 8, + 106, + 8, + 234, + 8, + 26, + 8, + 154, + 8, + 90, + 8, + 218, + 8, + 58, + 8, + 186, + 8, + 122, + 8, + 250, + 8, + 6, + 8, + 134, + 8, + 70, + 8, + 198, + 8, + 38, + 8, + 166, + 8, + 102, + 8, + 230, + 8, + 22, + 8, + 150, + 8, + 86, + 8, + 214, + 8, + 54, + 8, + 182, + 8, + 118, + 8, + 246, + 8, + 14, + 8, + 142, + 8, + 78, + 8, + 206, + 8, + 46, + 8, + 174, + 8, + 110, + 8, + 238, + 8, + 30, + 8, + 158, + 8, + 94, + 8, + 222, + 8, + 62, + 8, + 190, + 8, + 126, + 8, + 254, + 8, + 1, + 8, + 129, + 8, + 65, + 8, + 193, + 8, + 33, + 8, + 161, + 8, + 97, + 8, + 225, + 8, + 17, + 8, + 145, + 8, + 81, + 8, + 209, + 8, + 49, + 8, + 177, + 8, + 113, + 8, + 241, + 8, + 9, + 8, + 137, + 8, + 73, + 8, + 201, + 8, + 41, + 8, + 169, + 8, + 105, + 8, + 233, + 8, + 25, + 8, + 153, + 8, + 89, + 8, + 217, + 8, + 57, + 8, + 185, + 8, + 121, + 8, + 249, + 8, + 5, + 8, + 133, + 8, + 69, + 8, + 197, + 8, + 37, + 8, + 165, + 8, + 101, + 8, + 229, + 8, + 21, + 8, + 149, + 8, + 85, + 8, + 213, + 8, + 53, + 8, + 181, + 8, + 117, + 8, + 245, + 8, + 13, + 8, + 141, + 8, + 77, + 8, + 205, + 8, + 45, + 8, + 173, + 8, + 109, + 8, + 237, + 8, + 29, + 8, + 157, + 8, + 93, + 8, + 221, + 8, + 61, + 8, + 189, + 8, + 125, + 8, + 253, + 8, + 19, + 9, + 275, + 9, + 147, + 9, + 403, + 9, + 83, + 9, + 339, + 9, + 211, + 9, + 467, + 9, + 51, + 9, + 307, + 9, + 179, + 9, + 435, + 9, + 115, + 9, + 371, + 9, + 243, + 9, + 499, + 9, + 11, + 9, + 267, + 9, + 139, + 9, + 395, + 9, + 75, + 9, + 331, + 9, + 203, + 9, + 459, + 9, + 43, + 9, + 299, + 9, + 171, + 9, + 427, + 9, + 107, + 9, + 363, + 9, + 235, + 9, + 491, + 9, + 27, + 9, + 283, + 9, + 155, + 9, + 411, + 9, + 91, + 9, + 347, + 9, + 219, + 9, + 475, + 9, + 59, + 9, + 315, + 9, + 187, + 9, + 443, + 9, + 123, + 9, + 379, + 9, + 251, + 9, + 507, + 9, + 7, + 9, + 263, + 9, + 135, + 9, + 391, + 9, + 71, + 9, + 327, + 9, + 199, + 9, + 455, + 9, + 39, + 9, + 295, + 9, + 167, + 9, + 423, + 9, + 103, + 9, + 359, + 9, + 231, + 9, + 487, + 9, + 23, + 9, + 279, + 9, + 151, + 9, + 407, + 9, + 87, + 9, + 343, + 9, + 215, + 9, + 471, + 9, + 55, + 9, + 311, + 9, + 183, + 9, + 439, + 9, + 119, + 9, + 375, + 9, + 247, + 9, + 503, + 9, + 15, + 9, + 271, + 9, + 143, + 9, + 399, + 9, + 79, + 9, + 335, + 9, + 207, + 9, + 463, + 9, + 47, + 9, + 303, + 9, + 175, + 9, + 431, + 9, + 111, + 9, + 367, + 9, + 239, + 9, + 495, + 9, + 31, + 9, + 287, + 9, + 159, + 9, + 415, + 9, + 95, + 9, + 351, + 9, + 223, + 9, + 479, + 9, + 63, + 9, + 319, + 9, + 191, + 9, + 447, + 9, + 127, + 9, + 383, + 9, + 255, + 9, + 511, + 9, + 0, + 7, + 64, + 7, + 32, + 7, + 96, + 7, + 16, + 7, + 80, + 7, + 48, + 7, + 112, + 7, + 8, + 7, + 72, + 7, + 40, + 7, + 104, + 7, + 24, + 7, + 88, + 7, + 56, + 7, + 120, + 7, + 4, + 7, + 68, + 7, + 36, + 7, + 100, + 7, + 20, + 7, + 84, + 7, + 52, + 7, + 116, + 7, + 3, + 8, + 131, + 8, + 67, + 8, + 195, + 8, + 35, + 8, + 163, + 8, + 99, + 8, + 227, + 8 }; internal static readonly short[] distTreeCodes = { - 0, 5, 16, 5, 8, 5, 24, 5, 4, 5, 20, 5, 12, 5, 28, 5, - 2, 5, 18, 5, 10, 5, 26, 5, 6, 5, 22, 5, 14, 5, 30, 5, - 1, 5, 17, 5, 9, 5, 25, 5, 5, 5, 21, 5, 13, 5, 29, 5, - 3, 5, 19, 5, 11, 5, 27, 5, 7, 5, 23, 5 + 0, + 5, + 16, + 5, + 8, + 5, + 24, + 5, + 4, + 5, + 20, + 5, + 12, + 5, + 28, + 5, + 2, + 5, + 18, + 5, + 10, + 5, + 26, + 5, + 6, + 5, + 22, + 5, + 14, + 5, + 30, + 5, + 1, + 5, + 17, + 5, + 9, + 5, + 25, + 5, + 5, + 5, + 21, + 5, + 13, + 5, + 29, + 5, + 3, + 5, + 19, + 5, + 11, + 5, + 27, + 5, + 7, + 5, + 23, + 5 }; // extra bits for each bit length code - internal static readonly int[] extra_blbits = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7 }; + internal static readonly int[] extra_blbits = + { + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 3, + 7 + }; internal static readonly StaticTree Literals; internal static readonly StaticTree Distances; @@ -386,7 +967,13 @@ namespace SharpCompress.Compressors.Deflate internal int elems; // max number of elements in the tree internal int maxLength; // max bit length for the codes - private StaticTree(short[]? treeCodes, int[]? extraBits, int extraBase, int elems, int maxLength) + private StaticTree( + short[]? treeCodes, + int[]? extraBits, + int extraBase, + int elems, + int maxLength + ) { this.treeCodes = treeCodes; this.extraBits = extraBits; @@ -397,12 +984,27 @@ namespace SharpCompress.Compressors.Deflate static StaticTree() { - Literals = new StaticTree(lengthAndLiteralsTreeCodes, DeflateManager.ExtraLengthBits, - InternalConstants.LITERALS + 1, InternalConstants.L_CODES, - InternalConstants.MAX_BITS); - Distances = new StaticTree(distTreeCodes, DeflateManager.ExtraDistanceBits, 0, InternalConstants.D_CODES, - InternalConstants.MAX_BITS); - BitLengths = new StaticTree(null, extra_blbits, 0, InternalConstants.BL_CODES, InternalConstants.MAX_BL_BITS); + Literals = new StaticTree( + lengthAndLiteralsTreeCodes, + DeflateManager.ExtraLengthBits, + InternalConstants.LITERALS + 1, + InternalConstants.L_CODES, + InternalConstants.MAX_BITS + ); + Distances = new StaticTree( + distTreeCodes, + DeflateManager.ExtraDistanceBits, + 0, + InternalConstants.D_CODES, + InternalConstants.MAX_BITS + ); + BitLengths = new StaticTree( + null, + extra_blbits, + 0, + InternalConstants.BL_CODES, + InternalConstants.MAX_BL_BITS + ); } } } diff --git a/src/SharpCompress/Compressors/Deflate/ZlibBaseStream.cs b/src/SharpCompress/Compressors/Deflate/ZlibBaseStream.cs index 45d5dfac..a3a5eae5 100644 --- a/src/SharpCompress/Compressors/Deflate/ZlibBaseStream.cs +++ b/src/SharpCompress/Compressors/Deflate/ZlibBaseStream.cs @@ -69,11 +69,13 @@ namespace SharpCompress.Compressors.Deflate internal int Crc32 => crc?.Crc32Result ?? 0; - public ZlibBaseStream(Stream stream, - CompressionMode compressionMode, - CompressionLevel level, - ZlibStreamFlavor flavor, - Encoding encoding) + public ZlibBaseStream( + Stream stream, + CompressionMode compressionMode, + CompressionLevel level, + ZlibStreamFlavor flavor, + Encoding encoding + ) { _flushMode = FlushType.None; @@ -154,12 +156,12 @@ namespace SharpCompress.Compressors.Deflate _z.OutputBuffer = workingBuffer; _z.NextOut = 0; _z.AvailableBytesOut = _workingBuffer.Length; - int rc = (_wantCompress) - ? _z.Deflate(_flushMode) - : _z.Inflate(_flushMode); + int 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); + throw new ZlibException( + (_wantCompress ? "de" : "in") + "flating: " + _z.Message + ); } //if (_workingBuffer.Length - _z.AvailableBytesOut > 0) @@ -172,8 +174,7 @@ namespace SharpCompress.Compressors.Deflate { done = (_z.AvailableBytesIn == 8 && _z.AvailableBytesOut != 0); } - } - while (!done); + } while (!done); } private void finish() @@ -191,9 +192,10 @@ namespace SharpCompress.Compressors.Deflate _z.OutputBuffer = workingBuffer; _z.NextOut = 0; _z.AvailableBytesOut = _workingBuffer.Length; - int rc = (_wantCompress) - ? _z.Deflate(FlushType.Finish) - : _z.Inflate(FlushType.Finish); + int rc = + (_wantCompress) + ? _z.Deflate(FlushType.Finish) + : _z.Inflate(FlushType.Finish); if (rc != ZlibConstants.Z_STREAM_END && rc != ZlibConstants.Z_OK) { @@ -207,7 +209,11 @@ namespace SharpCompress.Compressors.Deflate if (_workingBuffer.Length - _z.AvailableBytesOut > 0) { - _stream.Write(_workingBuffer, 0, _workingBuffer.Length - _z.AvailableBytesOut); + _stream.Write( + _workingBuffer, + 0, + _workingBuffer.Length - _z.AvailableBytesOut + ); } done = _z.AvailableBytesIn == 0 && _z.AvailableBytesOut != 0; @@ -217,8 +223,7 @@ namespace SharpCompress.Compressors.Deflate { done = (_z.AvailableBytesIn == 8 && _z.AvailableBytesOut != 0); } - } - while (!done); + } while (!done); Flush(); @@ -241,7 +246,6 @@ namespace SharpCompress.Compressors.Deflate } } } - // workitem 7159 else if (_streamMode == StreamMode.Reader) { @@ -264,12 +268,17 @@ namespace SharpCompress.Compressors.Deflate // 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(trailer.Slice(_z.AvailableBytesIn, bytesNeeded)); + int bytesRead = _stream.Read( + trailer.Slice(_z.AvailableBytesIn, bytesNeeded) + ); if (bytesNeeded != bytesRead) { - throw new ZlibException(String.Format( - "Protocol error. AvailableBytesIn={0}, expected 8", - _z.AvailableBytesIn + bytesRead)); + throw new ZlibException( + String.Format( + "Protocol error. AvailableBytesIn={0}, expected 8", + _z.AvailableBytesIn + bytesRead + ) + ); } } else @@ -279,21 +288,31 @@ namespace SharpCompress.Compressors.Deflate Int32 crc32_expected = BinaryPrimitives.ReadInt32LittleEndian(trailer); Int32 crc32_actual = crc.Crc32Result; - Int32 isize_expected = BinaryPrimitives.ReadInt32LittleEndian(trailer.Slice(4)); + Int32 isize_expected = BinaryPrimitives.ReadInt32LittleEndian( + trailer.Slice(4) + ); Int32 isize_actual = (Int32)(_z.TotalBytesOut & 0x00000000FFFFFFFF); if (crc32_actual != crc32_expected) { throw new ZlibException( - String.Format("Bad CRC32 in GZIP stream. (actual({0:X8})!=expected({1:X8}))", - crc32_actual, crc32_expected)); + String.Format( + "Bad CRC32 in GZIP stream. (actual({0:X8})!=expected({1:X8}))", + crc32_actual, + crc32_expected + ) + ); } if (isize_actual != isize_expected) { throw new ZlibException( - String.Format("Bad size in GZIP stream. (actual({0})!=expected({1}))", isize_actual, - isize_expected)); + String.Format( + "Bad size in GZIP stream. (actual({0})!=expected({1}))", + isize_actual, + isize_expected + ) + ); } } else @@ -371,8 +390,8 @@ namespace SharpCompress.Compressors.Deflate if (Read(_buf1, 0, 1) == 0) return 0; // calculate CRC after reading - if (crc!=null) - crc.SlurpBlock(_buf1,0,1); + if (crc != null) + crc.SlurpBlock(_buf1, 0, 1); return (_buf1[0] & 0xFF); } #endif @@ -400,8 +419,7 @@ namespace SharpCompress.Compressors.Deflate { list.Add(_buf1[0]); } - } - while (!done); + } while (!done); byte[] buffer = list.ToArray(); return _encoding.GetString(buffer, 0, buffer.Length); } @@ -521,7 +539,9 @@ namespace SharpCompress.Compressors.Deflate if (rc != ZlibConstants.Z_OK && rc != ZlibConstants.Z_STREAM_END) { - throw new ZlibException(String.Format("Deflating: rc={0} msg={1}", rc, _z.Message)); + throw new ZlibException( + String.Format("Deflating: rc={0} msg={1}", rc, _z.Message) + ); } rc = (count - _z.AvailableBytesOut); @@ -571,9 +591,7 @@ namespace SharpCompress.Compressors.Deflate } // we have data in InputBuffer; now compress or decompress as appropriate - rc = (_wantCompress) - ? _z.Deflate(_flushMode) - : _z.Inflate(_flushMode); + rc = (_wantCompress) ? _z.Deflate(_flushMode) : _z.Inflate(_flushMode); if (nomoreinput && (rc == ZlibConstants.Z_BUF_ERROR)) { @@ -582,11 +600,20 @@ namespace SharpCompress.Compressors.Deflate if (rc != ZlibConstants.Z_OK && rc != ZlibConstants.Z_STREAM_END) { - throw new ZlibException(String.Format("{0}flating: rc={1} msg={2}", (_wantCompress ? "de" : "in"), - rc, _z.Message)); + throw new ZlibException( + String.Format( + "{0}flating: rc={1} msg={2}", + (_wantCompress ? "de" : "in"), + rc, + _z.Message + ) + ); } - if ((nomoreinput || rc == ZlibConstants.Z_STREAM_END) && (_z.AvailableBytesOut == count)) + if ( + (nomoreinput || rc == ZlibConstants.Z_STREAM_END) + && (_z.AvailableBytesOut == count) + ) { break; // nothing more to read } @@ -614,7 +641,9 @@ namespace SharpCompress.Compressors.Deflate if (rc != ZlibConstants.Z_OK && rc != ZlibConstants.Z_STREAM_END) { - throw new ZlibException(String.Format("Deflating: rc={0} msg={1}", rc, _z.Message)); + throw new ZlibException( + String.Format("Deflating: rc={0} msg={1}", rc, _z.Message) + ); } } } @@ -639,7 +668,11 @@ namespace SharpCompress.Compressors.Deflate public override Int64 Length => _stream.Length; - public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); } + public override long Position + { + get => throw new NotSupportedException(); + set => throw new NotSupportedException(); + } internal enum StreamMode { diff --git a/src/SharpCompress/Compressors/Deflate/ZlibCodec.cs b/src/SharpCompress/Compressors/Deflate/ZlibCodec.cs index 8b995018..4c8e0b78 100644 --- a/src/SharpCompress/Compressors/Deflate/ZlibCodec.cs +++ b/src/SharpCompress/Compressors/Deflate/ZlibCodec.cs @@ -3,20 +3,20 @@ // ZlibCodec.cs // ------------------------------------------------------------------ // -// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation. +// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation. // All rights reserved. // // This code module is part of DotNetZip, a zipfile class library. // // ------------------------------------------------------------------ // -// This code is licensed under the Microsoft Public License. +// This code is licensed under the Microsoft Public License. // See the file License.txt for the license details. // More info on: http://dotnetzip.codeplex.com // // ------------------------------------------------------------------ // -// last saved (in emacs): +// last saved (in emacs): // Time-stamp: <2009-November-03 15:40:51> // // ------------------------------------------------------------------ @@ -30,22 +30,22 @@ // is included below. // // ------------------------------------------------------------------ -// +// // Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. -// +// // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: -// +// // 1. Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in // the documentation and/or other materials provided with the distribution. -// +// // 3. The names of the authors may not be used to endorse or promote products // derived from this software without specific prior written permission. -// +// // THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, @@ -56,7 +56,7 @@ // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, // EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// +// // ----------------------------------------------------------------------- // // This program is based on zlib-1.1.3; credit to authors @@ -87,15 +87,15 @@ namespace SharpCompress.Compressors.Deflate public byte[] InputBuffer; /// - /// An index into the InputBuffer array, indicating where to start reading. + /// An index into the InputBuffer array, indicating where to start reading. /// public int NextIn; /// - /// The number of bytes available in the InputBuffer, starting at NextIn. + /// The number of bytes available in the InputBuffer, starting at NextIn. /// /// - /// Generally you should set this to InputBuffer.Length before the first Inflate() or Deflate() call. + /// Generally you should set this to InputBuffer.Length before the first Inflate() or Deflate() call. /// The class will update this number as calls to Inflate/Deflate are made. /// public int AvailableBytesIn; @@ -111,15 +111,15 @@ namespace SharpCompress.Compressors.Deflate public byte[] OutputBuffer; /// - /// An index into the OutputBuffer array, indicating where to start writing. + /// An index into the OutputBuffer array, indicating where to start writing. /// public int NextOut; /// - /// The number of bytes available in the OutputBuffer, starting at NextOut. + /// The number of bytes available in the OutputBuffer, starting at NextOut. /// /// - /// Generally you should set this to OutputBuffer.Length before the first Inflate() or Deflate() call. + /// Generally you should set this to OutputBuffer.Length before the first Inflate() or Deflate() call. /// The class will update this number as calls to Inflate/Deflate are made. /// public int AvailableBytesOut; @@ -145,13 +145,13 @@ namespace SharpCompress.Compressors.Deflate public CompressionLevel CompressLevel = CompressionLevel.Default; /// - /// The number of Window Bits to use. + /// The number of Window Bits to use. /// /// - /// This gauges the size of the sliding window, and hence the - /// compression effectiveness as well as memory consumption. It's best to just leave this + /// This gauges the size of the sliding window, and hence the + /// compression effectiveness as well as memory consumption. It's best to just leave this /// setting alone if you don't know what it is. The maximum value is 15 bits, which implies - /// a 32k window. + /// a 32k window. /// public int WindowBits = ZlibConstants.WindowBitsDefault; @@ -179,13 +179,11 @@ namespace SharpCompress.Compressors.Deflate /// Create a ZlibCodec. /// /// - /// If you use this default constructor, you will later have to explicitly call - /// InitializeInflate() or InitializeDeflate() before using the ZlibCodec to compress - /// or decompress. + /// If you use this default constructor, you will later have to explicitly call + /// InitializeInflate() or InitializeDeflate() before using the ZlibCodec to compress + /// or decompress. /// - public ZlibCodec() - { - } + public ZlibCodec() { } /// /// Create a ZlibCodec that either compresses or decompresses. @@ -218,10 +216,10 @@ namespace SharpCompress.Compressors.Deflate } /// - /// Initialize the inflation state. + /// Initialize the inflation state. /// /// - /// It is not necessary to call this before using the ZlibCodec to inflate data; + /// It is not necessary to call this before using the ZlibCodec to inflate data; /// It is implicitly called when you call the constructor. /// /// Z_OK if everything goes well. @@ -254,9 +252,9 @@ namespace SharpCompress.Compressors.Deflate } /// - /// Initialize the ZlibCodec for inflation, with the specified number of window bits. + /// Initialize the ZlibCodec for inflation, with the specified number of window bits. /// - /// The number of window bits to use. If you need to ask what that is, + /// The number of window bits to use. If you need to ask what that is, /// then you shouldn't be calling this initializer. /// Z_OK if all goes well. public int InitializeInflate(int windowBits) @@ -267,7 +265,7 @@ namespace SharpCompress.Compressors.Deflate /// /// Initialize the inflation state with an explicit flag to govern the handling of - /// RFC1950 header bytes. + /// RFC1950 header bytes. /// /// /// @@ -279,9 +277,9 @@ namespace SharpCompress.Compressors.Deflate /// false. /// /// - /// whether to expect an RFC1950 header byte pair when reading + /// whether to expect an RFC1950 header byte pair when reading /// the stream of data to be inflated. - /// The number of window bits to use. If you need to ask what that is, + /// The number of window bits to use. If you need to ask what that is, /// then you shouldn't be calling this initializer. /// Z_OK if everything goes well. public int InitializeInflate(int windowBits, bool expectRfc1950Header) @@ -289,7 +287,9 @@ namespace SharpCompress.Compressors.Deflate WindowBits = windowBits; if (dstate != null) { - throw new ZlibException("You may not call InitializeInflate() after calling InitializeDeflate()."); + throw new ZlibException( + "You may not call InitializeInflate() after calling InitializeDeflate()." + ); } istate = new InflateManager(expectRfc1950Header); return istate.Initialize(this, windowBits); @@ -299,7 +299,7 @@ namespace SharpCompress.Compressors.Deflate /// Inflate the data in the InputBuffer, placing the result in the OutputBuffer. /// /// - /// You must have set InputBuffer and OutputBuffer, NextIn and NextOut, and AvailableBytesIn and + /// You must have set InputBuffer and OutputBuffer, NextIn and NextOut, and AvailableBytesIn and /// AvailableBytesOut before calling this method. /// /// @@ -309,48 +309,48 @@ namespace SharpCompress.Compressors.Deflate /// int bufferSize = 1024; /// byte[] buffer = new byte[bufferSize]; /// ZlibCodec decompressor = new ZlibCodec(); - /// + /// /// Console.WriteLine("\n============================================"); /// Console.WriteLine("Size of Buffer to Inflate: {0} bytes.", CompressedBytes.Length); /// MemoryStream ms = new MemoryStream(DecompressedBytes); - /// + /// /// int rc = decompressor.InitializeInflate(); - /// + /// /// decompressor.InputBuffer = CompressedBytes; /// decompressor.NextIn = 0; /// decompressor.AvailableBytesIn = CompressedBytes.Length; - /// + /// /// decompressor.OutputBuffer = buffer; - /// - /// // pass 1: inflate + /// + /// // pass 1: inflate /// do /// { /// decompressor.NextOut = 0; /// decompressor.AvailableBytesOut = buffer.Length; /// rc = decompressor.Inflate(FlushType.None); - /// + /// /// if (rc != ZlibConstants.Z_OK && rc != ZlibConstants.Z_STREAM_END) /// throw new Exception("inflating: " + decompressor.Message); - /// + /// /// ms.Write(decompressor.OutputBuffer, 0, buffer.Length - decompressor.AvailableBytesOut); /// } /// while (decompressor.AvailableBytesIn > 0 || decompressor.AvailableBytesOut == 0); - /// + /// /// // pass 2: finish and flush /// do /// { /// decompressor.NextOut = 0; /// decompressor.AvailableBytesOut = buffer.Length; /// rc = decompressor.Inflate(FlushType.Finish); - /// + /// /// if (rc != ZlibConstants.Z_STREAM_END && rc != ZlibConstants.Z_OK) /// throw new Exception("inflating: " + decompressor.Message); - /// + /// /// if (buffer.Length - decompressor.AvailableBytesOut > 0) /// ms.Write(buffer, 0, buffer.Length - decompressor.AvailableBytesOut); /// } /// while (decompressor.AvailableBytesIn > 0 || decompressor.AvailableBytesOut == 0); - /// + /// /// decompressor.EndInflate(); /// } /// @@ -368,10 +368,10 @@ namespace SharpCompress.Compressors.Deflate } /// - /// Ends an inflation session. + /// Ends an inflation session. /// /// - /// Call this after successively calling Inflate(). This will cause all buffers to be flushed. + /// Call this after successively calling Inflate(). This will cause all buffers to be flushed. /// After calling this you cannot call Inflate() without a intervening call to one of the /// InitializeInflate() overloads. /// @@ -411,32 +411,32 @@ namespace SharpCompress.Compressors.Deflate /// int bufferSize = 40000; /// byte[] CompressedBytes = new byte[bufferSize]; /// byte[] DecompressedBytes = new byte[bufferSize]; - /// + /// /// ZlibCodec compressor = new ZlibCodec(); - /// + /// /// compressor.InitializeDeflate(CompressionLevel.Default); - /// + /// /// compressor.InputBuffer = System.Text.ASCIIEncoding.ASCII.GetBytes(TextToCompress); /// compressor.NextIn = 0; /// compressor.AvailableBytesIn = compressor.InputBuffer.Length; - /// + /// /// compressor.OutputBuffer = CompressedBytes; /// compressor.NextOut = 0; /// compressor.AvailableBytesOut = CompressedBytes.Length; - /// + /// /// while (compressor.TotalBytesIn != TextToCompress.Length && compressor.TotalBytesOut < bufferSize) /// { /// compressor.Deflate(FlushType.None); /// } - /// + /// /// while (true) /// { /// int rc= compressor.Deflate(FlushType.Finish); /// if (rc == ZlibConstants.Z_STREAM_END) break; /// } - /// + /// /// compressor.EndDeflate(); - /// + /// /// /// /// Z_OK if all goes well. You generally don't need to check the return code. @@ -461,7 +461,7 @@ namespace SharpCompress.Compressors.Deflate } /// - /// Initialize the ZlibCodec for deflation operation, using the specified CompressionLevel, + /// Initialize the ZlibCodec for deflation operation, using the specified CompressionLevel, /// and the explicit flag governing whether to emit an RFC1950 header byte pair. /// /// @@ -469,7 +469,7 @@ namespace SharpCompress.Compressors.Deflate /// If you want to generate a zlib stream, you should specify true for /// wantRfc1950Header. In this case, the library will emit a ZLIB /// header, as defined in RFC - /// 1950, in the compressed stream. + /// 1950, in the compressed stream. /// /// The compression level for the codec. /// whether to emit an initial RFC1950 byte pair in the compressed stream. @@ -481,8 +481,8 @@ namespace SharpCompress.Compressors.Deflate } /// - /// Initialize the ZlibCodec for deflation operation, using the specified CompressionLevel, - /// and the specified number of window bits. + /// Initialize the ZlibCodec for deflation operation, using the specified CompressionLevel, + /// and the specified number of window bits. /// /// /// The codec will use the specified number of window bits and the specified CompressionLevel. @@ -518,7 +518,9 @@ namespace SharpCompress.Compressors.Deflate { if (istate != null) { - throw new ZlibException("You may not call InitializeDeflate() after calling InitializeInflate()."); + throw new ZlibException( + "You may not call InitializeDeflate() after calling InitializeInflate()." + ); } dstate = new DeflateManager(); dstate.WantRfc1950HeaderBytes = wantRfc1950Header; @@ -539,59 +541,59 @@ namespace SharpCompress.Compressors.Deflate /// int bufferSize = 1024; /// byte[] buffer = new byte[bufferSize]; /// ZlibCodec compressor = new ZlibCodec(); - /// + /// /// Console.WriteLine("\n============================================"); /// Console.WriteLine("Size of Buffer to Deflate: {0} bytes.", UncompressedBytes.Length); /// MemoryStream ms = new MemoryStream(); - /// + /// /// int rc = compressor.InitializeDeflate(level); - /// + /// /// compressor.InputBuffer = UncompressedBytes; /// compressor.NextIn = 0; /// compressor.AvailableBytesIn = UncompressedBytes.Length; - /// + /// /// compressor.OutputBuffer = buffer; - /// - /// // pass 1: deflate + /// + /// // pass 1: deflate /// do /// { /// compressor.NextOut = 0; /// compressor.AvailableBytesOut = buffer.Length; /// rc = compressor.Deflate(FlushType.None); - /// + /// /// if (rc != ZlibConstants.Z_OK && rc != ZlibConstants.Z_STREAM_END) /// throw new Exception("deflating: " + compressor.Message); - /// + /// /// ms.Write(compressor.OutputBuffer, 0, buffer.Length - compressor.AvailableBytesOut); /// } /// while (compressor.AvailableBytesIn > 0 || compressor.AvailableBytesOut == 0); - /// + /// /// // pass 2: finish and flush /// do /// { /// compressor.NextOut = 0; /// compressor.AvailableBytesOut = buffer.Length; /// rc = compressor.Deflate(FlushType.Finish); - /// + /// /// if (rc != ZlibConstants.Z_STREAM_END && rc != ZlibConstants.Z_OK) /// throw new Exception("deflating: " + compressor.Message); - /// + /// /// if (buffer.Length - compressor.AvailableBytesOut > 0) /// ms.Write(buffer, 0, buffer.Length - compressor.AvailableBytesOut); /// } /// while (compressor.AvailableBytesIn > 0 || compressor.AvailableBytesOut == 0); - /// + /// /// compressor.EndDeflate(); - /// + /// /// ms.Seek(0, SeekOrigin.Begin); /// CompressedBytes = new byte[compressor.TotalBytesOut]; /// ms.Read(CompressedBytes, 0, CompressedBytes.Length); /// } /// /// - /// whether to flush all data as you deflate. Generally you will want to - /// use Z_NO_FLUSH here, in a series of calls to Deflate(), and then call EndDeflate() to - /// flush everything. + /// whether to flush all data as you deflate. Generally you will want to + /// use Z_NO_FLUSH here, in a series of calls to Deflate(), and then call EndDeflate() to + /// flush everything. /// /// Z_OK if all goes well. public int Deflate(FlushType flush) @@ -693,13 +695,20 @@ namespace SharpCompress.Compressors.Deflate return; } - if (dstate.pending.Length <= dstate.nextPending || - OutputBuffer.Length <= NextOut || - dstate.pending.Length < (dstate.nextPending + len) || - OutputBuffer.Length < (NextOut + len)) + if ( + dstate.pending.Length <= dstate.nextPending + || OutputBuffer.Length <= NextOut + || dstate.pending.Length < (dstate.nextPending + len) + || OutputBuffer.Length < (NextOut + len) + ) { - throw new ZlibException(String.Format("Invalid State. (pending.Length={0}, pendingCount={1})", - dstate.pending.Length, dstate.pendingCount)); + throw new ZlibException( + String.Format( + "Invalid State. (pending.Length={0}, pendingCount={1})", + dstate.pending.Length, + dstate.pendingCount + ) + ); } Array.Copy(dstate.pending, dstate.nextPending, OutputBuffer, NextOut, len); @@ -745,4 +754,4 @@ namespace SharpCompress.Compressors.Deflate return len; } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/Deflate/ZlibConstants.cs b/src/SharpCompress/Compressors/Deflate/ZlibConstants.cs index a6780614..48d6c170 100644 --- a/src/SharpCompress/Compressors/Deflate/ZlibConstants.cs +++ b/src/SharpCompress/Compressors/Deflate/ZlibConstants.cs @@ -1,20 +1,20 @@ // ZlibConstants.cs // ------------------------------------------------------------------ // -// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation. +// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation. // All rights reserved. // // This code module is part of DotNetZip, a zipfile class library. // // ------------------------------------------------------------------ // -// This code is licensed under the Microsoft Public License. +// This code is licensed under the Microsoft Public License. // See the file License.txt for the license details. // More info on: http://dotnetzip.codeplex.com // // ------------------------------------------------------------------ // -// last saved (in emacs): +// last saved (in emacs): // Time-stamp: <2009-November-03 18:50:19> // // ------------------------------------------------------------------ @@ -25,22 +25,22 @@ // copyright to that code is included here. // // ------------------------------------------------------------------ -// +// // Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. -// +// // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: -// +// // 1. Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in // the documentation and/or other materials provided with the distribution. -// +// // 3. The names of the authors may not be used to endorse or promote products // derived from this software without specific prior written permission. -// +// // THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, @@ -51,7 +51,7 @@ // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, // EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// +// // ----------------------------------------------------------------------- // // This program is based on zlib-1.1.3; credit to authors @@ -89,7 +89,7 @@ namespace SharpCompress.Compressors.Deflate public const int Z_STREAM_END = 1; /// - /// The operation ended in need of a dictionary. + /// The operation ended in need of a dictionary. /// public const int Z_NEED_DICT = 2; @@ -122,4 +122,4 @@ namespace SharpCompress.Compressors.Deflate /// public const int WorkingBufferSizeMin = 1024; } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/Deflate/ZlibStream.cs b/src/SharpCompress/Compressors/Deflate/ZlibStream.cs index c82040ef..8d8be7ae 100644 --- a/src/SharpCompress/Compressors/Deflate/ZlibStream.cs +++ b/src/SharpCompress/Compressors/Deflate/ZlibStream.cs @@ -37,16 +37,17 @@ namespace SharpCompress.Compressors.Deflate private bool _disposed; public ZlibStream(Stream stream, CompressionMode mode) - : this(stream, mode, CompressionLevel.Default, Encoding.UTF8) - { - } + : this(stream, mode, CompressionLevel.Default, Encoding.UTF8) { } public ZlibStream(Stream stream, CompressionMode mode, CompressionLevel level) - : this(stream, mode, level, Encoding.UTF8) - { - } + : this(stream, mode, level, Encoding.UTF8) { } - public ZlibStream(Stream stream, CompressionMode mode, CompressionLevel level, Encoding encoding) + public ZlibStream( + Stream stream, + CompressionMode mode, + CompressionLevel level, + Encoding encoding + ) { _baseStream = new ZlibBaseStream(stream, mode, level, ZlibStreamFlavor.ZLIB, encoding); } @@ -103,8 +104,12 @@ namespace SharpCompress.Compressors.Deflate if (value < ZlibConstants.WorkingBufferSizeMin) { throw new ZlibException( - String.Format("Don't be silly. {0} bytes?? Use a bigger buffer, at least {1}.", value, - ZlibConstants.WorkingBufferSizeMin)); + String.Format( + "Don't be silly. {0} bytes?? Use a bigger buffer, at least {1}.", + value, + ZlibConstants.WorkingBufferSizeMin + ) + ); } _baseStream._bufferSize = value; } @@ -194,7 +199,6 @@ namespace SharpCompress.Compressors.Deflate } return 0; } - set => throw new NotSupportedException(); } @@ -341,4 +345,4 @@ namespace SharpCompress.Compressors.Deflate #endregion System.IO.Stream methods } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/Deflate64/Deflate64Stream.cs b/src/SharpCompress/Compressors/Deflate64/Deflate64Stream.cs index c05f0c2a..d182db74 100644 --- a/src/SharpCompress/Compressors/Deflate64/Deflate64Stream.cs +++ b/src/SharpCompress/Compressors/Deflate64/Deflate64Stream.cs @@ -30,12 +30,17 @@ namespace SharpCompress.Compressors.Deflate64 if (mode != CompressionMode.Decompress) { - throw new NotImplementedException("Deflate64: this implementation only supports decompression"); + throw new NotImplementedException( + "Deflate64: this implementation only supports decompression" + ); } if (!stream.CanRead) { - throw new ArgumentException("Deflate64: input stream is not readable", nameof(stream)); + throw new ArgumentException( + "Deflate64: input stream is not readable", + nameof(stream) + ); } InitializeInflater(stream, ZipCompressionMethod.Deflate64); @@ -44,13 +49,21 @@ namespace SharpCompress.Compressors.Deflate64 /// /// Sets up this DeflateManagedStream to be used for Inflation/Decompression /// - private void InitializeInflater(Stream stream, ZipCompressionMethod method = ZipCompressionMethod.Deflate) + private void InitializeInflater( + Stream stream, + ZipCompressionMethod method = ZipCompressionMethod.Deflate + ) { Debug.Assert(stream != null); - Debug.Assert(method == ZipCompressionMethod.Deflate || method == ZipCompressionMethod.Deflate64); + Debug.Assert( + method == ZipCompressionMethod.Deflate || method == ZipCompressionMethod.Deflate64 + ); if (!stream.CanRead) { - throw new ArgumentException("Deflate64: input stream is not readable", nameof(stream)); + throw new ArgumentException( + "Deflate64: input stream is not readable", + nameof(stream) + ); } _inflater = new InflaterManaged(method == ZipCompressionMethod.Deflate64); @@ -138,7 +151,10 @@ namespace SharpCompress.Compressors.Deflate64 if (_inflater.Finished()) { // if we finished decompressing, we can't have anything left in the outputwindow. - Debug.Assert(_inflater.AvailableOutput == 0, "We should have copied all stuff out!"); + Debug.Assert( + _inflater.AvailableOutput == 0, + "We should have copied all stuff out!" + ); break; } diff --git a/src/SharpCompress/Compressors/Deflate64/DeflateInput.cs b/src/SharpCompress/Compressors/Deflate64/DeflateInput.cs index 16010e17..2305d241 100644 --- a/src/SharpCompress/Compressors/Deflate64/DeflateInput.cs +++ b/src/SharpCompress/Compressors/Deflate64/DeflateInput.cs @@ -33,7 +33,8 @@ namespace SharpCompress.Compressors.Deflate64 StartIndex = state._startIndex; } - internal /*readonly */struct InputState + internal /*readonly */ + struct InputState { internal readonly int _count; internal readonly int _startIndex; diff --git a/src/SharpCompress/Compressors/Deflate64/FastEncoderStatus.cs b/src/SharpCompress/Compressors/Deflate64/FastEncoderStatus.cs index f5f26276..8b0992da 100644 --- a/src/SharpCompress/Compressors/Deflate64/FastEncoderStatus.cs +++ b/src/SharpCompress/Compressors/Deflate64/FastEncoderStatus.cs @@ -11,31 +11,211 @@ namespace SharpCompress.Compressors.Deflate64 { // static information for encoding, DO NOT MODIFY - internal static ReadOnlySpan FAST_ENCODER_TREE_STRUCTURE_DATA => new byte[] - { - 0xec,0xbd,0x07,0x60,0x1c,0x49,0x96,0x25,0x26,0x2f,0x6d,0xca, - 0x7b,0x7f,0x4a,0xf5,0x4a,0xd7,0xe0,0x74,0xa1,0x08,0x80,0x60, - 0x13,0x24,0xd8,0x90,0x40,0x10,0xec,0xc1,0x88,0xcd,0xe6,0x92, - 0xec,0x1d,0x69,0x47,0x23,0x29,0xab,0x2a,0x81,0xca,0x65,0x56, - 0x65,0x5d,0x66,0x16,0x40,0xcc,0xed,0x9d,0xbc,0xf7,0xde,0x7b, - 0xef,0xbd,0xf7,0xde,0x7b,0xef,0xbd,0xf7,0xba,0x3b,0x9d,0x4e, - 0x27,0xf7,0xdf,0xff,0x3f,0x5c,0x66,0x64,0x01,0x6c,0xf6,0xce, - 0x4a,0xda,0xc9,0x9e,0x21,0x80,0xaa,0xc8,0x1f,0x3f,0x7e,0x7c, - 0x1f,0x3f - }; + internal static ReadOnlySpan FAST_ENCODER_TREE_STRUCTURE_DATA => + new byte[] + { + 0xec, + 0xbd, + 0x07, + 0x60, + 0x1c, + 0x49, + 0x96, + 0x25, + 0x26, + 0x2f, + 0x6d, + 0xca, + 0x7b, + 0x7f, + 0x4a, + 0xf5, + 0x4a, + 0xd7, + 0xe0, + 0x74, + 0xa1, + 0x08, + 0x80, + 0x60, + 0x13, + 0x24, + 0xd8, + 0x90, + 0x40, + 0x10, + 0xec, + 0xc1, + 0x88, + 0xcd, + 0xe6, + 0x92, + 0xec, + 0x1d, + 0x69, + 0x47, + 0x23, + 0x29, + 0xab, + 0x2a, + 0x81, + 0xca, + 0x65, + 0x56, + 0x65, + 0x5d, + 0x66, + 0x16, + 0x40, + 0xcc, + 0xed, + 0x9d, + 0xbc, + 0xf7, + 0xde, + 0x7b, + 0xef, + 0xbd, + 0xf7, + 0xde, + 0x7b, + 0xef, + 0xbd, + 0xf7, + 0xba, + 0x3b, + 0x9d, + 0x4e, + 0x27, + 0xf7, + 0xdf, + 0xff, + 0x3f, + 0x5c, + 0x66, + 0x64, + 0x01, + 0x6c, + 0xf6, + 0xce, + 0x4a, + 0xda, + 0xc9, + 0x9e, + 0x21, + 0x80, + 0xaa, + 0xc8, + 0x1f, + 0x3f, + 0x7e, + 0x7c, + 0x1f, + 0x3f + }; - internal static ReadOnlySpan B_FINAL_FAST_ENCODER_TREE_STRUCTURE_DATA => new byte[] - { - 0xed,0xbd,0x07,0x60,0x1c,0x49,0x96,0x25,0x26,0x2f,0x6d,0xca, - 0x7b,0x7f,0x4a,0xf5,0x4a,0xd7,0xe0,0x74,0xa1,0x08,0x80,0x60, - 0x13,0x24,0xd8,0x90,0x40,0x10,0xec,0xc1,0x88,0xcd,0xe6,0x92, - 0xec,0x1d,0x69,0x47,0x23,0x29,0xab,0x2a,0x81,0xca,0x65,0x56, - 0x65,0x5d,0x66,0x16,0x40,0xcc,0xed,0x9d,0xbc,0xf7,0xde,0x7b, - 0xef,0xbd,0xf7,0xde,0x7b,0xef,0xbd,0xf7,0xba,0x3b,0x9d,0x4e, - 0x27,0xf7,0xdf,0xff,0x3f,0x5c,0x66,0x64,0x01,0x6c,0xf6,0xce, - 0x4a,0xda,0xc9,0x9e,0x21,0x80,0xaa,0xc8,0x1f,0x3f,0x7e,0x7c, - 0x1f,0x3f - }; + internal static ReadOnlySpan B_FINAL_FAST_ENCODER_TREE_STRUCTURE_DATA => + new byte[] + { + 0xed, + 0xbd, + 0x07, + 0x60, + 0x1c, + 0x49, + 0x96, + 0x25, + 0x26, + 0x2f, + 0x6d, + 0xca, + 0x7b, + 0x7f, + 0x4a, + 0xf5, + 0x4a, + 0xd7, + 0xe0, + 0x74, + 0xa1, + 0x08, + 0x80, + 0x60, + 0x13, + 0x24, + 0xd8, + 0x90, + 0x40, + 0x10, + 0xec, + 0xc1, + 0x88, + 0xcd, + 0xe6, + 0x92, + 0xec, + 0x1d, + 0x69, + 0x47, + 0x23, + 0x29, + 0xab, + 0x2a, + 0x81, + 0xca, + 0x65, + 0x56, + 0x65, + 0x5d, + 0x66, + 0x16, + 0x40, + 0xcc, + 0xed, + 0x9d, + 0xbc, + 0xf7, + 0xde, + 0x7b, + 0xef, + 0xbd, + 0xf7, + 0xde, + 0x7b, + 0xef, + 0xbd, + 0xf7, + 0xba, + 0x3b, + 0x9d, + 0x4e, + 0x27, + 0xf7, + 0xdf, + 0xff, + 0x3f, + 0x5c, + 0x66, + 0x64, + 0x01, + 0x6c, + 0xf6, + 0xce, + 0x4a, + 0xda, + 0xc9, + 0x9e, + 0x21, + 0x80, + 0xaa, + 0xc8, + 0x1f, + 0x3f, + 0x7e, + 0x7c, + 0x1f, + 0x3f + }; // Output a currentMatch with length matchLen (>= MIN_MATCH) and displacement matchPos // @@ -70,94 +250,643 @@ namespace SharpCompress.Compressors.Deflate64 internal static readonly uint[] FAST_ENCODER_LITERAL_CODE_INFO = { - 0x0000d7ee,0x0004d7ee,0x0002d7ee,0x0006d7ee,0x0001d7ee,0x0005d7ee,0x0003d7ee, - 0x0007d7ee,0x000037ee,0x0000c7ec,0x00000126,0x000437ee,0x000237ee,0x000637ee, - 0x000137ee,0x000537ee,0x000337ee,0x000737ee,0x0000b7ee,0x0004b7ee,0x0002b7ee, - 0x0006b7ee,0x0001b7ee,0x0005b7ee,0x0003b7ee,0x0007b7ee,0x000077ee,0x000477ee, - 0x000277ee,0x000677ee,0x000017ed,0x000177ee,0x00000526,0x000577ee,0x000023ea, - 0x0001c7ec,0x000377ee,0x000777ee,0x000217ed,0x000063ea,0x00000b68,0x00000ee9, - 0x00005beb,0x000013ea,0x00000467,0x00001b68,0x00000c67,0x00002ee9,0x00000768, - 0x00001768,0x00000f68,0x00001ee9,0x00001f68,0x00003ee9,0x000053ea,0x000001e9, - 0x000000e8,0x000021e9,0x000011e9,0x000010e8,0x000031e9,0x000033ea,0x000008e8, - 0x0000f7ee,0x0004f7ee,0x000018e8,0x000009e9,0x000004e8,0x000029e9,0x000014e8, - 0x000019e9,0x000073ea,0x0000dbeb,0x00000ce8,0x00003beb,0x0002f7ee,0x000039e9, - 0x00000bea,0x000005e9,0x00004bea,0x000025e9,0x000027ec,0x000015e9,0x000035e9, - 0x00000de9,0x00002bea,0x000127ec,0x0000bbeb,0x0006f7ee,0x0001f7ee,0x0000a7ec, - 0x00007beb,0x0005f7ee,0x0000fbeb,0x0003f7ee,0x0007f7ee,0x00000fee,0x00000326, - 0x00000267,0x00000a67,0x00000667,0x00000726,0x00001ce8,0x000002e8,0x00000e67, - 0x000000a6,0x0001a7ec,0x00002de9,0x000004a6,0x00000167,0x00000967,0x000002a6, - 0x00000567,0x000117ed,0x000006a6,0x000001a6,0x000005a6,0x00000d67,0x000012e8, - 0x00000ae8,0x00001de9,0x00001ae8,0x000007eb,0x000317ed,0x000067ec,0x000097ed, - 0x000297ed,0x00040fee,0x00020fee,0x00060fee,0x00010fee,0x00050fee,0x00030fee, - 0x00070fee,0x00008fee,0x00048fee,0x00028fee,0x00068fee,0x00018fee,0x00058fee, - 0x00038fee,0x00078fee,0x00004fee,0x00044fee,0x00024fee,0x00064fee,0x00014fee, - 0x00054fee,0x00034fee,0x00074fee,0x0000cfee,0x0004cfee,0x0002cfee,0x0006cfee, - 0x0001cfee,0x0005cfee,0x0003cfee,0x0007cfee,0x00002fee,0x00042fee,0x00022fee, - 0x00062fee,0x00012fee,0x00052fee,0x00032fee,0x00072fee,0x0000afee,0x0004afee, - 0x0002afee,0x0006afee,0x0001afee,0x0005afee,0x0003afee,0x0007afee,0x00006fee, - 0x00046fee,0x00026fee,0x00066fee,0x00016fee,0x00056fee,0x00036fee,0x00076fee, - 0x0000efee,0x0004efee,0x0002efee,0x0006efee,0x0001efee,0x0005efee,0x0003efee, - 0x0007efee,0x00001fee,0x00041fee,0x00021fee,0x00061fee,0x00011fee,0x00051fee, - 0x00031fee,0x00071fee,0x00009fee,0x00049fee,0x00029fee,0x00069fee,0x00019fee, - 0x00059fee,0x00039fee,0x00079fee,0x00005fee,0x00045fee,0x00025fee,0x00065fee, - 0x00015fee,0x00055fee,0x00035fee,0x00075fee,0x0000dfee,0x0004dfee,0x0002dfee, - 0x0006dfee,0x0001dfee,0x0005dfee,0x0003dfee,0x0007dfee,0x00003fee,0x00043fee, - 0x00023fee,0x00063fee,0x00013fee,0x00053fee,0x00033fee,0x00073fee,0x0000bfee, - 0x0004bfee,0x0002bfee,0x0006bfee,0x0001bfee,0x0005bfee,0x0003bfee,0x0007bfee, - 0x00007fee,0x00047fee,0x00027fee,0x00067fee,0x00017fee,0x000197ed,0x000397ed, - 0x000057ed,0x00057fee,0x000257ed,0x00037fee,0x000157ed,0x00077fee,0x000357ed, - 0x0000ffee,0x0004ffee,0x0002ffee,0x0006ffee,0x0001ffee,0x00000084,0x00000003, - 0x00000184,0x00000044,0x00000144,0x000000c5,0x000002c5,0x000001c5,0x000003c6, - 0x000007c6,0x00000026,0x00000426,0x000003a7,0x00000ba7,0x000007a7,0x00000fa7, - 0x00000227,0x00000627,0x00000a27,0x00000e27,0x00000068,0x00000868,0x00001068, - 0x00001868,0x00000369,0x00001369,0x00002369,0x00003369,0x000006ea,0x000026ea, - 0x000046ea,0x000066ea,0x000016eb,0x000036eb,0x000056eb,0x000076eb,0x000096eb, - 0x0000b6eb,0x0000d6eb,0x0000f6eb,0x00003dec,0x00007dec,0x0000bdec,0x0000fdec, - 0x00013dec,0x00017dec,0x0001bdec,0x0001fdec,0x00006bed,0x0000ebed,0x00016bed, - 0x0001ebed,0x00026bed,0x0002ebed,0x00036bed,0x0003ebed,0x000003ec,0x000043ec, - 0x000083ec,0x0000c3ec,0x000103ec,0x000143ec,0x000183ec,0x0001c3ec,0x00001bee, - 0x00009bee,0x00011bee,0x00019bee,0x00021bee,0x00029bee,0x00031bee,0x00039bee, - 0x00041bee,0x00049bee,0x00051bee,0x00059bee,0x00061bee,0x00069bee,0x00071bee, - 0x00079bee,0x000167f0,0x000367f0,0x000567f0,0x000767f0,0x000967f0,0x000b67f0, - 0x000d67f0,0x000f67f0,0x001167f0,0x001367f0,0x001567f0,0x001767f0,0x001967f0, - 0x001b67f0,0x001d67f0,0x001f67f0,0x000087ef,0x000187ef,0x000287ef,0x000387ef, - 0x000487ef,0x000587ef,0x000687ef,0x000787ef,0x000887ef,0x000987ef,0x000a87ef, - 0x000b87ef,0x000c87ef,0x000d87ef,0x000e87ef,0x000f87ef,0x0000e7f0,0x0002e7f0, - 0x0004e7f0,0x0006e7f0,0x0008e7f0,0x000ae7f0,0x000ce7f0,0x000ee7f0,0x0010e7f0, - 0x0012e7f0,0x0014e7f0,0x0016e7f0,0x0018e7f0,0x001ae7f0,0x001ce7f0,0x001ee7f0, - 0x0005fff3,0x000dfff3,0x0015fff3,0x001dfff3,0x0025fff3,0x002dfff3,0x0035fff3, - 0x003dfff3,0x0045fff3,0x004dfff3,0x0055fff3,0x005dfff3,0x0065fff3,0x006dfff3, - 0x0075fff3,0x007dfff3,0x0085fff3,0x008dfff3,0x0095fff3,0x009dfff3,0x00a5fff3, - 0x00adfff3,0x00b5fff3,0x00bdfff3,0x00c5fff3,0x00cdfff3,0x00d5fff3,0x00ddfff3, - 0x00e5fff3,0x00edfff3,0x00f5fff3,0x00fdfff3,0x0003fff3,0x000bfff3,0x0013fff3, - 0x001bfff3,0x0023fff3,0x002bfff3,0x0033fff3,0x003bfff3,0x0043fff3,0x004bfff3, - 0x0053fff3,0x005bfff3,0x0063fff3,0x006bfff3,0x0073fff3,0x007bfff3,0x0083fff3, - 0x008bfff3,0x0093fff3,0x009bfff3,0x00a3fff3,0x00abfff3,0x00b3fff3,0x00bbfff3, - 0x00c3fff3,0x00cbfff3,0x00d3fff3,0x00dbfff3,0x00e3fff3,0x00ebfff3,0x00f3fff3, - 0x00fbfff3,0x0007fff3,0x000ffff3,0x0017fff3,0x001ffff3,0x0027fff3,0x002ffff3, - 0x0037fff3,0x003ffff3,0x0047fff3,0x004ffff3,0x0057fff3,0x005ffff3,0x0067fff3, - 0x006ffff3,0x0077fff3,0x007ffff3,0x0087fff3,0x008ffff3,0x0097fff3,0x009ffff3, - 0x00a7fff3,0x00affff3,0x00b7fff3,0x00bffff3,0x00c7fff3,0x00cffff3,0x00d7fff3, - 0x00dffff3,0x00e7fff3,0x00effff3,0x00f7fff3,0x00fffff3,0x0001e7f1,0x0003e7f1, - 0x0005e7f1,0x0007e7f1,0x0009e7f1,0x000be7f1,0x000de7f1,0x000fe7f1,0x0011e7f1, - 0x0013e7f1,0x0015e7f1,0x0017e7f1,0x0019e7f1,0x001be7f1,0x001de7f1,0x001fe7f1, - 0x0021e7f1,0x0023e7f1,0x0025e7f1,0x0027e7f1,0x0029e7f1,0x002be7f1,0x002de7f1, - 0x002fe7f1,0x0031e7f1,0x0033e7f1,0x0035e7f1,0x0037e7f1,0x0039e7f1,0x003be7f1, - 0x003de7f1,0x000047eb + 0x0000d7ee, + 0x0004d7ee, + 0x0002d7ee, + 0x0006d7ee, + 0x0001d7ee, + 0x0005d7ee, + 0x0003d7ee, + 0x0007d7ee, + 0x000037ee, + 0x0000c7ec, + 0x00000126, + 0x000437ee, + 0x000237ee, + 0x000637ee, + 0x000137ee, + 0x000537ee, + 0x000337ee, + 0x000737ee, + 0x0000b7ee, + 0x0004b7ee, + 0x0002b7ee, + 0x0006b7ee, + 0x0001b7ee, + 0x0005b7ee, + 0x0003b7ee, + 0x0007b7ee, + 0x000077ee, + 0x000477ee, + 0x000277ee, + 0x000677ee, + 0x000017ed, + 0x000177ee, + 0x00000526, + 0x000577ee, + 0x000023ea, + 0x0001c7ec, + 0x000377ee, + 0x000777ee, + 0x000217ed, + 0x000063ea, + 0x00000b68, + 0x00000ee9, + 0x00005beb, + 0x000013ea, + 0x00000467, + 0x00001b68, + 0x00000c67, + 0x00002ee9, + 0x00000768, + 0x00001768, + 0x00000f68, + 0x00001ee9, + 0x00001f68, + 0x00003ee9, + 0x000053ea, + 0x000001e9, + 0x000000e8, + 0x000021e9, + 0x000011e9, + 0x000010e8, + 0x000031e9, + 0x000033ea, + 0x000008e8, + 0x0000f7ee, + 0x0004f7ee, + 0x000018e8, + 0x000009e9, + 0x000004e8, + 0x000029e9, + 0x000014e8, + 0x000019e9, + 0x000073ea, + 0x0000dbeb, + 0x00000ce8, + 0x00003beb, + 0x0002f7ee, + 0x000039e9, + 0x00000bea, + 0x000005e9, + 0x00004bea, + 0x000025e9, + 0x000027ec, + 0x000015e9, + 0x000035e9, + 0x00000de9, + 0x00002bea, + 0x000127ec, + 0x0000bbeb, + 0x0006f7ee, + 0x0001f7ee, + 0x0000a7ec, + 0x00007beb, + 0x0005f7ee, + 0x0000fbeb, + 0x0003f7ee, + 0x0007f7ee, + 0x00000fee, + 0x00000326, + 0x00000267, + 0x00000a67, + 0x00000667, + 0x00000726, + 0x00001ce8, + 0x000002e8, + 0x00000e67, + 0x000000a6, + 0x0001a7ec, + 0x00002de9, + 0x000004a6, + 0x00000167, + 0x00000967, + 0x000002a6, + 0x00000567, + 0x000117ed, + 0x000006a6, + 0x000001a6, + 0x000005a6, + 0x00000d67, + 0x000012e8, + 0x00000ae8, + 0x00001de9, + 0x00001ae8, + 0x000007eb, + 0x000317ed, + 0x000067ec, + 0x000097ed, + 0x000297ed, + 0x00040fee, + 0x00020fee, + 0x00060fee, + 0x00010fee, + 0x00050fee, + 0x00030fee, + 0x00070fee, + 0x00008fee, + 0x00048fee, + 0x00028fee, + 0x00068fee, + 0x00018fee, + 0x00058fee, + 0x00038fee, + 0x00078fee, + 0x00004fee, + 0x00044fee, + 0x00024fee, + 0x00064fee, + 0x00014fee, + 0x00054fee, + 0x00034fee, + 0x00074fee, + 0x0000cfee, + 0x0004cfee, + 0x0002cfee, + 0x0006cfee, + 0x0001cfee, + 0x0005cfee, + 0x0003cfee, + 0x0007cfee, + 0x00002fee, + 0x00042fee, + 0x00022fee, + 0x00062fee, + 0x00012fee, + 0x00052fee, + 0x00032fee, + 0x00072fee, + 0x0000afee, + 0x0004afee, + 0x0002afee, + 0x0006afee, + 0x0001afee, + 0x0005afee, + 0x0003afee, + 0x0007afee, + 0x00006fee, + 0x00046fee, + 0x00026fee, + 0x00066fee, + 0x00016fee, + 0x00056fee, + 0x00036fee, + 0x00076fee, + 0x0000efee, + 0x0004efee, + 0x0002efee, + 0x0006efee, + 0x0001efee, + 0x0005efee, + 0x0003efee, + 0x0007efee, + 0x00001fee, + 0x00041fee, + 0x00021fee, + 0x00061fee, + 0x00011fee, + 0x00051fee, + 0x00031fee, + 0x00071fee, + 0x00009fee, + 0x00049fee, + 0x00029fee, + 0x00069fee, + 0x00019fee, + 0x00059fee, + 0x00039fee, + 0x00079fee, + 0x00005fee, + 0x00045fee, + 0x00025fee, + 0x00065fee, + 0x00015fee, + 0x00055fee, + 0x00035fee, + 0x00075fee, + 0x0000dfee, + 0x0004dfee, + 0x0002dfee, + 0x0006dfee, + 0x0001dfee, + 0x0005dfee, + 0x0003dfee, + 0x0007dfee, + 0x00003fee, + 0x00043fee, + 0x00023fee, + 0x00063fee, + 0x00013fee, + 0x00053fee, + 0x00033fee, + 0x00073fee, + 0x0000bfee, + 0x0004bfee, + 0x0002bfee, + 0x0006bfee, + 0x0001bfee, + 0x0005bfee, + 0x0003bfee, + 0x0007bfee, + 0x00007fee, + 0x00047fee, + 0x00027fee, + 0x00067fee, + 0x00017fee, + 0x000197ed, + 0x000397ed, + 0x000057ed, + 0x00057fee, + 0x000257ed, + 0x00037fee, + 0x000157ed, + 0x00077fee, + 0x000357ed, + 0x0000ffee, + 0x0004ffee, + 0x0002ffee, + 0x0006ffee, + 0x0001ffee, + 0x00000084, + 0x00000003, + 0x00000184, + 0x00000044, + 0x00000144, + 0x000000c5, + 0x000002c5, + 0x000001c5, + 0x000003c6, + 0x000007c6, + 0x00000026, + 0x00000426, + 0x000003a7, + 0x00000ba7, + 0x000007a7, + 0x00000fa7, + 0x00000227, + 0x00000627, + 0x00000a27, + 0x00000e27, + 0x00000068, + 0x00000868, + 0x00001068, + 0x00001868, + 0x00000369, + 0x00001369, + 0x00002369, + 0x00003369, + 0x000006ea, + 0x000026ea, + 0x000046ea, + 0x000066ea, + 0x000016eb, + 0x000036eb, + 0x000056eb, + 0x000076eb, + 0x000096eb, + 0x0000b6eb, + 0x0000d6eb, + 0x0000f6eb, + 0x00003dec, + 0x00007dec, + 0x0000bdec, + 0x0000fdec, + 0x00013dec, + 0x00017dec, + 0x0001bdec, + 0x0001fdec, + 0x00006bed, + 0x0000ebed, + 0x00016bed, + 0x0001ebed, + 0x00026bed, + 0x0002ebed, + 0x00036bed, + 0x0003ebed, + 0x000003ec, + 0x000043ec, + 0x000083ec, + 0x0000c3ec, + 0x000103ec, + 0x000143ec, + 0x000183ec, + 0x0001c3ec, + 0x00001bee, + 0x00009bee, + 0x00011bee, + 0x00019bee, + 0x00021bee, + 0x00029bee, + 0x00031bee, + 0x00039bee, + 0x00041bee, + 0x00049bee, + 0x00051bee, + 0x00059bee, + 0x00061bee, + 0x00069bee, + 0x00071bee, + 0x00079bee, + 0x000167f0, + 0x000367f0, + 0x000567f0, + 0x000767f0, + 0x000967f0, + 0x000b67f0, + 0x000d67f0, + 0x000f67f0, + 0x001167f0, + 0x001367f0, + 0x001567f0, + 0x001767f0, + 0x001967f0, + 0x001b67f0, + 0x001d67f0, + 0x001f67f0, + 0x000087ef, + 0x000187ef, + 0x000287ef, + 0x000387ef, + 0x000487ef, + 0x000587ef, + 0x000687ef, + 0x000787ef, + 0x000887ef, + 0x000987ef, + 0x000a87ef, + 0x000b87ef, + 0x000c87ef, + 0x000d87ef, + 0x000e87ef, + 0x000f87ef, + 0x0000e7f0, + 0x0002e7f0, + 0x0004e7f0, + 0x0006e7f0, + 0x0008e7f0, + 0x000ae7f0, + 0x000ce7f0, + 0x000ee7f0, + 0x0010e7f0, + 0x0012e7f0, + 0x0014e7f0, + 0x0016e7f0, + 0x0018e7f0, + 0x001ae7f0, + 0x001ce7f0, + 0x001ee7f0, + 0x0005fff3, + 0x000dfff3, + 0x0015fff3, + 0x001dfff3, + 0x0025fff3, + 0x002dfff3, + 0x0035fff3, + 0x003dfff3, + 0x0045fff3, + 0x004dfff3, + 0x0055fff3, + 0x005dfff3, + 0x0065fff3, + 0x006dfff3, + 0x0075fff3, + 0x007dfff3, + 0x0085fff3, + 0x008dfff3, + 0x0095fff3, + 0x009dfff3, + 0x00a5fff3, + 0x00adfff3, + 0x00b5fff3, + 0x00bdfff3, + 0x00c5fff3, + 0x00cdfff3, + 0x00d5fff3, + 0x00ddfff3, + 0x00e5fff3, + 0x00edfff3, + 0x00f5fff3, + 0x00fdfff3, + 0x0003fff3, + 0x000bfff3, + 0x0013fff3, + 0x001bfff3, + 0x0023fff3, + 0x002bfff3, + 0x0033fff3, + 0x003bfff3, + 0x0043fff3, + 0x004bfff3, + 0x0053fff3, + 0x005bfff3, + 0x0063fff3, + 0x006bfff3, + 0x0073fff3, + 0x007bfff3, + 0x0083fff3, + 0x008bfff3, + 0x0093fff3, + 0x009bfff3, + 0x00a3fff3, + 0x00abfff3, + 0x00b3fff3, + 0x00bbfff3, + 0x00c3fff3, + 0x00cbfff3, + 0x00d3fff3, + 0x00dbfff3, + 0x00e3fff3, + 0x00ebfff3, + 0x00f3fff3, + 0x00fbfff3, + 0x0007fff3, + 0x000ffff3, + 0x0017fff3, + 0x001ffff3, + 0x0027fff3, + 0x002ffff3, + 0x0037fff3, + 0x003ffff3, + 0x0047fff3, + 0x004ffff3, + 0x0057fff3, + 0x005ffff3, + 0x0067fff3, + 0x006ffff3, + 0x0077fff3, + 0x007ffff3, + 0x0087fff3, + 0x008ffff3, + 0x0097fff3, + 0x009ffff3, + 0x00a7fff3, + 0x00affff3, + 0x00b7fff3, + 0x00bffff3, + 0x00c7fff3, + 0x00cffff3, + 0x00d7fff3, + 0x00dffff3, + 0x00e7fff3, + 0x00effff3, + 0x00f7fff3, + 0x00fffff3, + 0x0001e7f1, + 0x0003e7f1, + 0x0005e7f1, + 0x0007e7f1, + 0x0009e7f1, + 0x000be7f1, + 0x000de7f1, + 0x000fe7f1, + 0x0011e7f1, + 0x0013e7f1, + 0x0015e7f1, + 0x0017e7f1, + 0x0019e7f1, + 0x001be7f1, + 0x001de7f1, + 0x001fe7f1, + 0x0021e7f1, + 0x0023e7f1, + 0x0025e7f1, + 0x0027e7f1, + 0x0029e7f1, + 0x002be7f1, + 0x002de7f1, + 0x002fe7f1, + 0x0031e7f1, + 0x0033e7f1, + 0x0035e7f1, + 0x0037e7f1, + 0x0039e7f1, + 0x003be7f1, + 0x003de7f1, + 0x000047eb }; internal static readonly uint[] FAST_ENCODER_DISTANCE_CODE_INFO = { - 0x00000f06,0x0001ff0a,0x0003ff0b,0x0007ff0b,0x0000ff19,0x00003f18,0x0000bf28, - 0x00007f28,0x00001f37,0x00005f37,0x00000d45,0x00002f46,0x00000054,0x00001d55, - 0x00000864,0x00000365,0x00000474,0x00001375,0x00000c84,0x00000284,0x00000a94, - 0x00000694,0x00000ea4,0x000001a4,0x000009b4,0x00000bb5,0x000005c4,0x00001bc5, - 0x000007d5,0x000017d5,0x00000000,0x00000100 + 0x00000f06, + 0x0001ff0a, + 0x0003ff0b, + 0x0007ff0b, + 0x0000ff19, + 0x00003f18, + 0x0000bf28, + 0x00007f28, + 0x00001f37, + 0x00005f37, + 0x00000d45, + 0x00002f46, + 0x00000054, + 0x00001d55, + 0x00000864, + 0x00000365, + 0x00000474, + 0x00001375, + 0x00000c84, + 0x00000284, + 0x00000a94, + 0x00000694, + 0x00000ea4, + 0x000001a4, + 0x000009b4, + 0x00000bb5, + 0x000005c4, + 0x00001bc5, + 0x000007d5, + 0x000017d5, + 0x00000000, + 0x00000100 }; - internal static readonly uint[] BIT_MASK = { 0, 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191, 16383, 32767 }; - internal static readonly byte[] EXTRA_LENGTH_BITS = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 }; - internal static readonly byte[] EXTRA_DISTANCE_BITS = { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 0, 0 }; + internal static readonly uint[] BIT_MASK = + { + 0, + 1, + 3, + 7, + 15, + 31, + 63, + 127, + 255, + 511, + 1023, + 2047, + 4095, + 8191, + 16383, + 32767 + }; + internal static readonly byte[] EXTRA_LENGTH_BITS = + { + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 4, + 4, + 4, + 4, + 5, + 5, + 5, + 5, + 0 + }; + internal static readonly byte[] EXTRA_DISTANCE_BITS = + { + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 2, + 3, + 3, + 4, + 4, + 5, + 5, + 6, + 6, + 7, + 7, + 8, + 8, + 9, + 9, + 10, + 10, + 11, + 11, + 12, + 12, + 13, + 13, + 0, + 0 + }; internal const int NUM_CHARS = 256; internal const int NUM_LENGTH_BASE_CODES = 29; internal const int NUM_DIST_BASE_CODES = 30; diff --git a/src/SharpCompress/Compressors/Deflate64/HuffmanTree.cs b/src/SharpCompress/Compressors/Deflate64/HuffmanTree.cs index 017c1cb9..eac0ff5f 100644 --- a/src/SharpCompress/Compressors/Deflate64/HuffmanTree.cs +++ b/src/SharpCompress/Compressors/Deflate64/HuffmanTree.cs @@ -42,17 +42,20 @@ namespace SharpCompress.Compressors.Deflate64 private readonly int _tableMask; // huffman tree for static block - public static HuffmanTree StaticLiteralLengthTree { get; } = new HuffmanTree(GetStaticLiteralTreeLength()); + public static HuffmanTree StaticLiteralLengthTree { get; } = + new HuffmanTree(GetStaticLiteralTreeLength()); - public static HuffmanTree StaticDistanceTree { get; } = new HuffmanTree(GetStaticDistanceTreeLength()); + public static HuffmanTree StaticDistanceTree { get; } = + new HuffmanTree(GetStaticDistanceTreeLength()); public HuffmanTree(byte[] codeLengths) { Debug.Assert( - codeLengths.Length == MAX_LITERAL_TREE_ELEMENTS || - codeLengths.Length == MAX_DIST_TREE_ELEMENTS || - codeLengths.Length == NUMBER_OF_CODE_LENGTH_TREE_ELEMENTS, - "we only expect three kinds of Length here"); + codeLengths.Length == MAX_LITERAL_TREE_ELEMENTS + || codeLengths.Length == MAX_DIST_TREE_ELEMENTS + || codeLengths.Length == NUMBER_OF_CODE_LENGTH_TREE_ELEMENTS, + "we only expect three kinds of Length here" + ); _codeLengthArray = codeLengths; if (_codeLengthArray.Length == MAX_LITERAL_TREE_ELEMENTS) @@ -124,7 +127,7 @@ namespace SharpCompress.Compressors.Deflate64 { bitLengthCount[codeLength]++; } - bitLengthCount[0] = 0; // clear count for length 0 + bitLengthCount[0] = 0; // clear count for length 0 Span nextCode = stackalloc uint[17]; uint tempCode = 0; @@ -236,7 +239,10 @@ namespace SharpCompress.Compressors.Deflate64 throw new InvalidDataException("Deflate64: invalid Huffman data"); } - Debug.Assert(value < 0, "CreateTable: Only negative numbers are used for tree pointers!"); + Debug.Assert( + value < 0, + "CreateTable: Only negative numbers are used for tree pointers!" + ); if ((start & codeBitMask) == 0) { @@ -272,14 +278,14 @@ namespace SharpCompress.Compressors.Deflate64 // input buffer. uint bitBuffer = input.TryLoad16Bits(); if (input.AvailableBits == 0) - { // running out of input. + { // running out of input. return -1; } // decode an element int symbol = _table[bitBuffer & _tableMask]; if (symbol < 0) - { // this will be the start of the binary tree + { // this will be the start of the binary tree // navigate the tree uint mask = (uint)1 << _tableBits; do diff --git a/src/SharpCompress/Compressors/Deflate64/InflaterManaged.cs b/src/SharpCompress/Compressors/Deflate64/InflaterManaged.cs index de9b78d5..3864ff44 100644 --- a/src/SharpCompress/Compressors/Deflate64/InflaterManaged.cs +++ b/src/SharpCompress/Compressors/Deflate64/InflaterManaged.cs @@ -39,28 +39,153 @@ namespace SharpCompress.Compressors.Deflate64 // const tables used in decoding: // Extra bits for length code 257 - 285. - private static ReadOnlySpan S_EXTRA_LENGTH_BITS => new byte[] - { 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,16 }; + private static ReadOnlySpan S_EXTRA_LENGTH_BITS => + new byte[] + { + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 4, + 4, + 4, + 4, + 5, + 5, + 5, + 5, + 16 + }; // The base length for length code 257 - 285. // The formula to get the real length for a length code is lengthBase[code - 257] + (value stored in extraBits) private static readonly int[] S_LENGTH_BASE = - { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,3}; + { + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 13, + 15, + 17, + 19, + 23, + 27, + 31, + 35, + 43, + 51, + 59, + 67, + 83, + 99, + 115, + 131, + 163, + 195, + 227, + 3 + }; // The base distance for distance code 0 - 31 // The real distance for a distance code is distanceBasePosition[code] + (value stored in extraBits) private static readonly int[] S_DISTANCE_BASE_POSITION = - { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,32769,49153 }; + { + 1, + 2, + 3, + 4, + 5, + 7, + 9, + 13, + 17, + 25, + 33, + 49, + 65, + 97, + 129, + 193, + 257, + 385, + 513, + 769, + 1025, + 1537, + 2049, + 3073, + 4097, + 6145, + 8193, + 12289, + 16385, + 24577, + 32769, + 49153 + }; // code lengths for code length alphabet is stored in following order - private static ReadOnlySpan S_CODE_ORDER => new byte[] { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; + private static ReadOnlySpan S_CODE_ORDER => + new byte[] { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; - private static ReadOnlySpan S_STATIC_DISTANCE_TREE_TABLE => new byte[] - { - 0x00,0x10,0x08,0x18,0x04,0x14,0x0c,0x1c,0x02,0x12,0x0a,0x1a, - 0x06,0x16,0x0e,0x1e,0x01,0x11,0x09,0x19,0x05,0x15,0x0d,0x1d, - 0x03,0x13,0x0b,0x1b,0x07,0x17,0x0f,0x1f - }; + private static ReadOnlySpan S_STATIC_DISTANCE_TREE_TABLE => + new byte[] + { + 0x00, + 0x10, + 0x08, + 0x18, + 0x04, + 0x14, + 0x0c, + 0x1c, + 0x02, + 0x12, + 0x0a, + 0x1a, + 0x06, + 0x16, + 0x0e, + 0x1e, + 0x01, + 0x11, + 0x09, + 0x19, + 0x05, + 0x15, + 0x0d, + 0x1d, + 0x03, + 0x13, + 0x0b, + 0x1b, + 0x07, + 0x17, + 0x0f, + 0x1f + }; private readonly OutputWindow _output; private readonly InputBuffer _input; @@ -68,6 +193,7 @@ namespace SharpCompress.Compressors.Deflate64 private HuffmanTree _distanceTree; private InflaterState _state; + //private bool _hasFormatReader; private int _bfinal; private BlockType _blockType; @@ -95,12 +221,16 @@ namespace SharpCompress.Compressors.Deflate64 //private IFileFormatReader _formatReader; // class to decode header and footer (e.g. gzip) - internal InflaterManaged(/*IFileFormatReader reader, */bool deflate64) + internal InflaterManaged( /*IFileFormatReader reader, */ + bool deflate64 + ) { _output = new OutputWindow(); _input = new InputBuffer(); - _codeList = new byte[HuffmanTree.MAX_LITERAL_TREE_ELEMENTS + HuffmanTree.MAX_DIST_TREE_ELEMENTS]; + _codeList = new byte[ + HuffmanTree.MAX_LITERAL_TREE_ELEMENTS + HuffmanTree.MAX_DIST_TREE_ELEMENTS + ]; _codeLengthTreeCodeLength = new byte[HuffmanTree.NUMBER_OF_CODE_LENGTH_TREE_ELEMENTS]; _deflate64 = deflate64; //if (reader != null) @@ -114,14 +244,15 @@ namespace SharpCompress.Compressors.Deflate64 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 - public bool Finished() => _state == InflaterState.Done || _state == InflaterState.VerifyingFooter; + public bool Finished() => + _state == InflaterState.Done || _state == InflaterState.VerifyingFooter; public int AvailableOutput => _output.AvailableBytes; @@ -147,14 +278,14 @@ namespace SharpCompress.Compressors.Deflate64 } if (length == 0) - { // filled in the bytes array + { // filled in the bytes array break; } // Decode will return false when more input is needed } while (!Finished() && Decode()); if (_state == InflaterState.VerifyingFooter) - { // finished reading CRC + { // finished reading CRC // In this case finished is true and output window has all the data. // But some data in output window might not be copied out. if (_output.AvailableBytes == 0) @@ -299,7 +430,6 @@ namespace SharpCompress.Compressors.Deflate64 return result; } - // Format of Non-compressed blocks (BTYPE=00): // // Any bits of input up to the next byte boundary are ignored. @@ -320,12 +450,12 @@ namespace SharpCompress.Compressors.Deflate64 switch (_state) { case InflaterState.UncompressedAligning: // initial state when calling this function - // we must skip to a byte boundary + // we must skip to a byte boundary _input.SkipToByteBoundary(); _state = InflaterState.UncompressedByte1; goto case InflaterState.UncompressedByte1; - case InflaterState.UncompressedByte1: // decoding block length + case InflaterState.UncompressedByte1: // decoding block length case InflaterState.UncompressedByte2: case InflaterState.UncompressedByte3: case InflaterState.UncompressedByte4: @@ -338,8 +468,10 @@ namespace SharpCompress.Compressors.Deflate64 _blockLengthBuffer[_state - InflaterState.UncompressedByte1] = (byte)bits; if (_state == InflaterState.UncompressedByte4) { - _blockLength = _blockLengthBuffer[0] + ((int)_blockLengthBuffer[1]) * 256; - int blockLengthComplement = _blockLengthBuffer[2] + ((int)_blockLengthBuffer[3]) * 256; + _blockLength = + _blockLengthBuffer[0] + ((int)_blockLengthBuffer[1]) * 256; + int blockLengthComplement = + _blockLengthBuffer[2] + ((int)_blockLengthBuffer[3]) * 256; // make sure complement matches if ((ushort)_blockLength != (ushort)(~blockLengthComplement)) @@ -376,7 +508,8 @@ namespace SharpCompress.Compressors.Deflate64 return false; default: - Debug./*Fail*/Assert(false, "check why we are here!"); + Debug. /*Fail*/ + Assert(false, "check why we are here!"); throw new InvalidDataException("Deflate64: unknown state"); } } @@ -386,7 +519,7 @@ namespace SharpCompress.Compressors.Deflate64 { endOfBlockCodeSeen = false; - int freeBytes = _output.FreeBytes; // it is a little bit faster than frequently accessing the property + int freeBytes = _output.FreeBytes; // it is a little bit faster than frequently accessing the property while (freeBytes > 65536) { // With Deflate64 we can have up to a 64kb length, so we ensure at least that much space is available @@ -423,16 +556,16 @@ namespace SharpCompress.Compressors.Deflate64 else { // length/distance pair - symbol -= 257; // length code started at 257 + symbol -= 257; // length code started at 257 if (symbol < 8) { - symbol += 3; // match length = 3,4,5,6,7,8,9,10 + symbol += 3; // match length = 3,4,5,6,7,8,9,10 _extraBits = 0; } else if (!_deflate64 && symbol == 28) { // extra bits for code 285 is 0 - symbol = 258; // code 285 means length 258 + symbol = 258; // code 285 means length 258 _extraBits = 0; } else @@ -517,7 +650,8 @@ namespace SharpCompress.Compressors.Deflate64 break; default: - Debug./*Fail*/Assert(false, "check why we are here!"); + Debug. /*Fail*/ + Assert(false, "check why we are here!"); throw new InvalidDataException("Deflate64: unknown state"); } } @@ -525,7 +659,6 @@ namespace SharpCompress.Compressors.Deflate64 return true; } - // Format of the dynamic block header: // 5 Bits: HLIT, # of Literal/Length codes - 257 (257 - 286) // 5 Bits: HDIST, # of Distance codes - 1 (1 - 32) @@ -714,7 +847,8 @@ namespace SharpCompress.Compressors.Deflate64 break; default: - Debug./*Fail*/Assert(false, "check why we are here!"); + Debug. /*Fail*/ + Assert(false, "check why we are here!"); throw new InvalidDataException("Deflate64: unknown state"); } @@ -723,7 +857,13 @@ namespace SharpCompress.Compressors.Deflate64 // Create literal and distance tables Array.Copy(_codeList, literalTreeCodeLength, _literalLengthCodeCount); - Array.Copy(_codeList, _literalLengthCodeCount, distanceTreeCodeLength, 0, _distanceCodeCount); + Array.Copy( + _codeList, + _literalLengthCodeCount, + distanceTreeCodeLength, + 0, + _distanceCodeCount + ); // Make sure there is an end-of-block code, otherwise how could we ever end? if (literalTreeCodeLength[HuffmanTree.END_OF_BLOCK_CODE] == 0) diff --git a/src/SharpCompress/Compressors/Deflate64/InflaterState.cs b/src/SharpCompress/Compressors/Deflate64/InflaterState.cs index 356ea88f..64450931 100644 --- a/src/SharpCompress/Compressors/Deflate64/InflaterState.cs +++ b/src/SharpCompress/Compressors/Deflate64/InflaterState.cs @@ -7,22 +7,22 @@ namespace SharpCompress.Compressors.Deflate64 // Do not rearrange the enum values. internal enum InflaterState { - ReadingHeader = 0, // Only applies to GZIP + ReadingHeader = 0, // Only applies to GZIP - ReadingBFinal = 2, // About to read bfinal bit - ReadingBType = 3, // About to read blockType bits + ReadingBFinal = 2, // About to read bfinal bit + ReadingBType = 3, // About to read blockType bits - ReadingNumLitCodes = 4, // About to read # literal codes - ReadingNumDistCodes = 5, // About to read # dist codes - ReadingNumCodeLengthCodes = 6, // About to read # code length codes - ReadingCodeLengthCodes = 7, // In the middle of reading the code length codes - ReadingTreeCodesBefore = 8, // In the middle of reading tree codes (loop top) - ReadingTreeCodesAfter = 9, // In the middle of reading tree codes (extension; code > 15) + ReadingNumLitCodes = 4, // About to read # literal codes + ReadingNumDistCodes = 5, // About to read # dist codes + ReadingNumCodeLengthCodes = 6, // About to read # code length codes + ReadingCodeLengthCodes = 7, // In the middle of reading the code length codes + ReadingTreeCodesBefore = 8, // In the middle of reading tree codes (loop top) + ReadingTreeCodesAfter = 9, // In the middle of reading tree codes (extension; code > 15) - DecodeTop = 10, // About to decode a literal (char/match) in a compressed block - HaveInitialLength = 11, // Decoding a match, have the literal code (base length) - HaveFullLength = 12, // Ditto, now have the full match length (incl. extra length bits) - HaveDistCode = 13, // Ditto, now have the distance code also, need extra dist bits + DecodeTop = 10, // About to decode a literal (char/match) in a compressed block + HaveInitialLength = 11, // Decoding a match, have the literal code (base length) + HaveFullLength = 12, // Ditto, now have the full match length (incl. extra length bits) + HaveDistCode = 13, // Ditto, now have the distance code also, need extra dist bits /* uncompressed blocks */ UncompressedAligning = 15, @@ -33,7 +33,7 @@ namespace SharpCompress.Compressors.Deflate64 DecodingUncompressed = 20, // These three apply only to GZIP - StartReadingFooter = 21, // (Initialisation for reading footer) + StartReadingFooter = 21, // (Initialisation for reading footer) ReadingFooter = 22, VerifyingFooter = 23, diff --git a/src/SharpCompress/Compressors/Deflate64/InputBuffer.cs b/src/SharpCompress/Compressors/Deflate64/InputBuffer.cs index 931a22fa..a7357565 100644 --- a/src/SharpCompress/Compressors/Deflate64/InputBuffer.cs +++ b/src/SharpCompress/Compressors/Deflate64/InputBuffer.cs @@ -21,11 +21,11 @@ namespace SharpCompress.Compressors.Deflate64 internal sealed class InputBuffer { - private byte[] _buffer; // byte array to store input - private int _start; // start poisition of the buffer - private int _end; // end position of the buffer - private uint _bitBuffer = 0; // store the bits here, we can quickly shift in this buffer - private int _bitsInBuffer = 0; // number of bits available in bitBuffer + private byte[] _buffer; // byte array to store input + private int _start; // start poisition of the buffer + private int _end; // end position of the buffer + private uint _bitBuffer = 0; // store the bits here, we can quickly shift in this buffer + private int _bitsInBuffer = 0; // number of bits available in bitBuffer /// Total bits available in the input buffer. public int AvailableBits => _bitsInBuffer; @@ -189,7 +189,10 @@ namespace SharpCompress.Compressors.Deflate64 /// Skip n bits in the buffer. public void SkipBits(int n) { - Debug.Assert(_bitsInBuffer >= n, "No enough bits in the buffer, Did you call EnsureBitsAvailable?"); + Debug.Assert( + _bitsInBuffer >= n, + "No enough bits in the buffer, Did you call EnsureBitsAvailable?" + ); _bitBuffer >>= n; _bitsInBuffer -= n; } diff --git a/src/SharpCompress/Compressors/Deflate64/OutputWindow.cs b/src/SharpCompress/Compressors/Deflate64/OutputWindow.cs index 13bf90c2..d48cd5fb 100644 --- a/src/SharpCompress/Compressors/Deflate64/OutputWindow.cs +++ b/src/SharpCompress/Compressors/Deflate64/OutputWindow.cs @@ -17,13 +17,13 @@ namespace SharpCompress.Compressors.Deflate64 internal sealed class OutputWindow { // With Deflate64 we can have up to a 65536 length as well as up to a 65538 distance. This means we need a Window that is at - // least 131074 bytes long so we have space to retrieve up to a full 64kb in lookback and place it in our buffer without + // least 131074 bytes long so we have space to retrieve up to a full 64kb in lookback and place it in our buffer without // overwriting existing data. OutputWindow requires that the WindowSize be an exponent of 2, so we round up to 2^18. private const int WINDOW_SIZE = 262144; private const int WINDOW_MASK = 262143; private readonly byte[] _window = new byte[WINDOW_SIZE]; // The window is 2^18 bytes - private int _end; // this is the position to where we should write next byte + private int _end; // this is the position to where we should write next byte private int _bytesUsed; // The number of bytes in the output window which is not consumed. /// Add a byte to output window. @@ -137,14 +137,16 @@ namespace SharpCompress.Compressors.Deflate64 { // this means we need to copy two parts separately // copy tailLen bytes from the end of output window - Array.Copy(_window, WINDOW_SIZE - tailLen, - output, offset, tailLen); + Array.Copy(_window, WINDOW_SIZE - tailLen, output, offset, tailLen); offset += tailLen; length = copyEnd; } Array.Copy(_window, copyEnd - length, output, offset, length); _bytesUsed -= copied; - Debug.Assert(_bytesUsed >= 0, "check this function and find why we copied more bytes than we have"); + Debug.Assert( + _bytesUsed >= 0, + "check this function and find why we copied more bytes than we have" + ); return copied; } } diff --git a/src/SharpCompress/Compressors/Filters/BCJ2Filter.cs b/src/SharpCompress/Compressors/Filters/BCJ2Filter.cs index d767cd6c..636f5dc0 100644 --- a/src/SharpCompress/Compressors/Filters/BCJ2Filter.cs +++ b/src/SharpCompress/Compressors/Filters/BCJ2Filter.cs @@ -25,7 +25,8 @@ namespace SharpCompress.Compressors.Filters private int _data2Pos; private readonly ushort[] _p = new ushort[256 + 2]; - private uint _range, _code; + private uint _range, + _code; private byte _prevByte; private bool _isDisposed; @@ -91,7 +92,11 @@ namespace SharpCompress.Compressors.Filters public override long Length => _baseStream.Length + _data1.Length + _data2.Length; - public override long Position { get => _position; set => throw new NotSupportedException(); } + public override long Position + { + get => _position; + set => throw new NotSupportedException(); + } public override int Read(byte[] buffer, int offset, int count) { @@ -176,17 +181,21 @@ namespace SharpCompress.Compressors.Filters uint dest; if (b == 0xE8) { - dest = - (uint) - ((_data1[_data1Pos++] << 24) | (_data1[_data1Pos++] << 16) | (_data1[_data1Pos++] << 8) | - _data1[_data1Pos++]); + dest = (uint)( + (_data1[_data1Pos++] << 24) + | (_data1[_data1Pos++] << 16) + | (_data1[_data1Pos++] << 8) + | _data1[_data1Pos++] + ); } else { - dest = - (uint) - ((_data2[_data2Pos++] << 24) | (_data2[_data2Pos++] << 16) | (_data2[_data2Pos++] << 8) | - _data2[_data2Pos++]); + dest = (uint)( + (_data2[_data2Pos++] << 24) + | (_data2[_data2Pos++] << 16) + | (_data2[_data2Pos++] << 8) + | _data2[_data2Pos++] + ); } dest -= (uint)(_position + 4); @@ -218,4 +227,4 @@ namespace SharpCompress.Compressors.Filters throw new NotSupportedException(); } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/Filters/BCJFilter.cs b/src/SharpCompress/Compressors/Filters/BCJFilter.cs index 4bc6bb2e..57b025a8 100644 --- a/src/SharpCompress/Compressors/Filters/BCJFilter.cs +++ b/src/SharpCompress/Compressors/Filters/BCJFilter.cs @@ -4,15 +4,24 @@ namespace SharpCompress.Compressors.Filters { internal class BCJFilter : Filter { - private static readonly bool[] MASK_TO_ALLOWED_STATUS = { true, true, true, false, true, false, false, false }; + private static readonly bool[] MASK_TO_ALLOWED_STATUS = + { + true, + true, + true, + false, + true, + false, + false, + false + }; private static readonly int[] MASK_TO_BIT_NUMBER = { 0, 1, 2, 2, 3, 3, 3, 3 }; private int _pos; private int _prevMask; - public BCJFilter(bool isEncoder, Stream baseStream) - : base(isEncoder, baseStream, 5) + public BCJFilter(bool isEncoder, Stream baseStream) : base(isEncoder, baseStream, 5) { _pos = 5; } @@ -46,8 +55,10 @@ namespace SharpCompress.Compressors.Filters _prevMask = (_prevMask << (prevPos - 1)) & 7; if (_prevMask != 0) { - if (!MASK_TO_ALLOWED_STATUS[_prevMask] || Test86MsByte( - buffer[i + 4 - MASK_TO_BIT_NUMBER[_prevMask]])) + if ( + !MASK_TO_ALLOWED_STATUS[_prevMask] + || Test86MsByte(buffer[i + 4 - MASK_TO_BIT_NUMBER[_prevMask]]) + ) { prevPos = i; _prevMask = (_prevMask << 1) | 1; @@ -60,10 +71,11 @@ namespace SharpCompress.Compressors.Filters if (Test86MsByte(buffer[i + 4])) { - int src = buffer[i + 1] - | (buffer[i + 2] << 8) - | (buffer[i + 3] << 16) - | (buffer[i + 4] << 24); + int src = + buffer[i + 1] + | (buffer[i + 2] << 8) + | (buffer[i + 3] << 16) + | (buffer[i + 4] << 24); int dest; while (true) { @@ -110,4 +122,4 @@ namespace SharpCompress.Compressors.Filters return i; } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/Filters/BranchExecFilter.cs b/src/SharpCompress/Compressors/Filters/BranchExecFilter.cs index 02f92ac5..6e8278cb 100644 --- a/src/SharpCompress/Compressors/Filters/BranchExecFilter.cs +++ b/src/SharpCompress/Compressors/Filters/BranchExecFilter.cs @@ -26,8 +26,8 @@ namespace SharpCompress.Compressors.Filters ARCH_SPARC_ALIGNMENT = 4, } - public static void X86Converter(byte[] data, UInt32 ip, ref UInt32 state) { - + public static void X86Converter(byte[] data, UInt32 ip, ref UInt32 state) + { long i = 0; long size = data.Length; UInt32 pos = 0; @@ -36,11 +36,11 @@ namespace SharpCompress.Compressors.Filters return; size -= 4; ip += 5; - - for (;;) + + for (; ; ) { i = pos; - + for (; i < size; i++) { if ((data[i] & 0xFE) == 0xE8) @@ -63,17 +63,28 @@ namespace SharpCompress.Compressors.Filters else { mask >>= (int)d; - if (mask != 0 && (mask > 4 || mask == 3 || (((((data[(UInt32)(mask >> 1) + 1])) + 1) & 0xFE) == 0) )) + if ( + mask != 0 + && ( + mask > 4 + || mask == 3 + || (((((data[(UInt32)(mask >> 1) + 1])) + 1) & 0xFE) == 0) + ) + ) { mask = (mask >> 1) | 4; pos++; continue; } } - + if ((((data[i + 4]) + 1) & 0xFE) == 0) { - UInt32 inst = ((UInt32)data[i + 4] << 24) | ((UInt32)data[i + 3] << 16) | ((UInt32)data[i + 2] << 8) | ((UInt32)data[i + 1]); + UInt32 inst = + ((UInt32)data[i + 4] << 24) + | ((UInt32)data[i + 3] << 16) + | ((UInt32)data[i + 2] << 8) + | ((UInt32)data[i + 1]); UInt32 cur = ip + (UInt32)pos; pos += 5; @@ -108,9 +119,9 @@ namespace SharpCompress.Compressors.Filters size &= ~(UInt32)3; ip -= 4; - for (;; ) // infinite loop + for (; ; ) // infinite loop { - for (;; ) // infinite loop + for (; ; ) // infinite loop { if (i >= size) return; @@ -143,9 +154,9 @@ namespace SharpCompress.Compressors.Filters size &= ~(UInt32)3; ip += 4; - for (;;) // infinite loop + for (; ; ) // infinite loop { - for (;;) // infinite loop + for (; ; ) // infinite loop { if (i >= size) { @@ -175,10 +186,10 @@ namespace SharpCompress.Compressors.Filters size &= ~(UInt32)1; long lim = size - 4; - for (;;) + for (; ; ) { UInt32 b1; - for (;;) + for (; ; ) { UInt32 b3; if (i > lim) @@ -191,21 +202,21 @@ namespace SharpCompress.Compressors.Filters break; } - UInt32 inst = ((UInt32)b1 << 19) - + (((UInt32)data[i + 1] & 0x7) << 8) - + (((UInt32)data[i - 2] << 11)) - + (data[i]); - - i += 2; + UInt32 inst = + ((UInt32)b1 << 19) + + (((UInt32)data[i + 1] & 0x7) << 8) + + (((UInt32)data[i - 2] << 11)) + + (data[i]); - UInt32 cur = ((UInt32)(ip + i)) >> 1; - inst -= cur; + i += 2; - - data[i - 4] = (Byte)(inst >> 11); - data[i - 3] = (Byte)(0xF0 | ((inst >> 19) & 0x7)); - data[i - 2] = (Byte)inst; - data[i - 1] = (Byte)(0xF8 | (inst >> 8)); + UInt32 cur = ((UInt32)(ip + i)) >> 1; + inst -= cur; + + data[i - 4] = (Byte)(inst >> 11); + data[i - 3] = (Byte)(0xF0 | ((inst >> 19) & 0x7)); + data[i - 2] = (Byte)inst; + data[i - 1] = (Byte)(0xF8 | (inst >> 8)); } } @@ -225,9 +236,14 @@ namespace SharpCompress.Compressors.Filters m++; do { - UInt32 iterator = (UInt32)( (i + (m * 5) - 8)); - if (((data[iterator + 3] >> (int)m) & 15) == 5 - && (((data[iterator - 1] | ((UInt32)data[iterator] << 8)) >> (int)m) & 0x70) == 0) + UInt32 iterator = (UInt32)((i + (m * 5) - 8)); + if ( + ((data[iterator + 3] >> (int)m) & 15) == 5 + && ( + ((data[iterator - 1] | ((UInt32)data[iterator] << 8)) >> (int)m) + & 0x70 + ) == 0 + ) { UInt32 raw = BitConverter.ToUInt32(data, (int)iterator); UInt32 inst = raw >> (int)m; @@ -245,12 +261,10 @@ namespace SharpCompress.Compressors.Filters Utility.SetLittleUInt32(ref data, raw, iterator); } - } - while (++m <= 4); + } while (++m <= 4); } i += 16; - } - while (i <= size); + } while (i <= size); return; } @@ -261,19 +275,21 @@ namespace SharpCompress.Compressors.Filters size &= ~(UInt32)3; ip -= 4; - for (;;) // infinite loop + for (; ; ) // infinite loop { - for (;;) // infinite loop + for (; ; ) // infinite loop { if (i >= size) return; i += 4; - if ((data[i - 4] == 0x40 && (data[i - 3] & 0xC0) == 0) || - (data[i - 4] == 0x7F && (data[i - 3] >= 0xC0))) + if ( + (data[i - 4] == 0x40 && (data[i - 3] & 0xC0) == 0) + || (data[i - 4] == 0x7F && (data[i - 3] >= 0xC0)) + ) break; } - + UInt32 inst = BitConverter.ToUInt32(data, (int)i - 4); if (BitConverter.IsLittleEndian) diff --git a/src/SharpCompress/Compressors/Filters/Filter.cs b/src/SharpCompress/Compressors/Filters/Filter.cs index b7fd8159..1ee8c076 100644 --- a/src/SharpCompress/Compressors/Filters/Filter.cs +++ b/src/SharpCompress/Compressors/Filters/Filter.cs @@ -47,7 +47,11 @@ namespace SharpCompress.Compressors.Filters public override long Length => _baseStream.Length; - public override long Position { get => _baseStream.Position; set => throw new NotSupportedException(); } + public override long Position + { + get => _baseStream.Position; + set => throw new NotSupportedException(); + } public override int Read(byte[] buffer, int offset, int count) { @@ -151,4 +155,4 @@ namespace SharpCompress.Compressors.Filters protected abstract int Transform(byte[] buffer, int offset, int count); } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/LZMA/AesDecoderStream.cs b/src/SharpCompress/Compressors/LZMA/AesDecoderStream.cs index 3e44ff89..a3c47462 100644 --- a/src/SharpCompress/Compressors/LZMA/AesDecoderStream.cs +++ b/src/SharpCompress/Compressors/LZMA/AesDecoderStream.cs @@ -22,7 +22,9 @@ namespace SharpCompress.Compressors.LZMA { if (pass.CryptoGetTextPassword() == null) { - throw new SharpCompress.Common.CryptographicException("Encrypted 7Zip archive has no password specified."); + throw new SharpCompress.Common.CryptographicException( + "Encrypted 7Zip archive has no password specified." + ); } mStream = input; @@ -79,8 +81,7 @@ namespace SharpCompress.Compressors.LZMA public override int Read(byte[] buffer, int offset, int count) { - if (count == 0 - || mWritten == mLimit) + if (count == 0 || mWritten == mLimit) { return 0; } @@ -107,8 +108,7 @@ namespace SharpCompress.Compressors.LZMA } mEnding += read; - } - while (mEnding - mOffset < 16); + } while (mEnding - mOffset < 16); } // We shouldn't return more data than we are limited to. diff --git a/src/SharpCompress/Compressors/LZMA/Bcj2DecoderStream.cs b/src/SharpCompress/Compressors/LZMA/Bcj2DecoderStream.cs index 62a7ad65..649801a3 100644 --- a/src/SharpCompress/Compressors/LZMA/Bcj2DecoderStream.cs +++ b/src/SharpCompress/Compressors/LZMA/Bcj2DecoderStream.cs @@ -149,14 +149,12 @@ namespace SharpCompress.Compressors.LZMA private static bool IsJcc(byte b0, byte b1) { - return b0 == 0x0F - && (b1 & 0xF0) == 0x80; + return b0 == 0x0F && (b1 & 0xF0) == 0x80; } private static bool IsJ(byte b0, byte b1) { - return (b1 & 0xFE) == 0xE8 - || IsJcc(b0, b1); + return (b1 & 0xFE) == 0xE8 || IsJcc(b0, b1); } private static int GetIndex(byte b0, byte b1) @@ -280,4 +278,4 @@ namespace SharpCompress.Compressors.LZMA } } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/LZMA/BitVector.cs b/src/SharpCompress/Compressors/LZMA/BitVector.cs index 9f267f72..5995512a 100644 --- a/src/SharpCompress/Compressors/LZMA/BitVector.cs +++ b/src/SharpCompress/Compressors/LZMA/BitVector.cs @@ -28,8 +28,7 @@ namespace SharpCompress.Compressors.LZMA } } - public BitVector(List bits) - : this(bits.Count) + public BitVector(List bits) : this(bits.Count) { for (int i = 0; i < bits.Count; i++) { @@ -98,4 +97,4 @@ namespace SharpCompress.Compressors.LZMA return sb.ToString(); } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/LZMA/CRC.cs b/src/SharpCompress/Compressors/LZMA/CRC.cs index 2ee0600a..478cb944 100644 --- a/src/SharpCompress/Compressors/LZMA/CRC.cs +++ b/src/SharpCompress/Compressors/LZMA/CRC.cs @@ -61,9 +61,9 @@ namespace SharpCompress.Compressors.LZMA { crc ^= value; return TABLE[0x300 + (crc & 0xFF)] - ^ TABLE[0x200 + ((crc >> 8) & 0xFF)] - ^ TABLE[0x100 + ((crc >> 16) & 0xFF)] - ^ TABLE[0x000 + (crc >> 24)]; + ^ TABLE[0x200 + ((crc >> 8) & 0xFF)] + ^ TABLE[0x100 + ((crc >> 16) & 0xFF)] + ^ TABLE[0x000 + (crc >> 24)]; } public static uint Update(uint crc, ulong value) @@ -86,4 +86,4 @@ namespace SharpCompress.Compressors.LZMA return crc; } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/LZMA/DecoderStream.cs b/src/SharpCompress/Compressors/LZMA/DecoderStream.cs index 1921ebab..084e2a5f 100644 --- a/src/SharpCompress/Compressors/LZMA/DecoderStream.cs +++ b/src/SharpCompress/Compressors/LZMA/DecoderStream.cs @@ -21,7 +21,11 @@ namespace SharpCompress.Compressors.LZMA public override long Length => throw new NotSupportedException(); - public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); } + public override long Position + { + get => throw new NotSupportedException(); + set => throw new NotSupportedException(); + } public override long Seek(long offset, SeekOrigin origin) { @@ -56,20 +60,27 @@ namespace SharpCompress.Compressors.LZMA throw new InvalidOperationException("Could not link output stream to coder."); } - private static void FindPrimaryOutStreamIndex(CFolder folderInfo, out int primaryCoderIndex, - out int primaryOutStreamIndex) + private static void FindPrimaryOutStreamIndex( + CFolder folderInfo, + out int primaryCoderIndex, + out int primaryOutStreamIndex + ) { bool foundPrimaryOutStream = false; primaryCoderIndex = -1; primaryOutStreamIndex = -1; - for (int outStreamIndex = 0, coderIndex = 0; - coderIndex < folderInfo._coders.Count; - coderIndex++) + for ( + int outStreamIndex = 0, coderIndex = 0; + coderIndex < folderInfo._coders.Count; + coderIndex++ + ) { - for (int coderOutStreamIndex = 0; - coderOutStreamIndex < folderInfo._coders[coderIndex]._numOutStreams; - coderOutStreamIndex++, outStreamIndex++) + for ( + int coderOutStreamIndex = 0; + coderOutStreamIndex < folderInfo._coders[coderIndex]._numOutStreams; + coderOutStreamIndex++, outStreamIndex++ + ) { if (folderInfo.FindBindPairForOutStream(outStreamIndex) < 0) { @@ -91,8 +102,14 @@ namespace SharpCompress.Compressors.LZMA } } - private static Stream CreateDecoderStream(Stream[] packStreams, long[] packSizes, Stream[] outStreams, - CFolder folderInfo, int coderIndex, IPasswordProvider pass) + private static Stream CreateDecoderStream( + Stream[] packStreams, + long[] packSizes, + Stream[] outStreams, + CFolder folderInfo, + int coderIndex, + IPasswordProvider pass + ) { var coderInfo = folderInfo._coders[coderIndex]; if (coderInfo._numOutStreams != 1) @@ -123,18 +140,31 @@ namespace SharpCompress.Compressors.LZMA if (outStreams[pairedOutIndex] != null) { - throw new NotSupportedException("Overlapping stream bindings are not supported."); + throw new NotSupportedException( + "Overlapping stream bindings are not supported." + ); } - int otherCoderIndex = FindCoderIndexForOutStreamIndex(folderInfo, pairedOutIndex); - inStreams[i] = CreateDecoderStream(packStreams, packSizes, outStreams, folderInfo, otherCoderIndex, - pass); + int otherCoderIndex = FindCoderIndexForOutStreamIndex( + folderInfo, + pairedOutIndex + ); + inStreams[i] = CreateDecoderStream( + packStreams, + packSizes, + outStreams, + folderInfo, + otherCoderIndex, + pass + ); //inStreamSizes[i] = folderInfo.UnpackSizes[pairedOutIndex]; if (outStreams[pairedOutIndex] != null) { - throw new NotSupportedException("Overlapping stream bindings are not supported."); + throw new NotSupportedException( + "Overlapping stream bindings are not supported." + ); } outStreams[pairedOutIndex] = inStreams[i]; @@ -154,11 +184,22 @@ namespace SharpCompress.Compressors.LZMA } long unpackSize = folderInfo._unpackSizes[outStreamId]; - return DecoderRegistry.CreateDecoderStream(coderInfo._methodId, inStreams, coderInfo._props, pass, unpackSize); + return DecoderRegistry.CreateDecoderStream( + coderInfo._methodId, + inStreams, + coderInfo._props, + pass, + unpackSize + ); } - internal static Stream CreateDecoderStream(Stream inStream, long startPos, long[] packSizes, CFolder folderInfo, - IPasswordProvider pass) + internal static Stream CreateDecoderStream( + Stream inStream, + long startPos, + long[] packSizes, + CFolder folderInfo, + IPasswordProvider pass + ) { if (!folderInfo.CheckStructure()) { @@ -174,9 +215,17 @@ namespace SharpCompress.Compressors.LZMA Stream[] outStreams = new Stream[folderInfo._unpackSizes.Count]; - int primaryCoderIndex, primaryOutStreamIndex; + int primaryCoderIndex, + primaryOutStreamIndex; FindPrimaryOutStreamIndex(folderInfo, out primaryCoderIndex, out primaryOutStreamIndex); - return CreateDecoderStream(inStreams, packSizes, outStreams, folderInfo, primaryCoderIndex, pass); + return CreateDecoderStream( + inStreams, + packSizes, + outStreams, + folderInfo, + primaryCoderIndex, + pass + ); } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/LZMA/ICoder.cs b/src/SharpCompress/Compressors/LZMA/ICoder.cs index 3ae84f48..a571ddc5 100644 --- a/src/SharpCompress/Compressors/LZMA/ICoder.cs +++ b/src/SharpCompress/Compressors/LZMA/ICoder.cs @@ -8,10 +8,7 @@ namespace SharpCompress.Compressors.LZMA /// internal class DataErrorException : Exception { - public DataErrorException() - : base("Data Error") - { - } + public DataErrorException() : base("Data Error") { } } /// @@ -19,10 +16,7 @@ namespace SharpCompress.Compressors.LZMA /// internal class InvalidParamException : Exception { - public InvalidParamException() - : base("Invalid Parameter") - { - } + public InvalidParamException() : base("Invalid Parameter") { } } public interface ICodeProgress @@ -59,16 +53,21 @@ namespace SharpCompress.Compressors.LZMA /// /// callback progress reference. /// - void Code(Stream inStream, Stream outStream, - Int64 inSize, Int64 outSize, ICodeProgress progress); + void Code( + Stream inStream, + Stream outStream, + Int64 inSize, + Int64 outSize, + ICodeProgress progress + ); } /* public interface ICoder2 { void Code(ISequentialInStream []inStreams, - const UInt64 []inSizes, - ISequentialOutStream []outStreams, + const UInt64 []inSizes, + ISequentialOutStream []outStreams, UInt64 []outSizes, ICodeProgress progress); }; diff --git a/src/SharpCompress/Compressors/LZMA/LZ/LzBinTree.cs b/src/SharpCompress/Compressors/LZMA/LZ/LzBinTree.cs index 37c70720..6d630b59 100644 --- a/src/SharpCompress/Compressors/LZMA/LZ/LzBinTree.cs +++ b/src/SharpCompress/Compressors/LZMA/LZ/LzBinTree.cs @@ -98,8 +98,12 @@ namespace SharpCompress.Compressors.LZMA.LZ return base.GetNumAvailableBytes(); } - public void Create(UInt32 historySize, UInt32 keepAddBufferBefore, - UInt32 matchMaxLen, UInt32 keepAddBufferAfter) + public void Create( + UInt32 historySize, + UInt32 keepAddBufferBefore, + UInt32 matchMaxLen, + UInt32 keepAddBufferAfter + ) { if (historySize > K_MAX_VAL_FOR_NORMALIZE - 256) { @@ -107,10 +111,14 @@ namespace SharpCompress.Compressors.LZMA.LZ } _cutValue = 16 + (matchMaxLen >> 1); - UInt32 windowReservSize = (historySize + keepAddBufferBefore + - matchMaxLen + keepAddBufferAfter) / 2 + 256; + UInt32 windowReservSize = + (historySize + keepAddBufferBefore + matchMaxLen + keepAddBufferAfter) / 2 + 256; - base.Create(historySize + keepAddBufferBefore, matchMaxLen + keepAddBufferAfter, windowReservSize); + base.Create( + historySize + keepAddBufferBefore, + matchMaxLen + keepAddBufferAfter, + windowReservSize + ); _matchMaxLen = matchMaxLen; @@ -166,7 +174,9 @@ namespace SharpCompress.Compressors.LZMA.LZ UInt32 matchMinPos = (_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0; UInt32 cur = _bufferOffset + _pos; UInt32 maxLen = K_START_MAX_LEN; // to avoid items for len < hashSize; - UInt32 hashValue, hash2Value = 0, hash3Value = 0; + UInt32 hashValue, + hash2Value = 0, + hash3Value = 0; if (_hashArray) { @@ -221,15 +231,18 @@ namespace SharpCompress.Compressors.LZMA.LZ UInt32 ptr0 = (_cyclicBufferPos << 1) + 1; UInt32 ptr1 = (_cyclicBufferPos << 1); - UInt32 len0, len1; + UInt32 len0, + len1; len0 = len1 = _kNumHashDirectBytes; if (_kNumHashDirectBytes != 0) { if (curMatch > matchMinPos) { - if (_bufferBase[_bufferOffset + curMatch + _kNumHashDirectBytes] != - _bufferBase[cur + _kNumHashDirectBytes]) + if ( + _bufferBase[_bufferOffset + curMatch + _kNumHashDirectBytes] + != _bufferBase[cur + _kNumHashDirectBytes] + ) { distances[offset++] = maxLen = _kNumHashDirectBytes; distances[offset++] = _pos - curMatch - 1; @@ -247,9 +260,12 @@ namespace SharpCompress.Compressors.LZMA.LZ break; } UInt32 delta = _pos - curMatch; - UInt32 cyclicPos = ((delta <= _cyclicBufferPos) - ? (_cyclicBufferPos - delta) - : (_cyclicBufferPos - delta + _cyclicBufferSize)) << 1; + UInt32 cyclicPos = + ( + (delta <= _cyclicBufferPos) + ? (_cyclicBufferPos - delta) + : (_cyclicBufferPos - delta + _cyclicBufferSize) + ) << 1; UInt32 pby1 = _bufferOffset + curMatch; UInt32 len = Math.Min(len0, len1); @@ -338,7 +354,8 @@ namespace SharpCompress.Compressors.LZMA.LZ UInt32 ptr0 = (_cyclicBufferPos << 1) + 1; UInt32 ptr1 = (_cyclicBufferPos << 1); - UInt32 len0, len1; + UInt32 len0, + len1; len0 = len1 = _kNumHashDirectBytes; UInt32 count = _cutValue; @@ -351,9 +368,12 @@ namespace SharpCompress.Compressors.LZMA.LZ } UInt32 delta = _pos - curMatch; - UInt32 cyclicPos = ((delta <= _cyclicBufferPos) - ? (_cyclicBufferPos - delta) - : (_cyclicBufferPos - delta + _cyclicBufferSize)) << 1; + UInt32 cyclicPos = + ( + (delta <= _cyclicBufferPos) + ? (_cyclicBufferPos - delta) + : (_cyclicBufferPos - delta + _cyclicBufferSize) + ) << 1; UInt32 pby1 = _bufferOffset + curMatch; UInt32 len = Math.Min(len0, len1); @@ -389,8 +409,7 @@ namespace SharpCompress.Compressors.LZMA.LZ } } MovePos(); - } - while (--num != 0); + } while (--num != 0); } private void NormalizeLinks(UInt32[] items, UInt32 numItems, UInt32 subValue) diff --git a/src/SharpCompress/Compressors/LZMA/LZ/LzInWindow.cs b/src/SharpCompress/Compressors/LZMA/LZ/LzInWindow.cs index 9ce2121a..943009d2 100644 --- a/src/SharpCompress/Compressors/LZMA/LZ/LzInWindow.cs +++ b/src/SharpCompress/Compressors/LZMA/LZ/LzInWindow.cs @@ -55,9 +55,10 @@ namespace SharpCompress.Compressors.LZMA.LZ { return; } - int numReadBytes = _stream != null - ? _stream.Read(_bufferBase, (int)(_bufferOffset + _streamPos), size) - : 0; + int numReadBytes = + _stream != null + ? _stream.Read(_bufferBase, (int)(_bufferOffset + _streamPos), size) + : 0; if (numReadBytes == 0) { _posLimit = _streamPos; @@ -182,4 +183,4 @@ namespace SharpCompress.Compressors.LZMA.LZ public bool IsDataStarved => _streamPos - _pos < _keepSizeAfter; } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/LZMA/LZ/LzOutWindow.cs b/src/SharpCompress/Compressors/LZMA/LZ/LzOutWindow.cs index 483b3a98..6542ff91 100644 --- a/src/SharpCompress/Compressors/LZMA/LZ/LzOutWindow.cs +++ b/src/SharpCompress/Compressors/LZMA/LZ/LzOutWindow.cs @@ -204,4 +204,4 @@ namespace SharpCompress.Compressors.LZMA.LZ public int AvailableBytes => _pos - _streamPos; } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/LZMA/LZipStream.cs b/src/SharpCompress/Compressors/LZMA/LZipStream.cs index a736bca1..912e4eff 100644 --- a/src/SharpCompress/Compressors/LZMA/LZipStream.cs +++ b/src/SharpCompress/Compressors/LZMA/LZipStream.cs @@ -44,7 +44,13 @@ namespace SharpCompress.Compressors.LZMA WriteHeaderSize(stream); _countingWritableSubStream = new CountingWritableSubStream(stream); - _stream = new Crc32Stream(new LzmaStream(new LzmaEncoderProperties(true, dSize), false, _countingWritableSubStream)); + _stream = new Crc32Stream( + new LzmaStream( + new LzmaEncoderProperties(true, dSize), + false, + _countingWritableSubStream + ) + ); } } @@ -107,17 +113,22 @@ namespace SharpCompress.Compressors.LZMA // reading the output length when we initialize. public override long Length => throw new NotImplementedException(); - public override long Position { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + public override long Position + { + get => throw new NotImplementedException(); + set => throw new NotImplementedException(); + } - public override int Read(byte[] buffer, int offset, int count) => _stream.Read(buffer, offset, count); + public override int Read(byte[] buffer, int offset, int count) => + _stream.Read(buffer, offset, count); public override int ReadByte() => _stream.ReadByte(); - public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException(); + public override long Seek(long offset, SeekOrigin origin) => + throw new NotSupportedException(); public override void SetLength(long value) => throw new NotImplementedException(); - #if !NETFRAMEWORK && !NETSTANDARD2_0 public override int Read(Span buffer) @@ -131,7 +142,6 @@ namespace SharpCompress.Compressors.LZMA _writeCount += buffer.Length; } - #endif public override void Write(byte[] buffer, int offset, int count) @@ -180,7 +190,13 @@ namespace SharpCompress.Compressors.LZMA return 0; } - if (header[0] != 'L' || header[1] != 'Z' || header[2] != 'I' || header[3] != 'P' || header[4] != 1 /* version 1 */) + if ( + header[0] != 'L' + || header[1] != 'Z' + || header[2] != 'I' + || header[3] != 'P' + || header[4] != 1 /* version 1 */ + ) { return 0; } @@ -189,7 +205,15 @@ namespace SharpCompress.Compressors.LZMA return (1 << basePower) - subtractionNumerator * (1 << (basePower - 4)); } - private static readonly byte[] headerBytes = new byte[6] { (byte)'L', (byte)'Z', (byte)'I', (byte)'P', 1, 113 }; + private static readonly byte[] headerBytes = new byte[6] + { + (byte)'L', + (byte)'Z', + (byte)'I', + (byte)'P', + 1, + 113 + }; public static void WriteHeaderSize(Stream stream) { diff --git a/src/SharpCompress/Compressors/LZMA/Log.cs b/src/SharpCompress/Compressors/LZMA/Log.cs index f4cbed5e..a31d2b69 100644 --- a/src/SharpCompress/Compressors/LZMA/Log.cs +++ b/src/SharpCompress/Compressors/LZMA/Log.cs @@ -83,4 +83,4 @@ namespace SharpCompress.Compressors.LZMA NEEDS_INDENT = true; } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/LZMA/LzmaBase.cs b/src/SharpCompress/Compressors/LZMA/LzmaBase.cs index 6e2b8a5d..74ca3cfb 100644 --- a/src/SharpCompress/Compressors/LZMA/LzmaBase.cs +++ b/src/SharpCompress/Compressors/LZMA/LzmaBase.cs @@ -101,9 +101,9 @@ namespace SharpCompress.Compressors.LZMA public const uint K_NUM_LOW_LEN_SYMBOLS = 1 << K_NUM_LOW_LEN_BITS; public const uint K_NUM_MID_LEN_SYMBOLS = 1 << K_NUM_MID_LEN_BITS; - public const uint K_NUM_LEN_SYMBOLS = K_NUM_LOW_LEN_SYMBOLS + K_NUM_MID_LEN_SYMBOLS + - (1 << K_NUM_HIGH_LEN_BITS); + public const uint K_NUM_LEN_SYMBOLS = + K_NUM_LOW_LEN_SYMBOLS + K_NUM_MID_LEN_SYMBOLS + (1 << K_NUM_HIGH_LEN_BITS); public const uint K_MATCH_MAX_LEN = K_MATCH_MIN_LEN + K_NUM_LEN_SYMBOLS - 1; } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/LZMA/LzmaDecoder.cs b/src/SharpCompress/Compressors/LZMA/LzmaDecoder.cs index f54c2bf7..a3841197 100644 --- a/src/SharpCompress/Compressors/LZMA/LzmaDecoder.cs +++ b/src/SharpCompress/Compressors/LZMA/LzmaDecoder.cs @@ -13,8 +13,12 @@ namespace SharpCompress.Compressors.LZMA { private BitDecoder _choice = new BitDecoder(); private BitDecoder _choice2 = new BitDecoder(); - 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 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 uint _numPosStates; @@ -85,8 +89,7 @@ namespace SharpCompress.Compressors.LZMA do { symbol = (symbol << 1) | _decoders[symbol].Decode(rangeDecoder); - } - while (symbol < 0x100); + } while (symbol < 0x100); return (byte)symbol; } @@ -107,8 +110,7 @@ namespace SharpCompress.Compressors.LZMA } break; } - } - while (symbol < 0x100); + } while (symbol < 0x100); return (byte)symbol; } } @@ -120,8 +122,7 @@ namespace SharpCompress.Compressors.LZMA public void Create(int numPosBits, int numPrevBits) { - if (_coders != null && _numPrevBits == numPrevBits && - _numPosBits == numPosBits) + if (_coders != null && _numPrevBits == numPrevBits && _numPosBits == numPosBits) { return; } @@ -155,23 +156,39 @@ namespace SharpCompress.Compressors.LZMA return _coders[GetState(pos, prevByte)].DecodeNormal(rangeDecoder); } - public byte DecodeWithMatchByte(RangeCoder.Decoder rangeDecoder, uint pos, byte prevByte, byte matchByte) + public byte DecodeWithMatchByte( + RangeCoder.Decoder rangeDecoder, + uint pos, + byte prevByte, + byte matchByte + ) { - return _coders[GetState(pos, prevByte)].DecodeWithMatchByte(rangeDecoder, matchByte); + return _coders[GetState(pos, prevByte)].DecodeWithMatchByte( + rangeDecoder, + matchByte + ); } } private OutWindow _outWindow; - private readonly BitDecoder[] _isMatchDecoders = new BitDecoder[Base.K_NUM_STATES << Base.K_NUM_POS_STATES_BITS_MAX]; + private readonly BitDecoder[] _isMatchDecoders = new BitDecoder[ + Base.K_NUM_STATES << Base.K_NUM_POS_STATES_BITS_MAX + ]; private readonly BitDecoder[] _isRepDecoders = new BitDecoder[Base.K_NUM_STATES]; private readonly BitDecoder[] _isRepG0Decoders = new BitDecoder[Base.K_NUM_STATES]; private readonly BitDecoder[] _isRepG1Decoders = new BitDecoder[Base.K_NUM_STATES]; private readonly BitDecoder[] _isRepG2Decoders = new BitDecoder[Base.K_NUM_STATES]; - private readonly BitDecoder[] _isRep0LongDecoders = new BitDecoder[Base.K_NUM_STATES << Base.K_NUM_POS_STATES_BITS_MAX]; + private readonly BitDecoder[] _isRep0LongDecoders = new BitDecoder[ + Base.K_NUM_STATES << Base.K_NUM_POS_STATES_BITS_MAX + ]; - private readonly BitTreeDecoder[] _posSlotDecoder = new BitTreeDecoder[Base.K_NUM_LEN_TO_POS_STATES]; - private readonly BitDecoder[] _posDecoders = new BitDecoder[Base.K_NUM_FULL_DISTANCES - Base.K_END_POS_MODEL_INDEX]; + private readonly BitTreeDecoder[] _posSlotDecoder = new BitTreeDecoder[ + Base.K_NUM_LEN_TO_POS_STATES + ]; + private readonly BitDecoder[] _posDecoders = new BitDecoder[ + Base.K_NUM_FULL_DISTANCES - Base.K_END_POS_MODEL_INDEX + ]; private BitTreeDecoder _posAlignDecoder = new BitTreeDecoder(Base.K_NUM_ALIGN_BITS); @@ -185,7 +202,10 @@ namespace SharpCompress.Compressors.LZMA private uint _posStateMask; private Base.State _state = new Base.State(); - private uint _rep0, _rep1, _rep2, _rep3; + private uint _rep0, + _rep1, + _rep2, + _rep3; public Decoder() { @@ -272,8 +292,13 @@ namespace SharpCompress.Compressors.LZMA _rep3 = 0; } - public void Code(Stream inStream, Stream outStream, - Int64 inSize, Int64 outSize, ICodeProgress progress) + public void Code( + Stream inStream, + Stream outStream, + Int64 inSize, + Int64 outSize, + ICodeProgress progress + ) { if (_outWindow is null) { @@ -309,19 +334,30 @@ namespace SharpCompress.Compressors.LZMA while (outWindow.HasSpace) { uint posState = (uint)outWindow._total & _posStateMask; - if (_isMatchDecoders[(_state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState].Decode(rangeDecoder) == 0) + if ( + _isMatchDecoders[ + (_state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState + ].Decode(rangeDecoder) == 0 + ) { byte b; byte prevByte = outWindow.GetByte(0); if (!_state.IsCharState()) { - b = _literalDecoder.DecodeWithMatchByte(rangeDecoder, - (uint)outWindow._total, prevByte, - outWindow.GetByte((int)_rep0)); + b = _literalDecoder.DecodeWithMatchByte( + rangeDecoder, + (uint)outWindow._total, + prevByte, + outWindow.GetByte((int)_rep0) + ); } else { - b = _literalDecoder.DecodeNormal(rangeDecoder, (uint)outWindow._total, prevByte); + b = _literalDecoder.DecodeNormal( + rangeDecoder, + (uint)outWindow._total, + prevByte + ); } outWindow.PutByte(b); _state.UpdateChar(); @@ -334,8 +370,10 @@ namespace SharpCompress.Compressors.LZMA if (_isRepG0Decoders[_state._index].Decode(rangeDecoder) == 0) { if ( - _isRep0LongDecoders[(_state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState].Decode( - rangeDecoder) == 0) + _isRep0LongDecoders[ + (_state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState + ].Decode(rangeDecoder) == 0 + ) { _state.UpdateShortRep(); outWindow.PutByte(outWindow.GetByte((int)_rep0)); @@ -375,20 +413,29 @@ namespace SharpCompress.Compressors.LZMA _rep1 = _rep0; len = Base.K_MATCH_MIN_LEN + _lenDecoder.Decode(rangeDecoder, posState); _state.UpdateMatch(); - uint posSlot = _posSlotDecoder[Base.GetLenToPosState(len)].Decode(rangeDecoder); + uint posSlot = _posSlotDecoder[Base.GetLenToPosState(len)].Decode( + rangeDecoder + ); if (posSlot >= Base.K_START_POS_MODEL_INDEX) { int numDirectBits = (int)((posSlot >> 1) - 1); _rep0 = ((2 | (posSlot & 1)) << numDirectBits); if (posSlot < Base.K_END_POS_MODEL_INDEX) { - _rep0 += BitTreeDecoder.ReverseDecode(_posDecoders, - _rep0 - posSlot - 1, rangeDecoder, numDirectBits); + _rep0 += BitTreeDecoder.ReverseDecode( + _posDecoders, + _rep0 - posSlot - 1, + rangeDecoder, + numDirectBits + ); } else { - _rep0 += (rangeDecoder.DecodeDirectBits( - numDirectBits - Base.K_NUM_ALIGN_BITS) << Base.K_NUM_ALIGN_BITS); + _rep0 += ( + rangeDecoder.DecodeDirectBits( + numDirectBits - Base.K_NUM_ALIGN_BITS + ) << Base.K_NUM_ALIGN_BITS + ); _rep0 += _posAlignDecoder.ReverseDecode(rangeDecoder); } } @@ -458,7 +505,7 @@ namespace SharpCompress.Compressors.LZMA set { } } public override void Flush() { } - public override int Read(byte[] buffer, int offset, int count) + public override int Read(byte[] buffer, int offset, int count) { return 0; } diff --git a/src/SharpCompress/Compressors/LZMA/LzmaEncoder.cs b/src/SharpCompress/Compressors/LZMA/LzmaEncoder.cs index 5dab5002..c1ab3b18 100644 --- a/src/SharpCompress/Compressors/LZMA/LzmaEncoder.cs +++ b/src/SharpCompress/Compressors/LZMA/LzmaEncoder.cs @@ -108,7 +108,11 @@ namespace SharpCompress.Compressors.LZMA } } - public void EncodeMatched(RangeCoder.Encoder rangeEncoder, byte matchByte, byte symbol) + public void EncodeMatched( + RangeCoder.Encoder rangeEncoder, + byte matchByte, + byte symbol + ) { uint context = 1; bool same = true; @@ -190,7 +194,9 @@ namespace SharpCompress.Compressors.LZMA public Encoder2 GetSubCoder(UInt32 pos, Byte prevByte) { - return _coders[((pos & _posMask) << _numPrevBits) + (uint)(prevByte >> (8 - _numPrevBits))]; + return _coders[ + ((pos & _posMask) << _numPrevBits) + (uint)(prevByte >> (8 - _numPrevBits)) + ]; } } @@ -198,8 +204,12 @@ namespace SharpCompress.Compressors.LZMA { private BitEncoder _choice = new BitEncoder(); private BitEncoder _choice2 = new BitEncoder(); - 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 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); public LenEncoder() @@ -268,20 +278,28 @@ namespace SharpCompress.Compressors.LZMA { return; } - prices[st + i] = b0 + _midCoder[posState].GetPrice(i - Base.K_NUM_LOW_LEN_SYMBOLS); + prices[st + i] = + b0 + _midCoder[posState].GetPrice(i - Base.K_NUM_LOW_LEN_SYMBOLS); } for (; i < numSymbols; i++) { - prices[st + i] = b1 + _highCoder.GetPrice(i - Base.K_NUM_LOW_LEN_SYMBOLS - Base.K_NUM_MID_LEN_SYMBOLS); + prices[st + i] = + b1 + + _highCoder.GetPrice( + i - Base.K_NUM_LOW_LEN_SYMBOLS - Base.K_NUM_MID_LEN_SYMBOLS + ); } } } - private const UInt32 K_NUM_LEN_SPEC_SYMBOLS = Base.K_NUM_LOW_LEN_SYMBOLS + Base.K_NUM_MID_LEN_SYMBOLS; + private const UInt32 K_NUM_LEN_SPEC_SYMBOLS = + Base.K_NUM_LOW_LEN_SYMBOLS + Base.K_NUM_MID_LEN_SYMBOLS; private class LenPriceTableEncoder : LenEncoder { - private readonly UInt32[] _prices = new UInt32[Base.K_NUM_LEN_SYMBOLS << Base.K_NUM_POS_STATES_BITS_ENCODING_MAX]; + private readonly UInt32[] _prices = new UInt32[ + Base.K_NUM_LEN_SYMBOLS << Base.K_NUM_POS_STATES_BITS_ENCODING_MAX + ]; private UInt32 _tableSize; private readonly UInt32[] _counters = new UInt32[Base.K_NUM_POS_STATES_ENCODING_MAX]; @@ -363,21 +381,26 @@ namespace SharpCompress.Compressors.LZMA private BinTree _matchFinder; private readonly RangeCoder.Encoder _rangeEncoder = new RangeCoder.Encoder(); - private readonly BitEncoder[] _isMatch = - new BitEncoder[Base.K_NUM_STATES << Base.K_NUM_POS_STATES_BITS_MAX]; + private readonly BitEncoder[] _isMatch = new BitEncoder[ + Base.K_NUM_STATES << Base.K_NUM_POS_STATES_BITS_MAX + ]; private readonly BitEncoder[] _isRep = new BitEncoder[Base.K_NUM_STATES]; private readonly BitEncoder[] _isRepG0 = new BitEncoder[Base.K_NUM_STATES]; private readonly BitEncoder[] _isRepG1 = new BitEncoder[Base.K_NUM_STATES]; private readonly BitEncoder[] _isRepG2 = new BitEncoder[Base.K_NUM_STATES]; - private readonly BitEncoder[] _isRep0Long = - new BitEncoder[Base.K_NUM_STATES << Base.K_NUM_POS_STATES_BITS_MAX]; + private readonly BitEncoder[] _isRep0Long = new BitEncoder[ + Base.K_NUM_STATES << Base.K_NUM_POS_STATES_BITS_MAX + ]; - private readonly BitTreeEncoder[] _posSlotEncoder = new BitTreeEncoder[Base.K_NUM_LEN_TO_POS_STATES]; + private readonly BitTreeEncoder[] _posSlotEncoder = new BitTreeEncoder[ + Base.K_NUM_LEN_TO_POS_STATES + ]; - private readonly BitEncoder[] _posEncoders = - new BitEncoder[Base.K_NUM_FULL_DISTANCES - Base.K_END_POS_MODEL_INDEX]; + private readonly BitEncoder[] _posEncoders = new BitEncoder[ + Base.K_NUM_FULL_DISTANCES - Base.K_END_POS_MODEL_INDEX + ]; private BitTreeEncoder _posAlignEncoder = new BitTreeEncoder(Base.K_NUM_ALIGN_BITS); @@ -399,8 +422,12 @@ namespace SharpCompress.Compressors.LZMA private bool _longestMatchWasFound; - private readonly UInt32[] _posSlotPrices = new UInt32[1 << (Base.K_NUM_POS_SLOT_BITS + Base.K_NUM_LEN_TO_POS_STATES_BITS)]; - private readonly UInt32[] _distancesPrices = new UInt32[Base.K_NUM_FULL_DISTANCES << Base.K_NUM_LEN_TO_POS_STATES_BITS]; + private readonly UInt32[] _posSlotPrices = new UInt32[ + 1 << (Base.K_NUM_POS_SLOT_BITS + Base.K_NUM_LEN_TO_POS_STATES_BITS) + ]; + private readonly UInt32[] _distancesPrices = new UInt32[ + Base.K_NUM_FULL_DISTANCES << Base.K_NUM_LEN_TO_POS_STATES_BITS + ]; private readonly UInt32[] _alignPrices = new UInt32[Base.K_ALIGN_TABLE_SIZE]; private UInt32 _alignPriceCount; @@ -444,7 +471,12 @@ namespace SharpCompress.Compressors.LZMA { return; } - _matchFinder.Create(_dictionarySize, K_NUM_OPTS, _numFastBytes, Base.K_MATCH_MAX_LEN + 1 + K_NUM_OPTS); + _matchFinder.Create( + _dictionarySize, + K_NUM_OPTS, + _numFastBytes, + Base.K_MATCH_MAX_LEN + 1 + K_NUM_OPTS + ); _dictionarySizePrev = _dictionarySize; _numFastBytesPrev = _numFastBytes; } @@ -515,8 +547,11 @@ namespace SharpCompress.Compressors.LZMA lenRes = _matchDistances[numDistancePairs - 2]; if (lenRes == _numFastBytes) { - lenRes += _matchFinder.GetMatchLen((int)lenRes - 1, _matchDistances[numDistancePairs - 1], - Base.K_MATCH_MAX_LEN - lenRes); + lenRes += _matchFinder.GetMatchLen( + (int)lenRes - 1, + _matchDistances[numDistancePairs - 1], + Base.K_MATCH_MAX_LEN - lenRes + ); } } _additionalOffset++; @@ -533,8 +568,10 @@ namespace SharpCompress.Compressors.LZMA private UInt32 GetRepLen1Price(Base.State state, UInt32 posState) { - return _isRepG0[state._index].GetPrice0() + - _isRep0Long[(state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState].GetPrice0(); + return _isRepG0[state._index].GetPrice0() + + _isRep0Long[ + (state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState + ].GetPrice0(); } private UInt32 GetPureRepPrice(UInt32 repIndex, Base.State state, UInt32 posState) @@ -543,7 +580,9 @@ namespace SharpCompress.Compressors.LZMA 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 { @@ -577,8 +616,9 @@ namespace SharpCompress.Compressors.LZMA } else { - price = _posSlotPrices[(lenToPosState << Base.K_NUM_POS_SLOT_BITS) + GetPosSlot2(pos)] + - _alignPrices[pos & Base.K_ALIGN_MASK]; + price = + _posSlotPrices[(lenToPosState << Base.K_NUM_POS_SLOT_BITS) + GetPosSlot2(pos)] + + _alignPrices[pos & Base.K_ALIGN_MASK]; } return price + _lenEncoder.GetPrice(len - Base.K_MATCH_MIN_LEN, posState); } @@ -610,8 +650,7 @@ namespace SharpCompress.Compressors.LZMA _optimum[posPrev]._backPrev = backCur; _optimum[posPrev]._posPrev = cur; cur = posPrev; - } - while (cur > 0); + } while (cur > 0); backRes = _optimum[0]._backPrev; _optimumCurrentIndex = _optimum[0]._posPrev; return _optimumCurrentIndex; @@ -631,7 +670,8 @@ namespace SharpCompress.Compressors.LZMA } _optimumCurrentIndex = _optimumEndIndex = 0; - UInt32 lenMain, numDistancePairs; + UInt32 lenMain, + numDistancePairs; if (!_longestMatchWasFound) { ReadMatchDistances(out lenMain, out numDistancePairs); @@ -693,12 +733,16 @@ namespace SharpCompress.Compressors.LZMA UInt32 posState = (position & _posStateMask); - _optimum[1]._price = _isMatch[(_state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState].GetPrice0() + - _literalEncoder.GetSubCoder(position, _previousByte) - .GetPrice(!_state.IsCharState(), matchByte, currentByte); + _optimum[1]._price = + _isMatch[(_state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState].GetPrice0() + + _literalEncoder + .GetSubCoder(position, _previousByte) + .GetPrice(!_state.IsCharState(), matchByte, currentByte); _optimum[1].MakeAsChar(); - UInt32 matchPrice = _isMatch[(_state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState].GetPrice1(); + UInt32 matchPrice = _isMatch[ + (_state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState + ].GetPrice1(); UInt32 repMatchPrice = matchPrice + _isRep[_state._index].GetPrice1(); if (matchByte == currentByte) @@ -730,8 +774,7 @@ namespace SharpCompress.Compressors.LZMA do { _optimum[len--]._price = K_IFINITY_PRICE; - } - while (len >= 2); + } while (len >= 2); for (i = 0; i < Base.K_NUM_REP_DISTANCES; i++) { @@ -743,7 +786,8 @@ namespace SharpCompress.Compressors.LZMA UInt32 price = repMatchPrice + GetPureRepPrice(i, _state, posState); do { - UInt32 curAndLenPrice = price + _repMatchLenEncoder.GetPrice(repLen - 2, posState); + UInt32 curAndLenPrice = + price + _repMatchLenEncoder.GetPrice(repLen - 2, posState); Optimal optimum = _optimum[repLen]; if (curAndLenPrice < optimum._price) { @@ -752,8 +796,7 @@ namespace SharpCompress.Compressors.LZMA optimum._backPrev = i; optimum._prev1IsChar = false; } - } - while (--repLen >= 2); + } while (--repLen >= 2); } UInt32 normalMatchPrice = matchPrice + _isRep[_state._index].GetPrice0(); @@ -769,7 +812,8 @@ namespace SharpCompress.Compressors.LZMA for (; ; len++) { UInt32 distance = _matchDistances[offs + 1]; - UInt32 curAndLenPrice = normalMatchPrice + GetPosLenPrice(distance, len, posState); + UInt32 curAndLenPrice = + normalMatchPrice + GetPosLenPrice(distance, len, posState); Optimal optimum = _optimum[len]; if (curAndLenPrice < optimum._price) { @@ -919,10 +963,14 @@ namespace SharpCompress.Compressors.LZMA posState = (position & _posStateMask); - UInt32 curAnd1Price = curPrice + - _isMatch[(state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState].GetPrice0() + - _literalEncoder.GetSubCoder(position, _matchFinder.GetIndexByte(0 - 2)). - GetPrice(!state.IsCharState(), matchByte, currentByte); + UInt32 curAnd1Price = + curPrice + + _isMatch[ + (state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState + ].GetPrice0() + + _literalEncoder + .GetSubCoder(position, _matchFinder.GetIndexByte(0 - 2)) + .GetPrice(!state.IsCharState(), matchByte, currentByte); Optimal nextOptimum = _optimum[cur + 1]; @@ -935,11 +983,17 @@ namespace SharpCompress.Compressors.LZMA nextIsChar = true; } - matchPrice = curPrice + _isMatch[(state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState].GetPrice1(); + matchPrice = + curPrice + + _isMatch[ + (state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState + ].GetPrice1(); repMatchPrice = matchPrice + _isRep[state._index].GetPrice1(); - if (matchByte == currentByte && - !(nextOptimum._posPrev < cur && nextOptimum._backPrev == 0)) + if ( + matchByte == currentByte + && !(nextOptimum._posPrev < cur && nextOptimum._backPrev == 0) + ) { UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(state, posState); if (shortRepPrice <= nextOptimum._price) @@ -973,18 +1027,20 @@ namespace SharpCompress.Compressors.LZMA Base.State state2 = state; state2.UpdateChar(); UInt32 posStateNext = (position + 1) & _posStateMask; - UInt32 nextRepMatchPrice = curAnd1Price + - _isMatch[(state2._index << Base.K_NUM_POS_STATES_BITS_MAX) + posStateNext] - .GetPrice1() + - _isRep[state2._index].GetPrice1(); + UInt32 nextRepMatchPrice = + curAnd1Price + + _isMatch[ + (state2._index << Base.K_NUM_POS_STATES_BITS_MAX) + posStateNext + ].GetPrice1() + + _isRep[state2._index].GetPrice1(); { UInt32 offset = cur + 1 + lenTest2; while (lenEnd < offset) { _optimum[++lenEnd]._price = K_IFINITY_PRICE; } - UInt32 curAndLenPrice = nextRepMatchPrice + GetRepPrice( - 0, lenTest2, state2, posStateNext); + UInt32 curAndLenPrice = + nextRepMatchPrice + GetRepPrice(0, lenTest2, state2, posStateNext); Optimal optimum = _optimum[offset]; if (curAndLenPrice < optimum._price) { @@ -1002,7 +1058,11 @@ namespace SharpCompress.Compressors.LZMA for (UInt32 repIndex = 0; repIndex < Base.K_NUM_REP_DISTANCES; repIndex++) { - UInt32 lenTest = _matchFinder.GetMatchLen(0 - 1, _reps[repIndex], numAvailableBytes); + UInt32 lenTest = _matchFinder.GetMatchLen( + 0 - 1, + _reps[repIndex], + numAvailableBytes + ); if (lenTest < 2) { continue; @@ -1014,7 +1074,8 @@ namespace SharpCompress.Compressors.LZMA { _optimum[++lenEnd]._price = K_IFINITY_PRICE; } - UInt32 curAndLenPrice = repMatchPrice + GetRepPrice(repIndex, lenTest, state, posState); + UInt32 curAndLenPrice = + repMatchPrice + GetRepPrice(repIndex, lenTest, state, posState); Optimal optimum = _optimum[cur + lenTest]; if (curAndLenPrice < optimum._price) { @@ -1023,8 +1084,7 @@ namespace SharpCompress.Compressors.LZMA optimum._backPrev = repIndex; optimum._prev1IsChar = false; } - } - while (--lenTest >= 2); + } while (--lenTest >= 2); lenTest = lenTestTemp; if (repIndex == 0) @@ -1036,27 +1096,43 @@ namespace SharpCompress.Compressors.LZMA if (lenTest < numAvailableBytesFull) { UInt32 t = Math.Min(numAvailableBytesFull - 1 - lenTest, _numFastBytes); - UInt32 lenTest2 = _matchFinder.GetMatchLen((Int32)lenTest, _reps[repIndex], t); + UInt32 lenTest2 = _matchFinder.GetMatchLen( + (Int32)lenTest, + _reps[repIndex], + t + ); if (lenTest2 >= 2) { Base.State state2 = state; state2.UpdateRep(); UInt32 posStateNext = (position + lenTest) & _posStateMask; UInt32 curAndLenCharPrice = - repMatchPrice + GetRepPrice(repIndex, lenTest, state, posState) + - _isMatch[(state2._index << Base.K_NUM_POS_STATES_BITS_MAX) + posStateNext].GetPrice0() + - _literalEncoder.GetSubCoder(position + lenTest, - _matchFinder.GetIndexByte((Int32)lenTest - 1 - 1)) - .GetPrice(true, - _matchFinder.GetIndexByte( - (Int32)lenTest - 1 - (Int32)(_reps[repIndex] + 1)), - _matchFinder.GetIndexByte((Int32)lenTest - 1)); + repMatchPrice + + GetRepPrice(repIndex, lenTest, state, posState) + + _isMatch[ + (state2._index << Base.K_NUM_POS_STATES_BITS_MAX) + posStateNext + ].GetPrice0() + + _literalEncoder + .GetSubCoder( + position + lenTest, + _matchFinder.GetIndexByte((Int32)lenTest - 1 - 1) + ) + .GetPrice( + true, + _matchFinder.GetIndexByte( + (Int32)lenTest - 1 - (Int32)(_reps[repIndex] + 1) + ), + _matchFinder.GetIndexByte((Int32)lenTest - 1) + ); state2.UpdateChar(); posStateNext = (position + lenTest + 1) & _posStateMask; - UInt32 nextMatchPrice = curAndLenCharPrice + - _isMatch[(state2._index << Base.K_NUM_POS_STATES_BITS_MAX) + posStateNext] - .GetPrice1(); - UInt32 nextRepMatchPrice = nextMatchPrice + _isRep[state2._index].GetPrice1(); + UInt32 nextMatchPrice = + curAndLenCharPrice + + _isMatch[ + (state2._index << Base.K_NUM_POS_STATES_BITS_MAX) + posStateNext + ].GetPrice1(); + UInt32 nextRepMatchPrice = + nextMatchPrice + _isRep[state2._index].GetPrice1(); // for(; lenTest2 >= 2; lenTest2--) { @@ -1065,8 +1141,9 @@ namespace SharpCompress.Compressors.LZMA { _optimum[++lenEnd]._price = K_IFINITY_PRICE; } - UInt32 curAndLenPrice = nextRepMatchPrice + - GetRepPrice(0, lenTest2, state2, posStateNext); + UInt32 curAndLenPrice = + nextRepMatchPrice + + GetRepPrice(0, lenTest2, state2, posStateNext); Optimal optimum = _optimum[cur + offset]; if (curAndLenPrice < optimum._price) { @@ -1086,7 +1163,11 @@ namespace SharpCompress.Compressors.LZMA if (newLen > numAvailableBytes) { newLen = numAvailableBytes; - for (numDistancePairs = 0; newLen > _matchDistances[numDistancePairs]; numDistancePairs += 2) + for ( + numDistancePairs = 0; + newLen > _matchDistances[numDistancePairs]; + numDistancePairs += 2 + ) { ; } @@ -1110,7 +1191,8 @@ namespace SharpCompress.Compressors.LZMA for (UInt32 lenTest = startLen; ; lenTest++) { UInt32 curBack = _matchDistances[offs + 1]; - UInt32 curAndLenPrice = normalMatchPrice + GetPosLenPrice(curBack, lenTest, posState); + UInt32 curAndLenPrice = + normalMatchPrice + GetPosLenPrice(curBack, lenTest, posState); Optimal optimum = _optimum[cur + lenTest]; if (curAndLenPrice < optimum._price) { @@ -1124,41 +1206,57 @@ namespace SharpCompress.Compressors.LZMA { if (lenTest < numAvailableBytesFull) { - UInt32 t = Math.Min(numAvailableBytesFull - 1 - lenTest, _numFastBytes); - UInt32 lenTest2 = _matchFinder.GetMatchLen((Int32)lenTest, curBack, t); + UInt32 t = Math.Min( + numAvailableBytesFull - 1 - lenTest, + _numFastBytes + ); + UInt32 lenTest2 = _matchFinder.GetMatchLen( + (Int32)lenTest, + curBack, + t + ); if (lenTest2 >= 2) { Base.State state2 = state; state2.UpdateMatch(); UInt32 posStateNext = (position + lenTest) & _posStateMask; - UInt32 curAndLenCharPrice = curAndLenPrice + - _isMatch[ - (state2._index << Base.K_NUM_POS_STATES_BITS_MAX) + - posStateNext].GetPrice0() + - _literalEncoder.GetSubCoder(position + lenTest, - _matchFinder.GetIndexByte( - (Int32)lenTest - 1 - 1)) - . - GetPrice(true, - _matchFinder.GetIndexByte( - (Int32)lenTest - - (Int32)(curBack + 1) - 1), - _matchFinder.GetIndexByte( - (Int32)lenTest - 1)); + UInt32 curAndLenCharPrice = + curAndLenPrice + + _isMatch[ + (state2._index << Base.K_NUM_POS_STATES_BITS_MAX) + + posStateNext + ].GetPrice0() + + _literalEncoder + .GetSubCoder( + position + lenTest, + _matchFinder.GetIndexByte((Int32)lenTest - 1 - 1) + ) + .GetPrice( + true, + _matchFinder.GetIndexByte( + (Int32)lenTest - (Int32)(curBack + 1) - 1 + ), + _matchFinder.GetIndexByte((Int32)lenTest - 1) + ); state2.UpdateChar(); posStateNext = (position + lenTest + 1) & _posStateMask; - UInt32 nextMatchPrice = curAndLenCharPrice + - _isMatch[ - (state2._index << Base.K_NUM_POS_STATES_BITS_MAX) + - posStateNext].GetPrice1(); - UInt32 nextRepMatchPrice = nextMatchPrice + _isRep[state2._index].GetPrice1(); + UInt32 nextMatchPrice = + curAndLenCharPrice + + _isMatch[ + (state2._index << Base.K_NUM_POS_STATES_BITS_MAX) + + posStateNext + ].GetPrice1(); + UInt32 nextRepMatchPrice = + nextMatchPrice + _isRep[state2._index].GetPrice1(); UInt32 offset = lenTest + 1 + lenTest2; while (lenEnd < cur + offset) { _optimum[++lenEnd]._price = K_IFINITY_PRICE; } - curAndLenPrice = nextRepMatchPrice + GetRepPrice(0, lenTest2, state2, posStateNext); + curAndLenPrice = + nextRepMatchPrice + + GetRepPrice(0, lenTest2, state2, posStateNext); optimum = _optimum[cur + offset]; if (curAndLenPrice < optimum._price) { @@ -1196,7 +1294,10 @@ namespace SharpCompress.Compressors.LZMA 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(); UInt32 len = Base.K_MATCH_MIN_LEN; @@ -1206,7 +1307,10 @@ namespace SharpCompress.Compressors.LZMA _posSlotEncoder[lenToPosState].Encode(_rangeEncoder, posSlot); int footerBits = 30; UInt32 posReduced = (((UInt32)1) << footerBits) - 1; - _rangeEncoder.EncodeDirectBits(posReduced >> Base.K_NUM_ALIGN_BITS, footerBits - Base.K_NUM_ALIGN_BITS); + _rangeEncoder.EncodeDirectBits( + posReduced >> Base.K_NUM_ALIGN_BITS, + footerBits - Base.K_NUM_ALIGN_BITS + ); _posAlignEncoder.ReverseEncode(_rangeEncoder, posReduced & Base.K_ALIGN_MASK); } @@ -1242,7 +1346,11 @@ namespace SharpCompress.Compressors.LZMA { if (_trainSize > 0) { - for (; _trainSize > 0 && (!_processingMode || !_matchFinder.IsDataStarved); _trainSize--) + for ( + ; + _trainSize > 0 && (!_processingMode || !_matchFinder.IsDataStarved); + _trainSize-- + ) { _matchFinder.Skip(1); } @@ -1261,13 +1369,19 @@ namespace SharpCompress.Compressors.LZMA Flush((UInt32)_nowPos64); return; } - UInt32 len, numDistancePairs; // it's not used + UInt32 len, + numDistancePairs; // it's not used ReadMatchDistances(out len, out numDistancePairs); UInt32 posState = (UInt32)(_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(); Byte curByte = _matchFinder.GetIndexByte((Int32)(0 - _additionalOffset)); - _literalEncoder.GetSubCoder((UInt32)(_nowPos64), _previousByte).Encode(_rangeEncoder, curByte); + _literalEncoder + .GetSubCoder((UInt32)(_nowPos64), _previousByte) + .Encode(_rangeEncoder, curByte); _previousByte = curByte; _additionalOffset--; _nowPos64++; @@ -1299,11 +1413,15 @@ namespace SharpCompress.Compressors.LZMA { _isMatch[complexState].Encode(_rangeEncoder, 0); Byte curByte = _matchFinder.GetIndexByte((Int32)(0 - _additionalOffset)); - LiteralEncoder.Encoder2 subCoder = _literalEncoder.GetSubCoder((UInt32)_nowPos64, _previousByte); + LiteralEncoder.Encoder2 subCoder = _literalEncoder.GetSubCoder( + (UInt32)_nowPos64, + _previousByte + ); if (!_state.IsCharState()) { - Byte matchByte = - _matchFinder.GetIndexByte((Int32)(0 - _repDistances[0] - 1 - _additionalOffset)); + Byte matchByte = _matchFinder.GetIndexByte( + (Int32)(0 - _repDistances[0] - 1 - _additionalOffset) + ); subCoder.EncodeMatched(_rangeEncoder, matchByte, curByte); } else @@ -1350,7 +1468,11 @@ namespace SharpCompress.Compressors.LZMA } else { - _repMatchLenEncoder.Encode(_rangeEncoder, len - Base.K_MATCH_MIN_LEN, posState); + _repMatchLenEncoder.Encode( + _rangeEncoder, + len - Base.K_MATCH_MIN_LEN, + posState + ); _state.UpdateRep(); } UInt32 distance = _repDistances[pos]; @@ -1381,15 +1503,24 @@ namespace SharpCompress.Compressors.LZMA if (posSlot < Base.K_END_POS_MODEL_INDEX) { - BitTreeEncoder.ReverseEncode(_posEncoders, - baseVal - posSlot - 1, _rangeEncoder, footerBits, - posReduced); + BitTreeEncoder.ReverseEncode( + _posEncoders, + baseVal - posSlot - 1, + _rangeEncoder, + footerBits, + posReduced + ); } else { - _rangeEncoder.EncodeDirectBits(posReduced >> Base.K_NUM_ALIGN_BITS, - footerBits - Base.K_NUM_ALIGN_BITS); - _posAlignEncoder.ReverseEncode(_rangeEncoder, posReduced & Base.K_ALIGN_MASK); + _rangeEncoder.EncodeDirectBits( + posReduced >> Base.K_NUM_ALIGN_BITS, + footerBits - Base.K_NUM_ALIGN_BITS + ); + _posAlignEncoder.ReverseEncode( + _rangeEncoder, + posReduced & Base.K_ALIGN_MASK + ); _alignPriceCount++; } } @@ -1464,8 +1595,7 @@ namespace SharpCompress.Compressors.LZMA ReleaseOutStream(); } - public void SetStreams(Stream inStream, Stream outStream, - Int64 inSize, Int64 outSize) + public void SetStreams(Stream inStream, Stream outStream, Int64 inSize, Int64 outSize) { _inStream = inStream; _finished = false; @@ -1488,8 +1618,13 @@ namespace SharpCompress.Compressors.LZMA _nowPos64 = 0; } - public void Code(Stream inStream, Stream outStream, - Int64 inSize, Int64 outSize, ICodeProgress progress) + public void Code( + Stream inStream, + Stream outStream, + Int64 inSize, + Int64 outSize, + ICodeProgress progress + ) { _needReleaseMfStream = false; _processingMode = false; @@ -1579,7 +1714,9 @@ namespace SharpCompress.Compressors.LZMA public void WriteCoderProperties(Span span) { - span[0] = (byte)((_posStateBits * 5 + _numLiteralPosStateBits) * 9 + _numLiteralContextBits); + span[0] = (byte)( + (_posStateBits * 5 + _numLiteralPosStateBits) * 9 + _numLiteralContextBits + ); for (int i = 0; i < 4; i++) { span[1 + i] = (byte)((_dictionarySize >> (8 * i)) & 0xFF); @@ -1596,11 +1733,19 @@ namespace SharpCompress.Compressors.LZMA UInt32 posSlot = GetPosSlot(i); int footerBits = (int)((posSlot >> 1) - 1); UInt32 baseVal = ((2 | (posSlot & 1)) << footerBits); - _tempPrices[i] = BitTreeEncoder.ReverseGetPrice(_posEncoders, - baseVal - posSlot - 1, footerBits, i - baseVal); + _tempPrices[i] = BitTreeEncoder.ReverseGetPrice( + _posEncoders, + baseVal - posSlot - 1, + footerBits, + i - baseVal + ); } - for (UInt32 lenToPosState = 0; lenToPosState < Base.K_NUM_LEN_TO_POS_STATES; lenToPosState++) + for ( + UInt32 lenToPosState = 0; + lenToPosState < Base.K_NUM_LEN_TO_POS_STATES; + lenToPosState++ + ) { UInt32 posSlot; BitTreeEncoder encoder = _posSlotEncoder[lenToPosState]; @@ -1612,8 +1757,10 @@ namespace SharpCompress.Compressors.LZMA } for (posSlot = Base.K_END_POS_MODEL_INDEX; posSlot < _distTableSize; posSlot++) { - _posSlotPrices[st + posSlot] += ((((posSlot >> 1) - 1) - Base.K_NUM_ALIGN_BITS) << - BitEncoder.K_NUM_BIT_PRICE_SHIFT_BITS); + _posSlotPrices[st + posSlot] += ( + (((posSlot >> 1) - 1) - Base.K_NUM_ALIGN_BITS) + << BitEncoder.K_NUM_BIT_PRICE_SHIFT_BITS + ); } UInt32 st2 = lenToPosState * Base.K_NUM_FULL_DISTANCES; @@ -1639,11 +1786,7 @@ namespace SharpCompress.Compressors.LZMA _alignPriceCount = 0; } - private static readonly string[] K_MATCH_FINDER_I_DS = - { - "BT2", - "BT4" - }; + private static readonly string[] K_MATCH_FINDER_I_DS = { "BT2", "BT4" }; private static int FindMatchFinder(string s) { @@ -1665,129 +1808,135 @@ namespace SharpCompress.Compressors.LZMA switch (propIDs[i]) { case CoderPropId.NumFastBytes: + { + if (!(prop is Int32)) { - if (!(prop is Int32)) - { - throw new InvalidParamException(); - } - Int32 numFastBytes = (Int32)prop; - if (numFastBytes < 5 || numFastBytes > Base.K_MATCH_MAX_LEN) - { - throw new InvalidParamException(); - } - _numFastBytes = (UInt32)numFastBytes; - break; + throw new InvalidParamException(); } + Int32 numFastBytes = (Int32)prop; + if (numFastBytes < 5 || numFastBytes > Base.K_MATCH_MAX_LEN) + { + throw new InvalidParamException(); + } + _numFastBytes = (UInt32)numFastBytes; + break; + } case CoderPropId.Algorithm: - { - /* - if (!(prop is Int32)) - throw new InvalidParamException(); - Int32 maximize = (Int32)prop; - _fastMode = (maximize == 0); - _maxMode = (maximize >= 2); - */ - break; - } + { + /* + if (!(prop is Int32)) + throw new InvalidParamException(); + Int32 maximize = (Int32)prop; + _fastMode = (maximize == 0); + _maxMode = (maximize >= 2); + */ + break; + } case CoderPropId.MatchFinder: + { + if (!(prop is String)) { - if (!(prop is String)) - { - throw new InvalidParamException(); - } - EMatchFinderType matchFinderIndexPrev = _matchFinderType; - int m = FindMatchFinder(((string)prop)); - if (m < 0) - { - throw new InvalidParamException(); - } - _matchFinderType = (EMatchFinderType)m; - if (_matchFinder != null && matchFinderIndexPrev != _matchFinderType) - { - _dictionarySizePrev = 0xFFFFFFFF; - _matchFinder = null; - } - break; + throw new InvalidParamException(); } + EMatchFinderType matchFinderIndexPrev = _matchFinderType; + int m = FindMatchFinder(((string)prop)); + if (m < 0) + { + throw new InvalidParamException(); + } + _matchFinderType = (EMatchFinderType)m; + if (_matchFinder != null && matchFinderIndexPrev != _matchFinderType) + { + _dictionarySizePrev = 0xFFFFFFFF; + _matchFinder = null; + } + break; + } case CoderPropId.DictionarySize: + { + const int kDicLogSizeMaxCompress = 30; + if (!(prop is Int32)) { - const int kDicLogSizeMaxCompress = 30; - if (!(prop is Int32)) - { - throw new InvalidParamException(); - } - ; - Int32 dictionarySize = (Int32)prop; - if (dictionarySize < (UInt32)(1 << Base.K_DIC_LOG_SIZE_MIN) || - dictionarySize > (UInt32)(1 << kDicLogSizeMaxCompress)) - { - throw new InvalidParamException(); - } - _dictionarySize = (UInt32)dictionarySize; - int dicLogSize; - for (dicLogSize = 0; dicLogSize < (UInt32)kDicLogSizeMaxCompress; dicLogSize++) - { - if (dictionarySize <= ((UInt32)(1) << dicLogSize)) - { - break; - } - } - _distTableSize = (UInt32)dicLogSize * 2; - break; + throw new InvalidParamException(); } + ; + Int32 dictionarySize = (Int32)prop; + if ( + dictionarySize < (UInt32)(1 << Base.K_DIC_LOG_SIZE_MIN) + || dictionarySize > (UInt32)(1 << kDicLogSizeMaxCompress) + ) + { + throw new InvalidParamException(); + } + _dictionarySize = (UInt32)dictionarySize; + int dicLogSize; + for ( + dicLogSize = 0; + dicLogSize < (UInt32)kDicLogSizeMaxCompress; + dicLogSize++ + ) + { + if (dictionarySize <= ((UInt32)(1) << dicLogSize)) + { + break; + } + } + _distTableSize = (UInt32)dicLogSize * 2; + break; + } case CoderPropId.PosStateBits: + { + if (!(prop is Int32)) { - if (!(prop is Int32)) - { - throw new InvalidParamException(); - } - Int32 v = (Int32)prop; - if (v < 0 || v > (UInt32)Base.K_NUM_POS_STATES_BITS_ENCODING_MAX) - { - throw new InvalidParamException(); - } - _posStateBits = v; - _posStateMask = (((UInt32)1) << _posStateBits) - 1; - break; + throw new InvalidParamException(); } + Int32 v = (Int32)prop; + if (v < 0 || v > (UInt32)Base.K_NUM_POS_STATES_BITS_ENCODING_MAX) + { + throw new InvalidParamException(); + } + _posStateBits = v; + _posStateMask = (((UInt32)1) << _posStateBits) - 1; + break; + } case CoderPropId.LitPosBits: + { + if (!(prop is Int32)) { - if (!(prop is Int32)) - { - throw new InvalidParamException(); - } - Int32 v = (Int32)prop; - if (v < 0 || v > Base.K_NUM_LIT_POS_STATES_BITS_ENCODING_MAX) - { - throw new InvalidParamException(); - } - _numLiteralPosStateBits = v; - break; + throw new InvalidParamException(); } + Int32 v = (Int32)prop; + if (v < 0 || v > Base.K_NUM_LIT_POS_STATES_BITS_ENCODING_MAX) + { + throw new InvalidParamException(); + } + _numLiteralPosStateBits = v; + break; + } case CoderPropId.LitContextBits: + { + if (!(prop is Int32)) { - if (!(prop is Int32)) - { - throw new InvalidParamException(); - } - Int32 v = (Int32)prop; - if (v < 0 || v > Base.K_NUM_LIT_CONTEXT_BITS_MAX) - { - throw new InvalidParamException(); - } + throw new InvalidParamException(); + } + Int32 v = (Int32)prop; + if (v < 0 || v > Base.K_NUM_LIT_CONTEXT_BITS_MAX) + { + throw new InvalidParamException(); + } ; - _numLiteralContextBits = v; - break; - } + _numLiteralContextBits = v; + break; + } case CoderPropId.EndMarker: + { + if (!(prop is Boolean)) { - if (!(prop is Boolean)) - { - throw new InvalidParamException(); - } - SetWriteEndMarkerMode((Boolean)prop); - break; + throw new InvalidParamException(); } + SetWriteEndMarkerMode((Boolean)prop); + break; + } default: throw new InvalidParamException(); } diff --git a/src/SharpCompress/Compressors/LZMA/LzmaEncoderProperties.cs b/src/SharpCompress/Compressors/LZMA/LzmaEncoderProperties.cs index de7fa6f1..395b2492 100644 --- a/src/SharpCompress/Compressors/LZMA/LzmaEncoderProperties.cs +++ b/src/SharpCompress/Compressors/LZMA/LzmaEncoderProperties.cs @@ -5,20 +5,11 @@ internal CoderPropId[] _propIDs; internal object[] _properties; - public LzmaEncoderProperties() - : this(false) - { - } + public LzmaEncoderProperties() : this(false) { } - public LzmaEncoderProperties(bool eos) - : this(eos, 1 << 20) - { - } + public LzmaEncoderProperties(bool eos) : this(eos, 1 << 20) { } - public LzmaEncoderProperties(bool eos, int dictionary) - : this(eos, dictionary, 32) - { - } + public LzmaEncoderProperties(bool eos, int dictionary) : this(eos, dictionary, 32) { } public LzmaEncoderProperties(bool eos, int dictionary, int numFastBytes) { @@ -29,27 +20,27 @@ string mf = "bt4"; _propIDs = new[] - { - CoderPropId.DictionarySize, - CoderPropId.PosStateBits, - CoderPropId.LitContextBits, - CoderPropId.LitPosBits, - CoderPropId.Algorithm, - CoderPropId.NumFastBytes, - CoderPropId.MatchFinder, - CoderPropId.EndMarker - }; + { + CoderPropId.DictionarySize, + CoderPropId.PosStateBits, + CoderPropId.LitContextBits, + CoderPropId.LitPosBits, + CoderPropId.Algorithm, + CoderPropId.NumFastBytes, + CoderPropId.MatchFinder, + CoderPropId.EndMarker + }; _properties = new object[] - { - dictionary, - posStateBits, - litContextBits, - litPosBits, - algorithm, - numFastBytes, - mf, - eos - }; + { + dictionary, + posStateBits, + litContextBits, + litPosBits, + algorithm, + numFastBytes, + mf, + eos + }; } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/LZMA/LzmaStream.cs b/src/SharpCompress/Compressors/LZMA/LzmaStream.cs index 53c77719..80238cdf 100644 --- a/src/SharpCompress/Compressors/LZMA/LzmaStream.cs +++ b/src/SharpCompress/Compressors/LZMA/LzmaStream.cs @@ -34,22 +34,22 @@ namespace SharpCompress.Compressors.LZMA private bool _isDisposed; public LzmaStream(byte[] properties, Stream inputStream) - : this(properties, inputStream, -1, -1, null, properties.Length < 5) - { - } + : this(properties, inputStream, -1, -1, null, properties.Length < 5) { } public LzmaStream(byte[] properties, Stream inputStream, long inputSize) - : this(properties, inputStream, inputSize, -1, null, properties.Length < 5) - { - } + : this(properties, inputStream, inputSize, -1, null, properties.Length < 5) { } public LzmaStream(byte[] properties, Stream inputStream, long inputSize, long outputSize) - : this(properties, inputStream, inputSize, outputSize, null, properties.Length < 5) - { - } + : this(properties, inputStream, inputSize, outputSize, null, properties.Length < 5) { } - public LzmaStream(byte[] properties, Stream inputStream, long inputSize, long outputSize, - Stream presetDictionary, bool isLzma2) + public LzmaStream( + byte[] properties, + Stream inputStream, + long inputSize, + long outputSize, + Stream presetDictionary, + bool isLzma2 + ) { _inputStream = inputStream; _inputSize = inputSize; @@ -92,11 +92,14 @@ namespace SharpCompress.Compressors.LZMA } public LzmaStream(LzmaEncoderProperties properties, bool isLzma2, Stream outputStream) - : this(properties, isLzma2, null, outputStream) - { - } + : this(properties, isLzma2, null, outputStream) { } - public LzmaStream(LzmaEncoderProperties properties, bool isLzma2, Stream presetDictionary, Stream outputStream) + public LzmaStream( + LzmaEncoderProperties properties, + bool isLzma2, + Stream presetDictionary, + Stream outputStream + ) { _isLzma2 = isLzma2; _availableBytes = 0; @@ -126,9 +129,7 @@ namespace SharpCompress.Compressors.LZMA public override bool CanWrite => _encoder != null; - public override void Flush() - { - } + public override void Flush() { } protected override void Dispose(bool disposing) { @@ -150,7 +151,11 @@ namespace SharpCompress.Compressors.LZMA public override long Length => _position + _availableBytes; - public override long Position { get => _position; set => throw new NotSupportedException(); } + public override long Position + { + get => _position; + set => throw new NotSupportedException(); + } public override int Read(byte[] buffer, int offset, int count) { @@ -189,8 +194,9 @@ namespace SharpCompress.Compressors.LZMA { _inputPosition += _outWindow.CopyStream(_inputStream, toProcess); } - else if (_decoder.Code(_dictionarySize, _outWindow, _rangeDecoder) - && _outputSize < 0) + else if ( + _decoder.Code(_dictionarySize, _outWindow, _rangeDecoder) && _outputSize < 0 + ) { _availableBytes = _outWindow.AvailableBytes; } @@ -204,7 +210,10 @@ namespace SharpCompress.Compressors.LZMA if (_availableBytes == 0 && !_uncompressedChunk) { _rangeDecoder.ReleaseStream(); - if (!_rangeDecoder.IsFinished || (_rangeDecoderLimit >= 0 && _rangeDecoder._total != _rangeDecoderLimit)) + if ( + !_rangeDecoder.IsFinished + || (_rangeDecoderLimit >= 0 && _rangeDecoder._total != _rangeDecoderLimit) + ) { throw new DataErrorException(); } diff --git a/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoder.cs b/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoder.cs index 9ea026a9..36ba6842 100644 --- a/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoder.cs +++ b/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoder.cs @@ -76,8 +76,7 @@ namespace SharpCompress.Compressors.LZMA.RangeCoder { _stream.WriteByte((byte)(temp + (_low >> 32))); temp = 0xFF; - } - while (--_cacheSize != 0); + } while (--_cacheSize != 0); _cache = (byte)(((uint)_low) >> 24); } _cacheSize++; @@ -251,4 +250,4 @@ namespace SharpCompress.Compressors.LZMA.RangeCoder // ulong GetProcessedSize() {return Stream.GetProcessedSize(); } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoderBit.cs b/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoderBit.cs index 2ab53aff..80b30bd8 100644 --- a/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoderBit.cs +++ b/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoderBit.cs @@ -52,7 +52,9 @@ namespace SharpCompress.Compressors.LZMA.RangeCoder } } - private static readonly UInt32[] PROB_PRICES = new UInt32[K_BIT_MODEL_TOTAL >> K_NUM_MOVE_REDUCING_BITS]; + private static readonly UInt32[] PROB_PRICES = new UInt32[ + K_BIT_MODEL_TOTAL >> K_NUM_MOVE_REDUCING_BITS + ]; static BitEncoder() { @@ -63,15 +65,19 @@ namespace SharpCompress.Compressors.LZMA.RangeCoder UInt32 end = (UInt32)1 << (kNumBits - i); for (UInt32 j = start; j < end; j++) { - PROB_PRICES[j] = ((UInt32)i << K_NUM_BIT_PRICE_SHIFT_BITS) + - (((end - j) << K_NUM_BIT_PRICE_SHIFT_BITS) >> (kNumBits - i - 1)); + PROB_PRICES[j] = + ((UInt32)i << K_NUM_BIT_PRICE_SHIFT_BITS) + + (((end - j) << K_NUM_BIT_PRICE_SHIFT_BITS) >> (kNumBits - i - 1)); } } } public uint GetPrice(uint symbol) { - return PROB_PRICES[(((_prob - symbol) ^ ((-(int)symbol))) & (K_BIT_MODEL_TOTAL - 1)) >> K_NUM_MOVE_REDUCING_BITS]; + return PROB_PRICES[ + (((_prob - symbol) ^ ((-(int)symbol))) & (K_BIT_MODEL_TOTAL - 1)) + >> K_NUM_MOVE_REDUCING_BITS + ]; } public uint GetPrice0() @@ -119,7 +125,8 @@ namespace SharpCompress.Compressors.LZMA.RangeCoder _prob += (K_BIT_MODEL_TOTAL - _prob) >> K_NUM_MOVE_BITS; if (rangeDecoder._range < Decoder.K_TOP_VALUE) { - rangeDecoder._code = (rangeDecoder._code << 8) | (byte)rangeDecoder._stream.ReadByte(); + rangeDecoder._code = + (rangeDecoder._code << 8) | (byte)rangeDecoder._stream.ReadByte(); rangeDecoder._range <<= 8; rangeDecoder._total++; } @@ -130,11 +137,12 @@ namespace SharpCompress.Compressors.LZMA.RangeCoder _prob -= (_prob) >> K_NUM_MOVE_BITS; if (rangeDecoder._range < Decoder.K_TOP_VALUE) { - rangeDecoder._code = (rangeDecoder._code << 8) | (byte)rangeDecoder._stream.ReadByte(); + rangeDecoder._code = + (rangeDecoder._code << 8) | (byte)rangeDecoder._stream.ReadByte(); rangeDecoder._range <<= 8; rangeDecoder._total++; } return 1; } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoderBitTree.cs b/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoderBitTree.cs index cc511603..a00a5135 100644 --- a/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoderBitTree.cs +++ b/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoderBitTree.cs @@ -24,7 +24,7 @@ namespace SharpCompress.Compressors.LZMA.RangeCoder public void Encode(Encoder rangeEncoder, UInt32 symbol) { UInt32 m = 1; - for (int bitIndex = _numBitLevels; bitIndex > 0;) + for (int bitIndex = _numBitLevels; bitIndex > 0; ) { bitIndex--; UInt32 bit = (symbol >> bitIndex) & 1; @@ -49,7 +49,7 @@ namespace SharpCompress.Compressors.LZMA.RangeCoder { UInt32 price = 0; UInt32 m = 1; - for (int bitIndex = _numBitLevels; bitIndex > 0;) + for (int bitIndex = _numBitLevels; bitIndex > 0; ) { bitIndex--; UInt32 bit = (symbol >> bitIndex) & 1; @@ -73,8 +73,12 @@ namespace SharpCompress.Compressors.LZMA.RangeCoder return price; } - public static UInt32 ReverseGetPrice(BitEncoder[] models, UInt32 startIndex, - int numBitLevels, UInt32 symbol) + public static UInt32 ReverseGetPrice( + BitEncoder[] models, + UInt32 startIndex, + int numBitLevels, + UInt32 symbol + ) { UInt32 price = 0; UInt32 m = 1; @@ -88,8 +92,13 @@ namespace SharpCompress.Compressors.LZMA.RangeCoder return price; } - public static void ReverseEncode(BitEncoder[] models, UInt32 startIndex, - Encoder rangeEncoder, int numBitLevels, UInt32 symbol) + public static void ReverseEncode( + BitEncoder[] models, + UInt32 startIndex, + Encoder rangeEncoder, + int numBitLevels, + UInt32 symbol + ) { UInt32 m = 1; for (int i = 0; i < numBitLevels; i++) @@ -145,8 +154,12 @@ namespace SharpCompress.Compressors.LZMA.RangeCoder return symbol; } - public static uint ReverseDecode(BitDecoder[] models, UInt32 startIndex, - Decoder rangeDecoder, int numBitLevels) + public static uint ReverseDecode( + BitDecoder[] models, + UInt32 startIndex, + Decoder rangeDecoder, + int numBitLevels + ) { uint m = 1; uint symbol = 0; @@ -160,4 +173,4 @@ namespace SharpCompress.Compressors.LZMA.RangeCoder return symbol; } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/LZMA/Registry.cs b/src/SharpCompress/Compressors/LZMA/Registry.cs index 8495c4bc..967d1fe7 100644 --- a/src/SharpCompress/Compressors/LZMA/Registry.cs +++ b/src/SharpCompress/Compressors/LZMA/Registry.cs @@ -22,8 +22,13 @@ namespace SharpCompress.Compressors.LZMA private const uint K_DEFLATE = 0x040108; private const uint K_B_ZIP2 = 0x040202; - internal static Stream CreateDecoderStream(CMethodId id, Stream[] inStreams, byte[] info, IPasswordProvider pass, - long limit) + internal static Stream CreateDecoderStream( + CMethodId id, + Stream[] inStreams, + byte[] info, + IPasswordProvider pass, + long limit + ) { switch (id._id) { @@ -53,4 +58,4 @@ namespace SharpCompress.Compressors.LZMA } } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/LZMA/Utilites/CrcBuilderStream.cs b/src/SharpCompress/Compressors/LZMA/Utilites/CrcBuilderStream.cs index 4410dd9a..e72c715a 100644 --- a/src/SharpCompress/Compressors/LZMA/Utilites/CrcBuilderStream.cs +++ b/src/SharpCompress/Compressors/LZMA/Utilites/CrcBuilderStream.cs @@ -46,13 +46,15 @@ namespace SharpCompress.Compressors.LZMA.Utilites public override bool CanWrite => true; - public override void Flush() - { - } + public override void Flush() { } public override long Length => throw new NotSupportedException(); - public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); } + public override long Position + { + get => throw new NotSupportedException(); + set => throw new NotSupportedException(); + } public override int Read(byte[] buffer, int offset, int count) { @@ -81,4 +83,4 @@ namespace SharpCompress.Compressors.LZMA.Utilites _mTarget.Write(buffer, offset, count); } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/LZMA/Utilites/CrcCheckStream.cs b/src/SharpCompress/Compressors/LZMA/Utilites/CrcCheckStream.cs index 9a59e26b..2f44bcc3 100644 --- a/src/SharpCompress/Compressors/LZMA/Utilites/CrcCheckStream.cs +++ b/src/SharpCompress/Compressors/LZMA/Utilites/CrcCheckStream.cs @@ -74,13 +74,15 @@ namespace SharpCompress.Compressors.LZMA.Utilites public override bool CanWrite => true; - public override void Flush() - { - } + public override void Flush() { } public override long Length => throw new NotSupportedException(); - public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); } + public override long Position + { + get => throw new NotSupportedException(); + set => throw new NotSupportedException(); + } public override int Read(byte[] buffer, int offset, int count) { diff --git a/src/SharpCompress/Compressors/LZMA/Utilites/IPasswordProvider.cs b/src/SharpCompress/Compressors/LZMA/Utilites/IPasswordProvider.cs index 51dc389e..977c86bf 100644 --- a/src/SharpCompress/Compressors/LZMA/Utilites/IPasswordProvider.cs +++ b/src/SharpCompress/Compressors/LZMA/Utilites/IPasswordProvider.cs @@ -4,4 +4,4 @@ { string CryptoGetTextPassword(); } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/PPMd/H/FreqData.cs b/src/SharpCompress/Compressors/PPMd/H/FreqData.cs index f4537c11..a139a449 100644 --- a/src/SharpCompress/Compressors/PPMd/H/FreqData.cs +++ b/src/SharpCompress/Compressors/PPMd/H/FreqData.cs @@ -14,10 +14,7 @@ namespace SharpCompress.Compressors.PPMd.H // STATE _PACK_ATTR * Stats; // }; - internal FreqData(byte[] memory) - : base(memory) - { - } + internal FreqData(byte[] memory) : base(memory) { } internal int SummFreq { diff --git a/src/SharpCompress/Compressors/PPMd/H/ModelPPM.cs b/src/SharpCompress/Compressors/PPMd/H/ModelPPM.cs index 8f0e6867..974a61ea 100644 --- a/src/SharpCompress/Compressors/PPMd/H/ModelPPM.cs +++ b/src/SharpCompress/Compressors/PPMd/H/ModelPPM.cs @@ -28,19 +28,43 @@ namespace SharpCompress.Compressors.PPMd.H public virtual int InitRl => _initRl; - public virtual int EscCount { get => _escCount; set => _escCount = value & 0xff; } + public virtual int EscCount + { + get => _escCount; + set => _escCount = value & 0xff; + } public virtual int[] CharMask => _charMask; - public virtual int NumMasked { get => _numMasked; set => _numMasked = value; } + public virtual int NumMasked + { + get => _numMasked; + set => _numMasked = value; + } - public virtual int PrevSuccess { get => _prevSuccess; set => _prevSuccess = value & 0xff; } + public virtual int PrevSuccess + { + get => _prevSuccess; + set => _prevSuccess = value & 0xff; + } - public virtual int InitEsc { get => _initEsc; set => _initEsc = value; } + public virtual int InitEsc + { + get => _initEsc; + set => _initEsc = value; + } - public virtual int RunLength { get => _runLength; set => _runLength = value; } + public virtual int RunLength + { + get => _runLength; + set => _runLength = value; + } - public virtual int HiBitsFlag { get => _hiBitsFlag; set => _hiBitsFlag = value & 0xff; } + public virtual int HiBitsFlag + { + get => _hiBitsFlag; + set => _hiBitsFlag = value & 0xff; + } public virtual int[][] BinSumm => _binSumm; @@ -77,7 +101,12 @@ namespace SharpCompress.Compressors.PPMd.H private PpmContext _maxContext; - private int _numMasked, _initEsc, _orderFall, _maxOrder, _runLength, _initRl; + private int _numMasked, + _initEsc, + _orderFall, + _maxOrder, + _runLength, + _initRl; private readonly int[] _charMask = new int[256]; @@ -88,11 +117,23 @@ namespace SharpCompress.Compressors.PPMd.H private readonly int[] _hb2Flag = new int[256]; // byte EscCount, PrevSuccess, HiBitsFlag; - private int _escCount, _prevSuccess, _hiBitsFlag; + private int _escCount, + _prevSuccess, + _hiBitsFlag; private readonly int[][] _binSumm = new int[128][]; // binary SEE-contexts - private static readonly int[] INIT_BIN_ESC = { 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051 }; + private static readonly int[] INIT_BIN_ESC = + { + 0x3CDD, + 0x1F3F, + 0x59BF, + 0x48F3, + 0x64A1, + 0x5ABC, + 0x6632, + 0x6051 + }; // Temp fields //UPGRADE_NOTE: Final was removed from the declaration of 'tempState1 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" @@ -187,7 +228,10 @@ namespace SharpCompress.Compressors.PPMd.H private void StartModelRare(int maxOrder) { - int i, k, m, step; + int i, + k, + m, + step; _escCount = 1; _maxOrder = maxOrder; RestartModelRare(); @@ -299,8 +343,10 @@ namespace SharpCompress.Compressors.PPMd.H if (_minContext.NumStats != 1) { - if (_minContext.FreqData.GetStats() <= SubAlloc.PText || - _minContext.FreqData.GetStats() > SubAlloc.HeapEnd) + if ( + _minContext.FreqData.GetStats() <= SubAlloc.PText + || _minContext.FreqData.GetStats() > SubAlloc.HeapEnd + ) { return (-1); } @@ -321,12 +367,14 @@ namespace SharpCompress.Compressors.PPMd.H { _orderFall++; _minContext.Address = _minContext.GetSuffix(); // =MinContext->Suffix; - if (_minContext.Address <= SubAlloc.PText || _minContext.Address > SubAlloc.HeapEnd) + if ( + _minContext.Address <= SubAlloc.PText + || _minContext.Address > SubAlloc.HeapEnd + ) { return (-1); } - } - while (_minContext.NumStats == _numMasked); + } while (_minContext.NumStats == _numMasked); if (!_minContext.DecodeSymbol2(this)) { return (-1); @@ -433,8 +481,7 @@ namespace SharpCompress.Compressors.PPMd.H do { p.IncrementAddress(); - } - while (p.Symbol != FoundState.Symbol); + } while (p.Symbol != FoundState.Symbol); } } else @@ -449,8 +496,7 @@ namespace SharpCompress.Compressors.PPMd.H break; } _ps[pps++] = p.Address; - } - while (pc.GetSuffix() != 0); + } while (pc.GetSuffix() != 0); } // NO_LOOP: if (pps == 0) { @@ -473,14 +519,15 @@ namespace SharpCompress.Compressors.PPMd.H do { p.IncrementAddress(); - } - while (p.Symbol != upState.Symbol); + } while (p.Symbol != upState.Symbol); } int cf = p.Freq - 1; int s0 = pc.FreqData.SummFreq - pc.NumStats - cf; // UpState.Freq=1+((2*cf <= s0)?(5*cf > s0):((2*cf+3*s0-1)/(2*s0))); - upState.Freq = 1 + ((2 * cf <= s0) ? (5 * cf > s0 ? 1 : 0) : ((2 * cf + 3 * s0 - 1) / (2 * s0))); + upState.Freq = + 1 + + ((2 * cf <= s0) ? (5 * cf > s0 ? 1 : 0) : ((2 * cf + 3 * s0 - 1) / (2 * s0))); } else { @@ -495,8 +542,7 @@ namespace SharpCompress.Compressors.PPMd.H { return 0; } - } - while (pps != 0); + } while (pps != 0); return pc.Address; } @@ -518,7 +564,11 @@ namespace SharpCompress.Compressors.PPMd.H PpmContext pc = _tempPpmContext3.Initialize(Heap); PpmContext successor = _tempPpmContext4.Initialize(Heap); - int ns1, ns, cf, sf, s0; + int ns1, + ns, + cf, + sf, + s0; pc.Address = _minContext.GetSuffix(); if (fs.Freq < MAX_FREQ / 4 && pc.Address != 0) { @@ -530,8 +580,7 @@ namespace SharpCompress.Compressors.PPMd.H do { p.IncrementAddress(); - } - while (p.Symbol != fs.Symbol); + } while (p.Symbol != fs.Symbol); tempState.Address = p.Address - State.SIZE; if (p.Freq >= tempState.Freq) { @@ -607,14 +656,20 @@ namespace SharpCompress.Compressors.PPMd.H // subAlloc.dumpHeap(); ns = _minContext.NumStats; s0 = _minContext.FreqData.SummFreq - (ns) - (fs.Freq - 1); - for (pc.Address = _maxContext.Address; pc.Address != _minContext.Address; pc.Address = pc.GetSuffix()) + for ( + pc.Address = _maxContext.Address; + pc.Address != _minContext.Address; + pc.Address = pc.GetSuffix() + ) { if ((ns1 = pc.NumStats) != 1) { if ((ns1 & 1) == 0) { //System.out.println(ns1); - pc.FreqData.SetStats(SubAlloc.ExpandUnits(pc.FreqData.GetStats(), Utility.URShift(ns1, 1))); + pc.FreqData.SetStats( + SubAlloc.ExpandUnits(pc.FreqData.GetStats(), Utility.URShift(ns1, 1)) + ); if (pc.FreqData.GetStats() == 0) { UpdateModelRestart(); @@ -626,8 +681,13 @@ namespace SharpCompress.Compressors.PPMd.H // int sum = ((2 * ns1 < ns) ? 1 : 0) + // 2 * ((4 * ((ns1 <= ns) ? 1 : 0)) & ((pc.getFreqData() // .getSummFreq() <= 8 * ns1) ? 1 : 0)); - int sum = ((2 * ns1 < ns) ? 1 : 0) + - 2 * (((4 * ns1 <= ns) ? 1 : 0) & ((pc.FreqData.SummFreq <= 8 * ns1) ? 1 : 0)); + int sum = + ((2 * ns1 < ns) ? 1 : 0) + + 2 + * ( + ((4 * ns1 <= ns) ? 1 : 0) + & ((pc.FreqData.SummFreq <= 8 * ns1) ? 1 : 0) + ); pc.FreqData.IncrementSummFreq(sum); } else @@ -659,7 +719,11 @@ namespace SharpCompress.Compressors.PPMd.H } else { - cf = 4 + (cf >= 9 * sf ? 1 : 0) + (cf >= 12 * sf ? 1 : 0) + (cf >= 15 * sf ? 1 : 0); + cf = + 4 + + (cf >= 9 * sf ? 1 : 0) + + (cf >= 12 * sf ? 1 : 0) + + (cf >= 15 * sf ? 1 : 0); pc.FreqData.IncrementSummFreq(cf); } p.Address = pc.FreqData.GetStats() + ns1 * State.SIZE; @@ -770,8 +834,12 @@ namespace SharpCompress.Compressors.PPMd.H State s = _tempState1.Initialize(Heap); s.Address = _minContext.FreqData.GetStats(); int i; - int count, hiCnt; - if ((count = (int)decoder.GetThreshold((uint)_minContext.FreqData.SummFreq)) < (hiCnt = s.Freq)) + int count, + hiCnt; + if ( + (count = (int)decoder.GetThreshold((uint)_minContext.FreqData.SummFreq)) + < (hiCnt = s.Freq) + ) { byte symbol; decoder.Decode(0, (uint)s.Freq); @@ -794,8 +862,7 @@ namespace SharpCompress.Compressors.PPMd.H NextContext(); return symbol; } - } - while (--i > 0); + } while (--i > 0); if (count >= _minContext.FreqData.SummFreq) { return -2; @@ -812,8 +879,7 @@ namespace SharpCompress.Compressors.PPMd.H { s.DecrementAddress(); _charMask[s.Symbol] = 0; - } - while (--i > 0); + } while (--i > 0); } else { @@ -826,7 +892,8 @@ namespace SharpCompress.Compressors.PPMd.H if (decoder.DecodeBit((uint)bs, 14) == 0) { byte symbol; - _binSumm[off1][off2] = (bs + INTERVAL - _minContext.GetMean(bs, PERIOD_BITS, 2)) & 0xFFFF; + _binSumm[off1][off2] = + (bs + INTERVAL - _minContext.GetMean(bs, PERIOD_BITS, 2)) & 0xFFFF; FoundState.Address = rs.Address; symbol = (byte)rs.Symbol; rs.IncrementFreq((rs.Freq < 128) ? 1 : 0); @@ -850,19 +917,24 @@ namespace SharpCompress.Compressors.PPMd.H { State s = _tempState1.Initialize(Heap); int i; - int freqSum, count, hiCnt; + int freqSum, + count, + hiCnt; See2Context see; - int num, numMasked = _minContext.NumStats; + int num, + numMasked = _minContext.NumStats; do { _orderFall++; _minContext.Address = _minContext.GetSuffix(); - if (_minContext.Address <= SubAlloc.PText || _minContext.Address > SubAlloc.HeapEnd) + if ( + _minContext.Address <= SubAlloc.PText + || _minContext.Address > SubAlloc.HeapEnd + ) { return -1; } - } - while (_minContext.NumStats == numMasked); + } while (_minContext.NumStats == numMasked); hiCnt = 0; s.Address = _minContext.FreqData.GetStats(); i = 0; @@ -874,8 +946,7 @@ namespace SharpCompress.Compressors.PPMd.H _minContext._ps[i] = s.Address; s.IncrementAddress(); i -= k; - } - while (i != num); + } while (i != num); see = _minContext.MakeEscFreq(this, numMasked, out freqSum); freqSum += hiCnt; @@ -885,9 +956,11 @@ namespace SharpCompress.Compressors.PPMd.H { byte symbol; State ps = _tempState2.Initialize(Heap); - for (hiCnt = 0, i = 0, ps.Address = _minContext._ps[i]; - (hiCnt += ps.Freq) <= count; - i++, ps.Address = _minContext._ps[i]) + for ( + hiCnt = 0, i = 0, ps.Address = _minContext._ps[i]; + (hiCnt += ps.Freq) <= count; + i++, ps.Address = _minContext._ps[i] + ) { ; } @@ -909,8 +982,7 @@ namespace SharpCompress.Compressors.PPMd.H { s.Address = _minContext._ps[--i]; _charMask[s.Symbol] = 0; - } - while (i != 0); + } while (i != 0); } } } diff --git a/src/SharpCompress/Compressors/PPMd/H/PPMContext.cs b/src/SharpCompress/Compressors/PPMd/H/PPMContext.cs index 83340887..53d9cc7f 100644 --- a/src/SharpCompress/Compressors/PPMd/H/PPMContext.cs +++ b/src/SharpCompress/Compressors/PPMd/H/PPMContext.cs @@ -24,11 +24,11 @@ namespace SharpCompress.Compressors.PPMd.H { if (Memory != null) { - _numStats = BinaryPrimitives.ReadInt16LittleEndian(Memory.AsSpan(Address)) & 0xffff; + _numStats = + BinaryPrimitives.ReadInt16LittleEndian(Memory.AsSpan(Address)) & 0xffff; } return _numStats; } - set { _numStats = value & 0xffff; @@ -61,7 +61,25 @@ namespace SharpCompress.Compressors.PPMd.H private int _suffix; // pointer ppmcontext //UPGRADE_NOTE: Final was removed from the declaration of 'ExpEscape'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly int[] EXP_ESCAPE = { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 }; + public static readonly int[] EXP_ESCAPE = + { + 25, + 14, + 9, + 7, + 5, + 5, + 4, + 4, + 4, + 3, + 3, + 3, + 2, + 2, + 2, + 2 + }; // Temp fields //UPGRADE_NOTE: Final was removed from the declaration of 'tempState1 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" @@ -83,8 +101,7 @@ namespace SharpCompress.Compressors.PPMd.H //UPGRADE_NOTE: Final was removed from the declaration of 'ps '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" internal int[] _ps = new int[256]; - public PpmContext(byte[] memory) - : base(memory) + public PpmContext(byte[] memory) : base(memory) { _oneState = new State(memory); _freqData = new FreqData(memory); @@ -166,14 +183,21 @@ namespace SharpCompress.Compressors.PPMd.H internal void Rescale(ModelPpm model) { - int oldNs = NumStats, i = NumStats - 1, adder, escFreq; + int oldNs = NumStats, + i = NumStats - 1, + adder, + escFreq; // STATE* p1, * p; State p1 = new State(model.Heap); State p = new State(model.Heap); State temp = new State(model.Heap); - for (p.Address = model.FoundState.Address; p.Address != _freqData.GetStats(); p.DecrementAddress()) + for ( + p.Address = model.FoundState.Address; + p.Address != _freqData.GetStats(); + p.DecrementAddress() + ) { temp.Address = p.Address - State.SIZE; State.PpmdSwap(p, temp); @@ -206,20 +230,17 @@ namespace SharpCompress.Compressors.PPMd.H p1.SetValues(temp2); p1.DecrementAddress(); temp3.Address = p1.Address - State.SIZE; - } - while (p1.Address != _freqData.GetStats() && tmp.Freq > temp3.Freq); + } while (p1.Address != _freqData.GetStats() && tmp.Freq > temp3.Freq); p1.SetValues(tmp); } - } - while (--i != 0); + } while (--i != 0); if (p.Freq == 0) { do { i++; p.DecrementAddress(); - } - while (p.Freq == 0); + } while (p.Freq == 0); escFreq += i; NumStats = NumStats - i; if (NumStats == 1) @@ -234,8 +255,7 @@ namespace SharpCompress.Compressors.PPMd.H // tmp.Freq-=(tmp.Freq >> 1) tmp.DecrementFreq(Utility.URShift(tmp.Freq, 1)); escFreq = Utility.URShift(escFreq, 1); - } - while (escFreq > 1); + } while (escFreq > 1); model.SubAlloc.FreeUnits(_freqData.GetStats(), Utility.URShift((oldNs + 1), 1)); _oneState.SetValues(tmp); model.FoundState.Address = _oneState.Address; @@ -244,7 +264,8 @@ namespace SharpCompress.Compressors.PPMd.H } escFreq -= Utility.URShift(escFreq, 1); _freqData.IncrementSummFreq(escFreq); - int n0 = Utility.URShift((oldNs + 1), 1), n1 = Utility.URShift((NumStats + 1), 1); + int n0 = Utility.URShift((oldNs + 1), 1), + n1 = Utility.URShift((NumStats + 1), 1); if (n0 != n1) { _freqData.SetStats(model.SubAlloc.ShrinkUnits(_freqData.GetStats(), n0, n1)); @@ -355,7 +376,8 @@ namespace SharpCompress.Compressors.PPMd.H internal bool DecodeSymbol2(ModelPpm model) { long count; - int hiCnt, i = NumStats - model.NumMasked; + int hiCnt, + i = NumStats - model.NumMasked; See2Context psee2C = MakeEscFreq2(model, i); RangeCoder coder = model.Coder; @@ -371,12 +393,10 @@ namespace SharpCompress.Compressors.PPMd.H do { p.IncrementAddress(); // p++; - } - while (model.CharMask[p.Symbol] == model.EscCount); + } while (model.CharMask[p.Symbol] == model.EscCount); hiCnt += p.Freq; _ps[pps++] = p.Address; - } - while (--i != 0); + } while (--i != 0); coder.SubRange.IncScale(hiCnt); count = coder.CurrentCount; if (count >= coder.SubRange.Scale) @@ -407,8 +427,7 @@ namespace SharpCompress.Compressors.PPMd.H { temp.Address = _ps[++pps]; // (*++pps) model.CharMask[temp.Symbol] = model.EscCount; - } - while (--i != 0); + } while (--i != 0); psee2C.IncSumm((int)coder.SubRange.Scale); model.NumMasked = NumStats; } @@ -487,7 +506,8 @@ namespace SharpCompress.Compressors.PPMd.H coder.SubRange.Scale = _freqData.SummFreq; State p = new State(model.Heap); p.Address = _freqData.GetStats(); - int i, hiCnt; + int i, + hiCnt; long count = coder.CurrentCount; if (count >= coder.SubRange.Scale) { @@ -529,8 +549,7 @@ namespace SharpCompress.Compressors.PPMd.H do { model.CharMask[p.DecrementAddress().Symbol] = model.EscCount; - } - while (--i != 0); + } while (--i != 0); coder.SubRange.HighCount = coder.SubRange.Scale; return (true); } diff --git a/src/SharpCompress/Compressors/PPMd/H/Pointer.cs b/src/SharpCompress/Compressors/PPMd/H/Pointer.cs index 98f0a9cb..40a15c30 100644 --- a/src/SharpCompress/Compressors/PPMd/H/Pointer.cs +++ b/src/SharpCompress/Compressors/PPMd/H/Pointer.cs @@ -16,12 +16,11 @@ namespace SharpCompress.Compressors.PPMd.H internal virtual int Address { get; set; } - protected T Initialize(byte[] mem) - where T : Pointer + protected T Initialize(byte[] mem) where T : Pointer { Memory = mem; Address = 0; return this as T; } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/PPMd/H/RangeCoder.cs b/src/SharpCompress/Compressors/PPMd/H/RangeCoder.cs index ce778e19..1d87849b 100644 --- a/src/SharpCompress/Compressors/PPMd/H/RangeCoder.cs +++ b/src/SharpCompress/Compressors/PPMd/H/RangeCoder.cs @@ -14,7 +14,9 @@ namespace SharpCompress.Compressors.PPMd.H internal const long UINT_MASK = 0xFFFFffffL; // uint low, code, range; - private long _low, _code, _range; + private long _low, + _code, + _range; private readonly IRarUnpack _unpackRead; private readonly Stream _stream; @@ -126,18 +128,32 @@ namespace SharpCompress.Compressors.PPMd.H internal class SubRange { // uint LowCount, HighCount, scale; - private long _lowCount, _highCount, _scale; + private long _lowCount, + _highCount, + _scale; internal void IncScale(int dScale) { Scale = Scale + dScale; } - internal long HighCount { get => _highCount; set => _highCount = value & RangeCoder.UINT_MASK; } + internal long HighCount + { + get => _highCount; + set => _highCount = value & RangeCoder.UINT_MASK; + } - internal long LowCount { get => _lowCount & RangeCoder.UINT_MASK; set => _lowCount = value & RangeCoder.UINT_MASK; } + internal long LowCount + { + get => _lowCount & RangeCoder.UINT_MASK; + set => _lowCount = value & RangeCoder.UINT_MASK; + } - internal long Scale { get => _scale; set => _scale = value & RangeCoder.UINT_MASK; } + internal long Scale + { + get => _scale; + set => _scale = value & RangeCoder.UINT_MASK; + } // Debug public override String ToString() diff --git a/src/SharpCompress/Compressors/PPMd/H/RarMemBlock.cs b/src/SharpCompress/Compressors/PPMd/H/RarMemBlock.cs index 2c63811f..b067fac8 100644 --- a/src/SharpCompress/Compressors/PPMd/H/RarMemBlock.cs +++ b/src/SharpCompress/Compressors/PPMd/H/RarMemBlock.cs @@ -7,14 +7,13 @@ namespace SharpCompress.Compressors.PPMd.H { public const int SIZE = 12; - private int _stamp, _nu; + private int _stamp, + _nu; - private int _next, _prev; // Pointer RarMemBlock + private int _next, + _prev; // Pointer RarMemBlock - public RarMemBlock(byte[] memory) - : base(memory) - { - } + public RarMemBlock(byte[] memory) : base(memory) { } internal int Stamp { @@ -22,11 +21,11 @@ namespace SharpCompress.Compressors.PPMd.H { if (Memory != null) { - _stamp = BinaryPrimitives.ReadInt16LittleEndian(Memory.AsSpan(Address)) & 0xffff; + _stamp = + BinaryPrimitives.ReadInt16LittleEndian(Memory.AsSpan(Address)) & 0xffff; } return _stamp; } - set { _stamp = value; diff --git a/src/SharpCompress/Compressors/PPMd/H/RarNode.cs b/src/SharpCompress/Compressors/PPMd/H/RarNode.cs index f6db5cf7..15775229 100644 --- a/src/SharpCompress/Compressors/PPMd/H/RarNode.cs +++ b/src/SharpCompress/Compressors/PPMd/H/RarNode.cs @@ -10,10 +10,7 @@ namespace SharpCompress.Compressors.PPMd.H public const int SIZE = 4; - public RarNode(byte[] memory) - : base(memory) - { - } + public RarNode(byte[] memory) : base(memory) { } internal int GetNext() { diff --git a/src/SharpCompress/Compressors/PPMd/H/SEE2Context.cs b/src/SharpCompress/Compressors/PPMd/H/SEE2Context.cs index c97f0836..dd4fa7c6 100644 --- a/src/SharpCompress/Compressors/PPMd/H/SEE2Context.cs +++ b/src/SharpCompress/Compressors/PPMd/H/SEE2Context.cs @@ -15,11 +15,23 @@ namespace SharpCompress.Compressors.PPMd.H } } - public virtual int Count { get => _count; set => _count = value & 0xff; } + public virtual int Count + { + get => _count; + set => _count = value & 0xff; + } - public virtual int Shift { get => _shift; set => _shift = value & 0xff; } + public virtual int Shift + { + get => _shift; + set => _shift = value & 0xff; + } - public virtual int Summ { get => _summ; set => _summ = value & 0xffff; } + public virtual int Summ + { + get => _summ; + set => _summ = value & 0xffff; + } public const int SIZE = 4; @@ -72,4 +84,4 @@ namespace SharpCompress.Compressors.PPMd.H return buffer.ToString(); } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/PPMd/H/State.cs b/src/SharpCompress/Compressors/PPMd/H/State.cs index e9d1a48c..6ce6d2d0 100644 --- a/src/SharpCompress/Compressors/PPMd/H/State.cs +++ b/src/SharpCompress/Compressors/PPMd/H/State.cs @@ -8,14 +8,19 @@ namespace SharpCompress.Compressors.PPMd.H { internal const int SIZE = 6; - internal State(byte[]? memory) - : base(memory) + internal State(byte[]? memory) : base(memory) { } + + internal int Symbol { + get => Memory[Address] & 0xff; + set => Memory[Address] = (byte)value; } - internal int Symbol { get => Memory[Address] & 0xff; set => Memory[Address] = (byte)value; } - - internal int Freq { get => Memory[Address + 1] & 0xff; set => Memory[Address + 1] = (byte)value; } + internal int Freq + { + get => Memory[Address + 1] & 0xff; + set => Memory[Address + 1] = (byte)value; + } internal State Initialize(byte[] mem) { @@ -68,7 +73,8 @@ namespace SharpCompress.Compressors.PPMd.H internal static void PpmdSwap(State ptr1, State ptr2) { - byte[] mem1 = ptr1.Memory, mem2 = ptr2.Memory; + byte[] mem1 = ptr1.Memory, + mem2 = ptr2.Memory; for (int i = 0, pos1 = ptr1.Address, pos2 = ptr2.Address; i < SIZE; i++, pos1++, pos2++) { byte temp = mem1[pos1]; diff --git a/src/SharpCompress/Compressors/PPMd/H/StateRef.cs b/src/SharpCompress/Compressors/PPMd/H/StateRef.cs index f1e8e90f..686c1128 100644 --- a/src/SharpCompress/Compressors/PPMd/H/StateRef.cs +++ b/src/SharpCompress/Compressors/PPMd/H/StateRef.cs @@ -11,9 +11,17 @@ namespace SharpCompress.Compressors.PPMd.H private int _successor; // pointer ppmcontext - internal int Symbol { get => _symbol; set => _symbol = value & 0xff; } + internal int Symbol + { + get => _symbol; + set => _symbol = value & 0xff; + } - internal int Freq { get => _freq; set => _freq = value & 0xff; } + internal int Freq + { + get => _freq; + set => _freq = value & 0xff; + } internal State Values { @@ -64,4 +72,4 @@ namespace SharpCompress.Compressors.PPMd.H return buffer.ToString(); } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/PPMd/H/SubAllocator.cs b/src/SharpCompress/Compressors/PPMd/H/SubAllocator.cs index 39a808d5..dba09739 100644 --- a/src/SharpCompress/Compressors/PPMd/H/SubAllocator.cs +++ b/src/SharpCompress/Compressors/PPMd/H/SubAllocator.cs @@ -7,13 +7,25 @@ namespace SharpCompress.Compressors.PPMd.H { internal class SubAllocator { - public virtual int FakeUnitsStart { get => _fakeUnitsStart; set => _fakeUnitsStart = value; } + public virtual int FakeUnitsStart + { + get => _fakeUnitsStart; + set => _fakeUnitsStart = value; + } public virtual int HeapEnd => _heapEnd; - public virtual int PText { get => _pText; set => _pText = value; } + public virtual int PText + { + get => _pText; + set => _pText = value; + } - public virtual int UnitsStart { get => _unitsStart; set => _unitsStart = value; } + public virtual int UnitsStart + { + get => _unitsStart; + set => _unitsStart = value; + } public virtual byte[] Heap => _heap; @@ -40,13 +52,18 @@ namespace SharpCompress.Compressors.PPMd.H private int _glueCount; // byte *HeapStart,*LoUnit, *HiUnit; - private int _heapStart, _loUnit, _hiUnit; + private int _heapStart, + _loUnit, + _hiUnit; //UPGRADE_NOTE: Final was removed from the declaration of 'freeList '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" private readonly RarNode[] _freeList = new RarNode[N_INDEXES]; // byte *pText, *UnitsStart,*HeapEnd,*FakeUnitsStart; - private int _pText, _unitsStart, _heapEnd, _fakeUnitsStart; + private int _pText, + _unitsStart, + _heapEnd, + _fakeUnitsStart; private byte[] _heap; @@ -106,7 +123,8 @@ namespace SharpCompress.Compressors.PPMd.H private void SplitBlock(int pv, int oldIndx, int newIndx) { - int i, uDiff = _indx2Units[oldIndx] - _indx2Units[newIndx]; + int i, + uDiff = _indx2Units[oldIndx] - _indx2Units[newIndx]; int p = pv + U2B(_indx2Units[newIndx]); if (_indx2Units[i = _units2Indx[uDiff - 1]] != uDiff) { @@ -193,7 +211,9 @@ namespace SharpCompress.Compressors.PPMd.H s0.Address = _tempMemBlockPos; RarMemBlock p = _tempRarMemBlock2; RarMemBlock p1 = _tempRarMemBlock3; - int i, k, sz; + int i, + k, + sz; if (_loUnit != _hiUnit) { _heap[_loUnit] = 0; @@ -227,7 +247,11 @@ namespace SharpCompress.Compressors.PPMd.H p.Address = s0.GetNext(); while (p.Address != s0.Address) { - for (p.Remove(), sz = p.GetNu(); sz > 128; sz -= 128, p.Address = MbPtr(p.Address, 128)) + for ( + p.Remove(), sz = p.GetNu(); + sz > 128; + sz -= 128, p.Address = MbPtr(p.Address, 128) + ) { InsertNode(p.Address, N_INDEXES - 1); } @@ -268,8 +292,7 @@ namespace SharpCompress.Compressors.PPMd.H } return (0); } - } - while (_freeList[i].GetNext() == 0); + } while (_freeList[i].GetNext() == 0); int retVal = RemoveNode(i); SplitBlock(retVal, i, indx); return retVal; @@ -361,7 +384,8 @@ namespace SharpCompress.Compressors.PPMd.H public virtual void InitSubAllocator() { - int i, k; + int i, + k; new Span(_heap, _freeListPos, SizeOfFreeList()).Clear(); _pText = _heapStart; diff --git a/src/SharpCompress/Compressors/PPMd/I1/Allocator.cs b/src/SharpCompress/Compressors/PPMd/I1/Allocator.cs index 269e44c1..39a0c94d 100644 --- a/src/SharpCompress/Compressors/PPMd/I1/Allocator.cs +++ b/src/SharpCompress/Compressors/PPMd/I1/Allocator.cs @@ -102,7 +102,10 @@ namespace SharpCompress.Compressors.PPMd.I1 { for (int index = 0; index < INDEX_COUNT; index++) { - _memoryNodes[index] = new MemoryNode((uint)(NODE_OFFSET + index * MemoryNode.SIZE), _memory); + _memoryNodes[index] = new MemoryNode( + (uint)(NODE_OFFSET + index * MemoryNode.SIZE), + _memory + ); _memoryNodes[index].Stamp = 0; _memoryNodes[index].Next = MemoryNode.ZERO; _memoryNodes[index].UnitCount = 0; @@ -335,7 +338,11 @@ namespace SharpCompress.Compressors.PPMd.I1 for (uint index = 0; index < INDEX_COUNT; index++) { - for (memoryNode = _memoryNodes[index]; counts[index] != 0; memoryNode = memoryNode.Next) + for ( + memoryNode = _memoryNodes[index]; + counts[index] != 0; + memoryNode = memoryNode.Next + ) { while (memoryNode.Next.Stamp == 0) { @@ -374,8 +381,7 @@ namespace SharpCompress.Compressors.PPMd.I1 oldIndex = INDEX_TO_UNITS[index] * UNIT_SIZE; return (_baseUnit - _text > oldIndex) ? (_baseUnit -= oldIndex) : Pointer.ZERO; } - } - while (!_memoryNodes[oldIndex].Available); + } while (!_memoryNodes[oldIndex].Available); Pointer allocatedBlock = _memoryNodes[oldIndex].Remove(); SplitBlock(allocatedBlock, oldIndex, index); @@ -396,7 +402,10 @@ namespace SharpCompress.Compressors.PPMd.I1 unitCountDifference -= unitCount; } - _memoryNodes[UNITS_TO_INDEX[unitCountDifference - 1]].Insert(newPointer, unitCountDifference); + _memoryNodes[UNITS_TO_INDEX[unitCountDifference - 1]].Insert( + newPointer, + unitCountDifference + ); } private void GlueFreeBlocks() @@ -425,7 +434,10 @@ namespace SharpCompress.Compressors.PPMd.I1 memoryNode0 = _memoryNodes[index].Remove(); if (memoryNode0.UnitCount != 0) { - while ((memoryNode2 = memoryNode0 + memoryNode0.UnitCount).Stamp == uint.MaxValue) + while ( + (memoryNode2 = memoryNode0 + memoryNode0.UnitCount).Stamp + == uint.MaxValue + ) { memoryNode0.UnitCount = memoryNode0.UnitCount + memoryNode2.UnitCount; memoryNode2.UnitCount = 0; @@ -453,8 +465,10 @@ namespace SharpCompress.Compressors.PPMd.I1 if (INDEX_TO_UNITS[index] != unitCount) { uint unitCountDifference = unitCount - INDEX_TO_UNITS[--index]; - _memoryNodes[unitCountDifference - 1].Insert(memoryNode0 + (unitCount - unitCountDifference), - unitCountDifference); + _memoryNodes[unitCountDifference - 1].Insert( + memoryNode0 + (unitCount - unitCountDifference), + unitCountDifference + ); } _memoryNodes[index].Insert(memoryNode0, INDEX_TO_UNITS[index]); @@ -482,10 +496,9 @@ namespace SharpCompress.Compressors.PPMd.I1 target[11] = source[11]; target += UNIT_SIZE; source += UNIT_SIZE; - } - while (--unitCount != 0); + } while (--unitCount != 0); } #endregion } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/PPMd/I1/Coder.cs b/src/SharpCompress/Compressors/PPMd/I1/Coder.cs index a5c0d862..7f398284 100644 --- a/src/SharpCompress/Compressors/PPMd/I1/Coder.cs +++ b/src/SharpCompress/Compressors/PPMd/I1/Coder.cs @@ -33,8 +33,11 @@ namespace SharpCompress.Compressors.PPMd.I1 public void RangeEncoderNormalize(Stream stream) { - while ((_low ^ (_low + _range)) < RANGE_TOP || - _range < RANGE_BOTTOM && ((_range = (uint)-_low & (RANGE_BOTTOM - 1)) != 0 || true)) + while ( + (_low ^ (_low + _range)) < RANGE_TOP + || _range < RANGE_BOTTOM + && ((_range = (uint)-_low & (RANGE_BOTTOM - 1)) != 0 || true) + ) { stream.WriteByte((byte)(_low >> 24)); _range <<= 8; @@ -76,8 +79,11 @@ namespace SharpCompress.Compressors.PPMd.I1 public void RangeDecoderNormalize(Stream stream) { - while ((_low ^ (_low + _range)) < RANGE_TOP || - _range < RANGE_BOTTOM && ((_range = (uint)-_low & (RANGE_BOTTOM - 1)) != 0 || true)) + while ( + (_low ^ (_low + _range)) < RANGE_TOP + || _range < RANGE_BOTTOM + && ((_range = (uint)-_low & (RANGE_BOTTOM - 1)) != 0 || true) + ) { _code = (_code << 8) | (byte)stream.ReadByte(); _range <<= 8; @@ -101,4 +107,4 @@ namespace SharpCompress.Compressors.PPMd.I1 _range *= _highCount - _lowCount; } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/PPMd/I1/MemoryNode.cs b/src/SharpCompress/Compressors/PPMd/I1/MemoryNode.cs index aee8b181..1c6429ad 100644 --- a/src/SharpCompress/Compressors/PPMd/I1/MemoryNode.cs +++ b/src/SharpCompress/Compressors/PPMd/I1/MemoryNode.cs @@ -44,8 +44,11 @@ namespace SharpCompress.Compressors.PPMd.I1 /// public uint Stamp { - get => _memory[_address] | ((uint)_memory[_address + 1]) << 8 | ((uint)_memory[_address + 2]) << 16 | - ((uint)_memory[_address + 3]) << 24; + get => + _memory[_address] + | ((uint)_memory[_address + 1]) << 8 + | ((uint)_memory[_address + 2]) << 16 + | ((uint)_memory[_address + 3]) << 24; set { _memory[_address] = (byte)value; @@ -60,9 +63,14 @@ namespace SharpCompress.Compressors.PPMd.I1 /// public MemoryNode Next { - get => new MemoryNode( - _memory[_address + 4] | ((uint)_memory[_address + 5]) << 8 | - ((uint)_memory[_address + 6]) << 16 | ((uint)_memory[_address + 7]) << 24, _memory); + get => + new MemoryNode( + _memory[_address + 4] + | ((uint)_memory[_address + 5]) << 8 + | ((uint)_memory[_address + 6]) << 16 + | ((uint)_memory[_address + 7]) << 24, + _memory + ); set { _memory[_address + 4] = (byte)value._address; @@ -77,8 +85,11 @@ namespace SharpCompress.Compressors.PPMd.I1 /// public uint UnitCount { - get => _memory[_address + 8] | ((uint)_memory[_address + 9]) << 8 | - ((uint)_memory[_address + 10]) << 16 | ((uint)_memory[_address + 11]) << 24; + get => + _memory[_address + 8] + | ((uint)_memory[_address + 9]) << 8 + | ((uint)_memory[_address + 10]) << 16 + | ((uint)_memory[_address + 11]) << 24; set { _memory[_address + 8] = (byte)value; @@ -240,4 +251,4 @@ namespace SharpCompress.Compressors.PPMd.I1 return _address.GetHashCode(); } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/PPMd/I1/Model.cs b/src/SharpCompress/Compressors/PPMd/I1/Model.cs index 347057eb..d7f67b8b 100644 --- a/src/SharpCompress/Compressors/PPMd/I1/Model.cs +++ b/src/SharpCompress/Compressors/PPMd/I1/Model.cs @@ -52,11 +52,18 @@ namespace SharpCompress.Compressors.PPMd.I1 private static readonly ushort[] INITIAL_BINARY_ESCAPES = { - 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, + 0x3CDD, + 0x1F3F, + 0x59BF, + 0x48F3, + 0x64A1, + 0x5ABC, + 0x6632, 0x6051 }; - private static ReadOnlySpan EXPONENTIAL_ESCAPES => new byte[] { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 }; + private static ReadOnlySpan EXPONENTIAL_ESCAPES => + new byte[] { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 }; #region Public Methods @@ -200,8 +207,7 @@ namespace SharpCompress.Compressors.PPMd.I1 { goto StopEncoding; } - } - while (_minimumContext.NumberStatistics == _numberMasked); + } while (_minimumContext.NumberStatistics == _numberMasked); EncodeSymbol2(c, _minimumContext); _coder.RangeEncodeSymbol(); } @@ -222,7 +228,7 @@ namespace SharpCompress.Compressors.PPMd.I1 _coder.RangeEncoderNormalize(target); } - StopEncoding: + StopEncoding: _coder.RangeEncoderFlush(target); } @@ -293,8 +299,7 @@ namespace SharpCompress.Compressors.PPMd.I1 { goto StopDecoding; } - } - while (_minimumContext.NumberStatistics == _numberMasked); + } while (_minimumContext.NumberStatistics == _numberMasked); DecodeSymbol2(_minimumContext); _coder.RangeRemoveSubrange(); } @@ -321,7 +326,7 @@ namespace SharpCompress.Compressors.PPMd.I1 _coder.RangeDecoderNormalize(source); } - StopDecoding: + StopDecoding: return total; } @@ -344,7 +349,11 @@ namespace SharpCompress.Compressors.PPMd.I1 if (modelOrder < 2) { _orderFall = _modelOrder; - for (PpmContext context = _maximumContext; context.Suffix != PpmContext.ZERO; context = context.Suffix) + for ( + PpmContext context = _maximumContext; + context.Suffix != PpmContext.ZERO; + context = context.Suffix + ) { _orderFall--; } @@ -386,14 +395,18 @@ namespace SharpCompress.Compressors.PPMd.I1 } for (int index2 = 0; index2 < 8; index2++) { - _binarySummary[probability, index2] = - (ushort)(BINARY_SCALE - INITIAL_BINARY_ESCAPES[index2] / (index1 + 1)); + _binarySummary[probability, index2] = (ushort)( + BINARY_SCALE - INITIAL_BINARY_ESCAPES[index2] / (index1 + 1) + ); } for (int index2 = 8; index2 < 64; index2 += 8) { for (int index3 = 0; index3 < 8; index3++) { - _binarySummary[probability, index2 + index3] = _binarySummary[probability, index3]; + _binarySummary[probability, index2 + index3] = _binarySummary[ + probability, + index3 + ]; } } } @@ -441,8 +454,7 @@ namespace SharpCompress.Compressors.PPMd.I1 { symbol = state[1].Symbol; state++; - } - while (symbol != foundStateSymbol); + } while (symbol != foundStateSymbol); if (state[0].Frequency >= state[-1].Frequency) { Swap(state[0], state[-1]); @@ -526,7 +538,9 @@ namespace SharpCompress.Compressors.PPMd.I1 } currentContext.Statistics = state; } - currentContext.SummaryFrequency += (ushort)((3 * ns1 + 1 < numberStatistics) ? 1 : 0); + currentContext.SummaryFrequency += (ushort)( + (3 * ns1 + 1 < numberStatistics) ? 1 : 0 + ); } else { @@ -545,8 +559,9 @@ namespace SharpCompress.Compressors.PPMd.I1 { state.Frequency = (byte)(MAXIMUM_FREQUENCY - 4); } - currentContext.SummaryFrequency = - (ushort)(state.Frequency + _initialEscape + ((numberStatistics > 2) ? 1 : 0)); + currentContext.SummaryFrequency = (ushort)( + state.Frequency + _initialEscape + ((numberStatistics > 2) ? 1 : 0) + ); } cf = (uint)(2 * foundStateFrequency * (currentContext.SummaryFrequency + 6)); @@ -559,7 +574,12 @@ namespace SharpCompress.Compressors.PPMd.I1 } else { - cf = (uint)(4 + ((cf > 9 * sf) ? 1 : 0) + ((cf > 12 * sf) ? 1 : 0) + ((cf > 15 * sf) ? 1 : 0)); + cf = (uint)( + 4 + + ((cf > 9 * sf) ? 1 : 0) + + ((cf > 12 * sf) ? 1 : 0) + + ((cf > 15 * sf) ? 1 : 0) + ); currentContext.SummaryFrequency += (ushort)cf; } @@ -573,7 +593,7 @@ namespace SharpCompress.Compressors.PPMd.I1 _maximumContext = foundStateSuccessor; return; - RestartModel: + RestartModel: RestoreModel(currentContext, minimumContext, foundStateSuccessor); } @@ -619,8 +639,7 @@ namespace SharpCompress.Compressors.PPMd.I1 { temporary = state[1].Symbol; state++; - } - while (temporary != symbol); + } while (temporary != symbol); } temporary = (byte)((state.Frequency < MAXIMUM_FREQUENCY - 9) ? 1 : 0); state.Frequency += temporary; @@ -629,21 +648,22 @@ namespace SharpCompress.Compressors.PPMd.I1 else { state = context.FirstState; - state.Frequency += - (byte)(((context.Suffix.NumberStatistics == 0) ? 1 : 0) & ((state.Frequency < 24) ? 1 : 0)); + state.Frequency += (byte)( + ((context.Suffix.NumberStatistics == 0) ? 1 : 0) + & ((state.Frequency < 24) ? 1 : 0) + ); } - LoopEntry: + LoopEntry: if (state.Successor != upBranch) { context = state.Successor; break; } states[stateIndex++] = state; - } - while (context.Suffix != PpmContext.ZERO); + } while (context.Suffix != PpmContext.ZERO); - NoLoop: + NoLoop: if (stateIndex == 0) { return context; @@ -667,12 +687,13 @@ namespace SharpCompress.Compressors.PPMd.I1 { temporary = state[1].Symbol; state++; - } - while (temporary != symbol); + } while (temporary != symbol); } uint cf = (uint)(state.Frequency - 1); uint s0 = (uint)(context.SummaryFrequency - context.NumberStatistics - cf); - localFrequency = (byte)(1 + ((2 * cf <= s0) ? (uint)((5 * cf > s0) ? 1 : 0) : ((cf + 2 * s0 - 3) / s0))); + localFrequency = (byte)( + 1 + ((2 * cf <= s0) ? (uint)((5 * cf > s0) ? 1 : 0) : ((cf + 2 * s0 - 3) / s0)) + ); } else { @@ -694,8 +715,7 @@ namespace SharpCompress.Compressors.PPMd.I1 currentContext.Suffix = context; context = currentContext; states[--stateIndex].Successor = context; - } - while (stateIndex != 0); + } while (stateIndex != 0); return context; } @@ -736,8 +756,7 @@ namespace SharpCompress.Compressors.PPMd.I1 do { states[--stateIndex].Successor = context; - } - while (stateIndex != 0); + } while (stateIndex != 0); _allocator._text = _allocator._heap + 1; _orderFall = 1; } @@ -754,8 +773,7 @@ namespace SharpCompress.Compressors.PPMd.I1 { temporary = state[1].Symbol; state++; - } - while (temporary != symbol); + } while (temporary != symbol); } temporary = (byte)((state.Frequency < MAXIMUM_FREQUENCY - 9) ? 2 : 0); state.Frequency += temporary; @@ -767,7 +785,7 @@ namespace SharpCompress.Compressors.PPMd.I1 state.Frequency += (byte)((state.Frequency < 32) ? 1 : 0); } - LoopEntry: + LoopEntry: if (state.Successor != PpmContext.ZERO) { break; @@ -783,8 +801,7 @@ namespace SharpCompress.Compressors.PPMd.I1 do { states[--stateIndex].Successor = context; - } - while (stateIndex != 0); + } while (stateIndex != 0); _allocator._text = _allocator._heap + 1; _orderFall = 1; return context; @@ -806,26 +823,41 @@ namespace SharpCompress.Compressors.PPMd.I1 return state.Successor; } - private void RestoreModel(PpmContext context, PpmContext minimumContext, PpmContext foundStateSuccessor) + private void RestoreModel( + PpmContext context, + PpmContext minimumContext, + PpmContext foundStateSuccessor + ) { PpmContext currentContext; _allocator._text = _allocator._heap; - for (currentContext = _maximumContext; currentContext != context; currentContext = currentContext.Suffix) + for ( + currentContext = _maximumContext; + currentContext != context; + currentContext = currentContext.Suffix + ) { if (--currentContext.NumberStatistics == 0) { - currentContext.Flags = - (byte) - ((currentContext.Flags & 0x10) + ((currentContext.Statistics.Symbol >= 0x40) ? 0x08 : 0x00)); + currentContext.Flags = (byte)( + (currentContext.Flags & 0x10) + + ((currentContext.Statistics.Symbol >= 0x40) ? 0x08 : 0x00) + ); PpmState state = currentContext.Statistics; Copy(currentContext.FirstState, state); _allocator.SpecialFreeUnits(state); - currentContext.FirstStateFrequency = (byte)((currentContext.FirstStateFrequency + 11) >> 3); + currentContext.FirstStateFrequency = (byte)( + (currentContext.FirstStateFrequency + 11) >> 3 + ); } else { - Refresh((uint)((currentContext.NumberStatistics + 3) >> 1), false, currentContext); + Refresh( + (uint)((currentContext.NumberStatistics + 3) >> 1), + false, + currentContext + ); } } @@ -833,18 +865,29 @@ namespace SharpCompress.Compressors.PPMd.I1 { if (currentContext.NumberStatistics == 0) { - currentContext.FirstStateFrequency -= (byte)(currentContext.FirstStateFrequency >> 1); + currentContext.FirstStateFrequency -= (byte)( + currentContext.FirstStateFrequency >> 1 + ); } - else if ((currentContext.SummaryFrequency += 4) > 128 + 4 * currentContext.NumberStatistics) + else if ( + (currentContext.SummaryFrequency += 4) + > 128 + 4 * currentContext.NumberStatistics + ) { - Refresh((uint)((currentContext.NumberStatistics + 2) >> 1), true, currentContext); + Refresh( + (uint)((currentContext.NumberStatistics + 2) >> 1), + true, + currentContext + ); } } if (_method > ModelRestorationMethod.Freeze) { _maximumContext = foundStateSuccessor; - _allocator._glueCount += (uint)(((_allocator._memoryNodes[1].Stamp & 1) == 0) ? 1 : 0); + _allocator._glueCount += (uint)( + ((_allocator._memoryNodes[1].Stamp & 1) == 0) ? 1 : 0 + ); } else if (_method == ModelRestorationMethod.Freeze) { @@ -858,8 +901,10 @@ namespace SharpCompress.Compressors.PPMd.I1 _allocator._glueCount = 0; _orderFall = _modelOrder; } - else if (_method == ModelRestorationMethod.Restart || - _allocator.GetMemoryUsed() < (_allocator._allocatorSize >> 1)) + else if ( + _method == ModelRestorationMethod.Restart + || _allocator.GetMemoryUsed() < (_allocator._allocatorSize >> 1) + ) { StartModel(_modelOrder, _method); _escapeCount = 0; @@ -875,8 +920,7 @@ namespace SharpCompress.Compressors.PPMd.I1 { CutOff(0, _maximumContext); _allocator.ExpandText(); - } - while (_allocator.GetMemoryUsed() > 3 * (_allocator._allocatorSize >> 2)); + } while (_allocator.GetMemoryUsed() > 3 * (_allocator._allocatorSize >> 2)); _allocator._glueCount = 0; _orderFall = _modelOrder; @@ -918,4 +962,4 @@ namespace SharpCompress.Compressors.PPMd.I1 #endregion } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/PPMd/I1/ModelRestorationMethod.cs b/src/SharpCompress/Compressors/PPMd/I1/ModelRestorationMethod.cs index 720e9d99..9e89d9da 100644 --- a/src/SharpCompress/Compressors/PPMd/I1/ModelRestorationMethod.cs +++ b/src/SharpCompress/Compressors/PPMd/I1/ModelRestorationMethod.cs @@ -26,4 +26,4 @@ namespace SharpCompress.Compressors.PPMd.I1 /// Freeze = 2 } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/PPMd/I1/Pointer.cs b/src/SharpCompress/Compressors/PPMd/I1/Pointer.cs index b17343e7..05748848 100644 --- a/src/SharpCompress/Compressors/PPMd/I1/Pointer.cs +++ b/src/SharpCompress/Compressors/PPMd/I1/Pointer.cs @@ -46,7 +46,9 @@ namespace SharpCompress.Compressors.PPMd.I1 #if DEBUG if (_address == 0) { - throw new InvalidOperationException("The pointer being indexed is a null pointer."); + throw new InvalidOperationException( + "The pointer being indexed is a null pointer." + ); } #endif return _memory[_address + offset]; @@ -56,7 +58,9 @@ namespace SharpCompress.Compressors.PPMd.I1 #if DEBUG if (_address == 0) { - throw new InvalidOperationException("The pointer being indexed is a null pointer."); + throw new InvalidOperationException( + "The pointer being indexed is a null pointer." + ); } #endif _memory[_address + offset] = value; @@ -139,7 +143,9 @@ namespace SharpCompress.Compressors.PPMd.I1 #if DEBUG if (pointer._address == 0) { - throw new InvalidOperationException("The pointer being incremented is a null pointer."); + throw new InvalidOperationException( + "The pointer being incremented is a null pointer." + ); } #endif pointer._address++; @@ -192,7 +198,9 @@ namespace SharpCompress.Compressors.PPMd.I1 #if DEBUG if (pointer._address == 0) { - throw new InvalidOperationException("The pointer being decremented is a null pointer."); + throw new InvalidOperationException( + "The pointer being decremented is a null pointer." + ); } #endif pointer._address--; @@ -211,12 +219,14 @@ namespace SharpCompress.Compressors.PPMd.I1 if (pointer1._address == 0) { throw new InvalidOperationException( - "The pointer to the left of the subtraction operator is a null pointer."); + "The pointer to the left of the subtraction operator is a null pointer." + ); } if (pointer2._address == 0) { throw new InvalidOperationException( - "The pointer to the right of the subtraction operator is a null pointer."); + "The pointer to the right of the subtraction operator is a null pointer." + ); } #endif return pointer1._address - pointer2._address; @@ -234,12 +244,14 @@ namespace SharpCompress.Compressors.PPMd.I1 if (pointer1._address == 0) { throw new InvalidOperationException( - "The pointer to the left of the less than operator is a null pointer."); + "The pointer to the left of the less than operator is a null pointer." + ); } if (pointer2._address == 0) { throw new InvalidOperationException( - "The pointer to the right of the less than operator is a null pointer."); + "The pointer to the right of the less than operator is a null pointer." + ); } #endif return pointer1._address < pointer2._address; @@ -257,12 +269,14 @@ namespace SharpCompress.Compressors.PPMd.I1 if (pointer1._address == 0) { throw new InvalidOperationException( - "The pointer to the left of the less than or equal to operator is a null pointer."); + "The pointer to the left of the less than or equal to operator is a null pointer." + ); } if (pointer2._address == 0) { throw new InvalidOperationException( - "The pointer to the right of the less than or equal to operator is a null pointer."); + "The pointer to the right of the less than or equal to operator is a null pointer." + ); } #endif return pointer1._address <= pointer2._address; @@ -280,12 +294,14 @@ namespace SharpCompress.Compressors.PPMd.I1 if (pointer1._address == 0) { throw new InvalidOperationException( - "The pointer to the left of the greater than operator is a null pointer."); + "The pointer to the left of the greater than operator is a null pointer." + ); } if (pointer2._address == 0) { throw new InvalidOperationException( - "The pointer to the right of the greater than operator is a null pointer."); + "The pointer to the right of the greater than operator is a null pointer." + ); } #endif return pointer1._address > pointer2._address; @@ -303,12 +319,14 @@ namespace SharpCompress.Compressors.PPMd.I1 if (pointer1._address == 0) { throw new InvalidOperationException( - "The pointer to the left of the greater than or equal to operator is a null pointer."); + "The pointer to the left of the greater than or equal to operator is a null pointer." + ); } if (pointer2._address == 0) { throw new InvalidOperationException( - "The pointer to the right of the greater than or equal to operator is a null pointer."); + "The pointer to the right of the greater than or equal to operator is a null pointer." + ); } #endif return pointer1._address >= pointer2._address; @@ -360,4 +378,4 @@ namespace SharpCompress.Compressors.PPMd.I1 return _address.GetHashCode(); } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/PPMd/I1/PpmContext.cs b/src/SharpCompress/Compressors/PPMd/I1/PpmContext.cs index f75cbd3a..35d020b6 100644 --- a/src/SharpCompress/Compressors/PPMd/I1/PpmContext.cs +++ b/src/SharpCompress/Compressors/PPMd/I1/PpmContext.cs @@ -36,12 +36,20 @@ namespace SharpCompress.Compressors.PPMd.I1 /// /// Gets or sets the number statistics. /// - public byte NumberStatistics { get => _memory[_address]; set => _memory[_address] = value; } + public byte NumberStatistics + { + get => _memory[_address]; + set => _memory[_address] = value; + } /// /// Gets or sets the flags. /// - public byte Flags { get => _memory[_address + 1]; set => _memory[_address + 1] = value; } + public byte Flags + { + get => _memory[_address + 1]; + set => _memory[_address + 1] = value; + } /// /// Gets or sets the summary frequency. @@ -61,9 +69,14 @@ namespace SharpCompress.Compressors.PPMd.I1 /// public PpmState Statistics { - get => new PpmState( - _memory[_address + 4] | ((uint)_memory[_address + 5]) << 8 | - ((uint)_memory[_address + 6]) << 16 | ((uint)_memory[_address + 7]) << 24, _memory); + get => + new PpmState( + _memory[_address + 4] + | ((uint)_memory[_address + 5]) << 8 + | ((uint)_memory[_address + 6]) << 16 + | ((uint)_memory[_address + 7]) << 24, + _memory + ); set { _memory[_address + 4] = (byte)value._address; @@ -78,9 +91,14 @@ namespace SharpCompress.Compressors.PPMd.I1 /// public PpmContext Suffix { - get => new PpmContext( - _memory[_address + 8] | ((uint)_memory[_address + 9]) << 8 | - ((uint)_memory[_address + 10]) << 16 | ((uint)_memory[_address + 11]) << 24, _memory); + get => + new PpmContext( + _memory[_address + 8] + | ((uint)_memory[_address + 9]) << 8 + | ((uint)_memory[_address + 10]) << 16 + | ((uint)_memory[_address + 11]) << 24, + _memory + ); set { _memory[_address + 8] = (byte)value._address; @@ -122,14 +140,22 @@ namespace SharpCompress.Compressors.PPMd.I1 /// information can be obtained using the Symbol property on the PPM state provided by the /// property. /// - public byte FirstStateSymbol { get => _memory[_address + 2]; set => _memory[_address + 2] = value; } + public byte FirstStateSymbol + { + get => _memory[_address + 2]; + set => _memory[_address + 2] = value; + } /// /// Gets or sets the frequency of the first PPM state. This is provided for convenience. The same /// information can be obtained using the Frequency property on the PPM state provided by the ///context.FirstState property. /// - public byte FirstStateFrequency { get => _memory[_address + 3]; set => _memory[_address + 3] = value; } + public byte FirstStateFrequency + { + get => _memory[_address + 3]; + set => _memory[_address + 3] = value; + } /// /// Gets or sets the successor of the first PPM state. This is provided for convenience. The same @@ -137,9 +163,14 @@ namespace SharpCompress.Compressors.PPMd.I1 /// public PpmContext FirstStateSuccessor { - get => new PpmContext( - _memory[_address + 4] | ((uint)_memory[_address + 5]) << 8 | - ((uint)_memory[_address + 6]) << 16 | ((uint)_memory[_address + 7]) << 24, _memory); + get => + new PpmContext( + _memory[_address + 4] + | ((uint)_memory[_address + 5]) << 8 + | ((uint)_memory[_address + 6]) << 16 + | ((uint)_memory[_address + 7]) << 24, + _memory + ); set { _memory[_address + 4] = (byte)value._address; @@ -256,8 +287,11 @@ namespace SharpCompress.Compressors.PPMd.I1 { PpmState state = context.FirstState; int index1 = _probabilities[state.Frequency - 1]; - int index2 = _numberStatisticsToBinarySummaryIndex[context.Suffix.NumberStatistics] + _previousSuccess + - context.Flags + ((_runLength >> 26) & 0x20); + int index2 = + _numberStatisticsToBinarySummaryIndex[context.Suffix.NumberStatistics] + + _previousSuccess + + context.Flags + + ((_runLength >> 26) & 0x20); if (state.Symbol == symbol) { @@ -265,15 +299,20 @@ namespace SharpCompress.Compressors.PPMd.I1 state.Frequency += (byte)((state.Frequency < 196) ? 1 : 0); _coder._lowCount = 0; _coder._highCount = _binarySummary[index1, index2]; - _binarySummary[index1, index2] += - (ushort)(INTERVAL - Mean(_binarySummary[index1, index2], PERIOD_BIT_COUNT, 2)); + _binarySummary[index1, index2] += (ushort)( + INTERVAL - Mean(_binarySummary[index1, index2], PERIOD_BIT_COUNT, 2) + ); _previousSuccess = 1; _runLength++; } else { _coder._lowCount = _binarySummary[index1, index2]; - _binarySummary[index1, index2] -= (ushort)Mean(_binarySummary[index1, index2], PERIOD_BIT_COUNT, 2); + _binarySummary[index1, index2] -= (ushort)Mean( + _binarySummary[index1, index2], + PERIOD_BIT_COUNT, + 2 + ); _coder._highCount = BINARY_SCALE; _initialEscape = EXPONENTIAL_ESCAPES[_binarySummary[index1, index2] >> 10]; _characterMask[state.Symbol] = _escapeCount; @@ -321,8 +360,7 @@ namespace SharpCompress.Compressors.PPMd.I1 do { _characterMask[(--state).Symbol] = _escapeCount; - } - while (--index != 0); + } while (--index != 0); _coder._highCount = _coder._scale; return; } @@ -345,16 +383,14 @@ namespace SharpCompress.Compressors.PPMd.I1 { currentSymbol = state[1].Symbol; state++; - } - while (_characterMask[currentSymbol] == _escapeCount); + } while (_characterMask[currentSymbol] == _escapeCount); _characterMask[currentSymbol] = _escapeCount; if (currentSymbol == symbol) { goto SymbolFound; } lowCount += state.Frequency; - } - while (--index != 0); + } while (--index != 0); _coder._lowCount = lowCount; _coder._scale += _coder._lowCount; @@ -363,18 +399,17 @@ namespace SharpCompress.Compressors.PPMd.I1 _numberMasked = context.NumberStatistics; return; - SymbolFound: + SymbolFound: _coder._lowCount = lowCount; lowCount += state.Frequency; _coder._highCount = lowCount; - for (PpmState p1 = state; --index != 0;) + for (PpmState p1 = state; --index != 0; ) { do { currentSymbol = p1[1].Symbol; p1++; - } - while (_characterMask[currentSymbol] == _escapeCount); + } while (_characterMask[currentSymbol] == _escapeCount); lowCount += p1.Frequency; } _coder._scale += lowCount; @@ -386,8 +421,11 @@ namespace SharpCompress.Compressors.PPMd.I1 { PpmState state = context.FirstState; int index1 = _probabilities[state.Frequency - 1]; - int index2 = _numberStatisticsToBinarySummaryIndex[context.Suffix.NumberStatistics] + _previousSuccess + - context.Flags + ((_runLength >> 26) & 0x20); + int index2 = + _numberStatisticsToBinarySummaryIndex[context.Suffix.NumberStatistics] + + _previousSuccess + + context.Flags + + ((_runLength >> 26) & 0x20); if (_coder.RangeGetCurrentShiftCount(TOTAL_BIT_COUNT) < _binarySummary[index1, index2]) { @@ -395,15 +433,20 @@ namespace SharpCompress.Compressors.PPMd.I1 state.Frequency += (byte)((state.Frequency < 196) ? 1 : 0); _coder._lowCount = 0; _coder._highCount = _binarySummary[index1, index2]; - _binarySummary[index1, index2] += - (ushort)(INTERVAL - Mean(_binarySummary[index1, index2], PERIOD_BIT_COUNT, 2)); + _binarySummary[index1, index2] += (ushort)( + INTERVAL - Mean(_binarySummary[index1, index2], PERIOD_BIT_COUNT, 2) + ); _previousSuccess = 1; _runLength++; } else { _coder._lowCount = _binarySummary[index1, index2]; - _binarySummary[index1, index2] -= (ushort)Mean(_binarySummary[index1, index2], PERIOD_BIT_COUNT, 2); + _binarySummary[index1, index2] -= (ushort)Mean( + _binarySummary[index1, index2], + PERIOD_BIT_COUNT, + 2 + ); _coder._highCount = BINARY_SCALE; _initialEscape = EXPONENTIAL_ESCAPES[_binarySummary[index1, index2] >> 10]; _characterMask[state.Symbol] = _escapeCount; @@ -453,8 +496,7 @@ namespace SharpCompress.Compressors.PPMd.I1 do { _characterMask[(--state).Symbol] = _escapeCount; - } - while (--index != 0); + } while (--index != 0); _coder._highCount = _coder._scale; return; } @@ -480,14 +522,12 @@ namespace SharpCompress.Compressors.PPMd.I1 { currentSymbol = state[1].Symbol; state++; - } - while (_characterMask[currentSymbol] == _escapeCount); + } while (_characterMask[currentSymbol] == _escapeCount); highCount += state.Frequency; _decodeStates[stateIndex++] = state; // note that decodeStates is a static array that is re-used on each call to this method (for performance reasons) - } - while (--index != 0); + } while (--index != 0); _coder._scale += highCount; count = _coder.RangeGetCurrentCount(); @@ -515,8 +555,7 @@ namespace SharpCompress.Compressors.PPMd.I1 { _characterMask[_decodeStates[stateIndex].Symbol] = _escapeCount; stateIndex++; - } - while (--index != 0); + } while (--index != 0); see2Context._summary += (ushort)_coder._scale; } } @@ -562,8 +601,10 @@ namespace SharpCompress.Compressors.PPMd.I1 numberStatistics = context.Suffix.NumberStatistics; int index1 = _probabilities[context.NumberStatistics + 2] - 3; - int index2 = ((context.SummaryFrequency > 11 * (context.NumberStatistics + 1)) ? 1 : 0) + - ((2 * context.NumberStatistics < numberStatistics + _numberMasked) ? 2 : 0) + context.Flags; + int index2 = + ((context.SummaryFrequency > 11 * (context.NumberStatistics + 1)) ? 1 : 0) + + ((2 * context.NumberStatistics < numberStatistics + _numberMasked) ? 2 : 0) + + context.Flags; see2Context = _see2Contexts[index1, index2]; _coder._scale = see2Context.Mean(); } @@ -615,22 +656,19 @@ namespace SharpCompress.Compressors.PPMd.I1 do { Copy(p1[0], p1[-1]); - } - while (localFrequency > (--p1)[-1].Frequency); + } while (localFrequency > (--p1)[-1].Frequency); p1.Symbol = localSymbol; p1.Frequency = localFrequency; p1.Successor = localSuccessor; } - } - while (--index != 0); + } while (--index != 0); if (state.Frequency == 0) { do { index++; - } - while ((--state).Frequency == 0); + } while ((--state).Frequency == 0); escapeFrequency += index; oldUnitCount = (uint)((context.NumberStatistics + 2) >> 1); @@ -640,7 +678,9 @@ namespace SharpCompress.Compressors.PPMd.I1 localSymbol = context.Statistics.Symbol; localFrequency = context.Statistics.Frequency; localSuccessor = context.Statistics.Successor; - localFrequency = (byte)((2 * localFrequency + escapeFrequency - 1) / escapeFrequency); + localFrequency = (byte)( + (2 * localFrequency + escapeFrequency - 1) / escapeFrequency + ); if (localFrequency > MAXIMUM_FREQUENCY / 3) { localFrequency = (byte)(MAXIMUM_FREQUENCY / 3); @@ -649,13 +689,18 @@ namespace SharpCompress.Compressors.PPMd.I1 context.FirstStateSymbol = localSymbol; context.FirstStateFrequency = localFrequency; context.FirstStateSuccessor = localSuccessor; - context.Flags = (byte)((context.Flags & 0x10) + ((localSymbol >= 0x40) ? 0x08 : 0x00)); + context.Flags = (byte)( + (context.Flags & 0x10) + ((localSymbol >= 0x40) ? 0x08 : 0x00) + ); _foundState = context.FirstState; return; } - context.Statistics = _allocator.ShrinkUnits(context.Statistics, oldUnitCount, - (uint)((context.NumberStatistics + 2) >> 1)); + context.Statistics = _allocator.ShrinkUnits( + context.Statistics, + oldUnitCount, + (uint)((context.NumberStatistics + 2) >> 1) + ); context.Flags &= 0xf7; index = context.NumberStatistics; state = context.Statistics; @@ -663,8 +708,7 @@ namespace SharpCompress.Compressors.PPMd.I1 do { context.Flags |= (byte)(((++state).Symbol >= 0x40) ? 0x08 : 0x00); - } - while (--index != 0); + } while (--index != 0); } escapeFrequency -= (escapeFrequency >> 1); @@ -679,10 +723,16 @@ namespace SharpCompress.Compressors.PPMd.I1 int escapeFrequency; int scaleValue = (scale ? 1 : 0); - context.Statistics = _allocator.ShrinkUnits(context.Statistics, oldUnitCount, (uint)((index + 2) >> 1)); + context.Statistics = _allocator.ShrinkUnits( + context.Statistics, + oldUnitCount, + (uint)((index + 2) >> 1) + ); PpmState statistics = context.Statistics; - context.Flags = - (byte)((context.Flags & (0x10 + (scale ? 0x04 : 0x00))) + ((statistics.Symbol >= 0x40) ? 0x08 : 0x00)); + context.Flags = (byte)( + (context.Flags & (0x10 + (scale ? 0x04 : 0x00))) + + ((statistics.Symbol >= 0x40) ? 0x08 : 0x00) + ); escapeFrequency = context.SummaryFrequency - statistics.Frequency; statistics.Frequency = (byte)((statistics.Frequency + scaleValue) >> scaleValue); context.SummaryFrequency = statistics.Frequency; @@ -693,8 +743,7 @@ namespace SharpCompress.Compressors.PPMd.I1 statistics.Frequency = (byte)((statistics.Frequency + scaleValue) >> scaleValue); context.SummaryFrequency += statistics.Frequency; context.Flags |= (byte)((statistics.Symbol >= 0x40) ? 0x08 : 0x00); - } - while (--index != 0); + } while (--index != 0); escapeFrequency = (escapeFrequency + scaleValue) >> scaleValue; context.SummaryFrequency += (ushort)escapeFrequency; @@ -763,7 +812,9 @@ namespace SharpCompress.Compressors.PPMd.I1 } if (index == 0) { - context.Flags = (byte)((context.Flags & 0x10) + ((state.Symbol >= 0x40) ? 0x08 : 0x00)); + context.Flags = (byte)( + (context.Flags & 0x10) + ((state.Symbol >= 0x40) ? 0x08 : 0x00) + ); Copy(context.FirstState, state); _allocator.FreeUnits(state, unitCount); context.FirstStateFrequency = (byte)((context.FirstStateFrequency + 11) >> 3); @@ -790,8 +841,10 @@ namespace SharpCompress.Compressors.PPMd.I1 { state.Successor = PpmContext.ZERO; } - if ((state.Successor == PpmContext.ZERO) && - (context.Suffix.NumberStatistics == 0 || context.Suffix.Flags == 0xff)) + if ( + (state.Successor == PpmContext.ZERO) + && (context.Suffix.NumberStatistics == 0 || context.Suffix.Flags == 0xff) + ) { _allocator.FreeUnits(context, 1); return PpmContext.ZERO; @@ -799,7 +852,11 @@ namespace SharpCompress.Compressors.PPMd.I1 return context; } - for (PpmState state = context.Statistics + context.NumberStatistics; state >= context.Statistics; state--) + for ( + PpmState state = context.Statistics + context.NumberStatistics; + state >= context.Statistics; + state-- + ) { if ((Pointer)state.Successor >= _allocator._baseUnit && order < _modelOrder) { @@ -814,4 +871,4 @@ namespace SharpCompress.Compressors.PPMd.I1 return context; } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/PPMd/I1/PpmState.cs b/src/SharpCompress/Compressors/PPMd/I1/PpmState.cs index dc72009d..de88fea1 100644 --- a/src/SharpCompress/Compressors/PPMd/I1/PpmState.cs +++ b/src/SharpCompress/Compressors/PPMd/I1/PpmState.cs @@ -34,21 +34,34 @@ namespace SharpCompress.Compressors.PPMd.I1 /// /// Gets or sets the symbol. /// - public byte Symbol { get => _memory[_address]; set => _memory[_address] = value; } + public byte Symbol + { + get => _memory[_address]; + set => _memory[_address] = value; + } /// /// Gets or sets the frequency. /// - public byte Frequency { get => _memory[_address + 1]; set => _memory[_address + 1] = value; } + public byte Frequency + { + get => _memory[_address + 1]; + set => _memory[_address + 1] = value; + } /// /// Gets or sets the successor. /// public Model.PpmContext Successor { - get => new Model.PpmContext( - _memory[_address + 2] | ((uint)_memory[_address + 3]) << 8 | - ((uint)_memory[_address + 4]) << 16 | ((uint)_memory[_address + 5]) << 24, _memory); + get => + new Model.PpmContext( + _memory[_address + 2] + | ((uint)_memory[_address + 3]) << 8 + | ((uint)_memory[_address + 4]) << 16 + | ((uint)_memory[_address + 5]) << 24, + _memory + ); set { _memory[_address + 2] = (byte)value._address; @@ -190,4 +203,4 @@ namespace SharpCompress.Compressors.PPMd.I1 return _address.GetHashCode(); } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/PPMd/I1/See2Context.cs b/src/SharpCompress/Compressors/PPMd/I1/See2Context.cs index 3029d85b..68e09cca 100644 --- a/src/SharpCompress/Compressors/PPMd/I1/See2Context.cs +++ b/src/SharpCompress/Compressors/PPMd/I1/See2Context.cs @@ -52,4 +52,4 @@ namespace SharpCompress.Compressors.PPMd.I1 } } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/PPMd/PpmdProperties.cs b/src/SharpCompress/Compressors/PPMd/PpmdProperties.cs index 08eef12c..326b6019 100644 --- a/src/SharpCompress/Compressors/PPMd/PpmdProperties.cs +++ b/src/SharpCompress/Compressors/PPMd/PpmdProperties.cs @@ -6,21 +6,19 @@ namespace SharpCompress.Compressors.PPMd { public class PpmdProperties { - private int _allocatorSize; internal Allocator? _allocator; - public PpmdProperties() - : this(16 << 20, 6) - { - } + public PpmdProperties() : this(16 << 20, 6) { } public PpmdProperties(int allocatorSize, int modelOrder) - : this(allocatorSize, modelOrder, ModelRestorationMethod.Restart) - { - } + : this(allocatorSize, modelOrder, ModelRestorationMethod.Restart) { } - internal PpmdProperties(int allocatorSize, int modelOrder, ModelRestorationMethod modelRestorationMethod) + internal PpmdProperties( + int allocatorSize, + int modelOrder, + ModelRestorationMethod modelRestorationMethod + ) { AllocatorSize = allocatorSize; ModelOrder = modelOrder; @@ -31,9 +29,7 @@ namespace SharpCompress.Compressors.PPMd public PpmdVersion Version { get; } = PpmdVersion.I1; internal ModelRestorationMethod RestorationMethod { get; } - public PpmdProperties(byte[] properties) : this(properties.AsSpan()) - { - } + public PpmdProperties(byte[] properties) : this(properties.AsSpan()) { } public PpmdProperties(ReadOnlySpan properties) { @@ -74,7 +70,12 @@ namespace SharpCompress.Compressors.PPMd byte[] bytes = new byte[2]; BinaryPrimitives.WriteUInt16LittleEndian( bytes, - (ushort)((ModelOrder - 1) + (((AllocatorSize >> 20) - 1) << 4) + ((ushort)RestorationMethod << 12))); + (ushort)( + (ModelOrder - 1) + + (((AllocatorSize >> 20) - 1) << 4) + + ((ushort)RestorationMethod << 12) + ) + ); return bytes; } } diff --git a/src/SharpCompress/Compressors/PPMd/PpmdStream.cs b/src/SharpCompress/Compressors/PPMd/PpmdStream.cs index 33715c3a..4e48d71a 100644 --- a/src/SharpCompress/Compressors/PPMd/PpmdStream.cs +++ b/src/SharpCompress/Compressors/PPMd/PpmdStream.cs @@ -65,9 +65,7 @@ namespace SharpCompress.Compressors.PPMd public override bool CanWrite => _compress; - public override void Flush() - { - } + public override void Flush() { } protected override void Dispose(bool isDisposing) { @@ -88,7 +86,11 @@ namespace SharpCompress.Compressors.PPMd public override long Length => throw new NotSupportedException(); - public override long Position { get => _position; set => throw new NotSupportedException(); } + public override long Position + { + get => _position; + set => throw new NotSupportedException(); + } public override int Read(byte[] buffer, int offset, int count) { @@ -141,4 +143,4 @@ namespace SharpCompress.Compressors.PPMd } } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/PPMd/PpmdVersion.cs b/src/SharpCompress/Compressors/PPMd/PpmdVersion.cs index 8ab1aa38..cd0d6f46 100644 --- a/src/SharpCompress/Compressors/PPMd/PpmdVersion.cs +++ b/src/SharpCompress/Compressors/PPMd/PpmdVersion.cs @@ -6,4 +6,4 @@ H7Z, I1 } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/Rar/MultiVolumeReadOnlyStream.cs b/src/SharpCompress/Compressors/Rar/MultiVolumeReadOnlyStream.cs index 61201b62..db406df9 100644 --- a/src/SharpCompress/Compressors/Rar/MultiVolumeReadOnlyStream.cs +++ b/src/SharpCompress/Compressors/Rar/MultiVolumeReadOnlyStream.cs @@ -21,7 +21,10 @@ namespace SharpCompress.Compressors.Rar private long currentPartTotalReadBytes; private long currentEntryTotalReadBytes; - internal MultiVolumeReadOnlyStream(IEnumerable parts, IExtractionListener streamListener) + internal MultiVolumeReadOnlyStream( + IEnumerable parts, + IExtractionListener streamListener + ) { this.streamListener = streamListener; @@ -54,9 +57,11 @@ namespace SharpCompress.Compressors.Rar CurrentCrc = filePartEnumerator.Current.FileHeader.FileCrc; - streamListener.FireFilePartExtractionBegin(filePartEnumerator.Current.FilePartName, - filePartEnumerator.Current.FileHeader.CompressedSize, - filePartEnumerator.Current.FileHeader.UncompressedSize); + streamListener.FireFilePartExtractionBegin( + filePartEnumerator.Current.FilePartName, + filePartEnumerator.Current.FileHeader.CompressedSize, + filePartEnumerator.Current.FileHeader.UncompressedSize + ); } public override int Read(byte[] buffer, int offset, int count) @@ -82,18 +87,24 @@ namespace SharpCompress.Compressors.Rar currentOffset += read; currentCount -= read; totalRead += read; - if (((maxPosition - currentPosition) == 0) - && filePartEnumerator.Current.FileHeader.IsSplitAfter) + if ( + ((maxPosition - currentPosition) == 0) + && filePartEnumerator.Current.FileHeader.IsSplitAfter + ) { if (filePartEnumerator.Current.FileHeader.R4Salt != null) { - throw new InvalidFormatException("Sharpcompress currently does not support multi-volume decryption."); + throw new InvalidFormatException( + "Sharpcompress currently does not support multi-volume decryption." + ); } string fileName = filePartEnumerator.Current.FileHeader.FileName; if (!filePartEnumerator.MoveNext()) { throw new InvalidFormatException( - "Multi-part rar file is incomplete. Entry expects a new volume: " + fileName); + "Multi-part rar file is incomplete. Entry expects a new volume: " + + fileName + ); } InitializeNextFilePart(); } @@ -104,7 +115,10 @@ namespace SharpCompress.Compressors.Rar } currentPartTotalReadBytes += totalRead; currentEntryTotalReadBytes += totalRead; - streamListener.FireCompressedBytesRead(currentPartTotalReadBytes, currentEntryTotalReadBytes); + streamListener.FireCompressedBytesRead( + currentPartTotalReadBytes, + currentEntryTotalReadBytes + ); return totalRead; } @@ -123,7 +137,11 @@ namespace SharpCompress.Compressors.Rar public override long Length => throw new NotSupportedException(); - public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); } + public override long Position + { + get => throw new NotSupportedException(); + set => throw new NotSupportedException(); + } public override long Seek(long offset, SeekOrigin origin) { @@ -140,4 +158,4 @@ namespace SharpCompress.Compressors.Rar throw new NotSupportedException(); } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/Rar/RarCRC.cs b/src/SharpCompress/Compressors/Rar/RarCRC.cs index c9e8159c..a7e565a4 100644 --- a/src/SharpCompress/Compressors/Rar/RarCRC.cs +++ b/src/SharpCompress/Compressors/Rar/RarCRC.cs @@ -46,4 +46,4 @@ namespace SharpCompress.Compressors.Rar } } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/Rar/RarCrcStream.cs b/src/SharpCompress/Compressors/Rar/RarCrcStream.cs index 127cef25..120d8c3e 100644 --- a/src/SharpCompress/Compressors/Rar/RarCrcStream.cs +++ b/src/SharpCompress/Compressors/Rar/RarCrcStream.cs @@ -8,8 +8,11 @@ namespace SharpCompress.Compressors.Rar private readonly MultiVolumeReadOnlyStream readStream; private uint currentCrc; - public RarCrcStream(IRarUnpack unpack, FileHeader fileHeader, MultiVolumeReadOnlyStream readStream) - : base(unpack, fileHeader, readStream) + public RarCrcStream( + IRarUnpack unpack, + FileHeader fileHeader, + MultiVolumeReadOnlyStream readStream + ) : base(unpack, fileHeader, readStream) { this.readStream = readStream; ResetCrc(); @@ -41,4 +44,4 @@ namespace SharpCompress.Compressors.Rar return result; } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/Rar/RarStream.cs b/src/SharpCompress/Compressors/Rar/RarStream.cs index 2ad3c9b8..9c470fbd 100644 --- a/src/SharpCompress/Compressors/Rar/RarStream.cs +++ b/src/SharpCompress/Compressors/Rar/RarStream.cs @@ -52,14 +52,16 @@ namespace SharpCompress.Compressors.Rar public override bool CanWrite => false; - public override void Flush() - { - } + public override void Flush() { } public override long Length => fileHeader.UncompressedSize; //commented out code always returned the length of the file - public override long Position { get => _position; /* fileHeader.UncompressedSize - unpack.DestSize;*/ set => throw new NotSupportedException(); } + public override long Position + { + get => _position; /* fileHeader.UncompressedSize - unpack.DestSize;*/ + set => throw new NotSupportedException(); + } public override int Read(byte[] buffer, int offset, int count) { @@ -117,8 +119,11 @@ namespace SharpCompress.Compressors.Rar { if (tmpBuffer.Length < tmpCount + count) { - byte[] newBuffer = - new byte[tmpBuffer.Length * 2 > tmpCount + count ? tmpBuffer.Length * 2 : tmpCount + count]; + byte[] newBuffer = new byte[ + tmpBuffer.Length * 2 > tmpCount + count + ? tmpBuffer.Length * 2 + : tmpCount + count + ]; Buffer.BlockCopy(tmpBuffer, 0, newBuffer, 0, tmpCount); tmpBuffer = newBuffer; } diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/AudioVariables.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/AudioVariables.cs index c2510617..3e7319f3 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/AudioVariables.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/AudioVariables.cs @@ -23,4 +23,4 @@ namespace SharpCompress.Compressors.Rar.UnpackV1.Decode internal int LastChar { get; set; } internal int LastDelta { get; set; } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/BitDecode.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/BitDecode.cs index a8d499b5..aa8ff4dd 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/BitDecode.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/BitDecode.cs @@ -2,9 +2,6 @@ namespace SharpCompress.Compressors.Rar.UnpackV1.Decode { internal class BitDecode : Decode { - internal BitDecode() - : base(new int[PackDef.BC]) - { - } + internal BitDecode() : base(new int[PackDef.BC]) { } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/CodeType.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/CodeType.cs index e9703ff1..a0f31371 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/CodeType.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/CodeType.cs @@ -12,4 +12,4 @@ namespace SharpCompress.Compressors.Rar.UnpackV1.Decode CODE_VM, CODE_VMDATA } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/Decode.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/Decode.cs index ceed74de..7634dc7e 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/Decode.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/Decode.cs @@ -2,10 +2,7 @@ namespace SharpCompress.Compressors.Rar.UnpackV1.Decode { internal class Decode { - internal Decode() - : this(new int[2]) - { - } + internal Decode() : this(new int[2]) { } protected Decode(int[] customDecodeNum) { @@ -31,4 +28,4 @@ namespace SharpCompress.Compressors.Rar.UnpackV1.Decode internal int MaxNum { get; set; } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/DistDecode.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/DistDecode.cs index 1a0b666b..9b49acc3 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/DistDecode.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/DistDecode.cs @@ -2,9 +2,6 @@ namespace SharpCompress.Compressors.Rar.UnpackV1.Decode { internal class DistDecode : Decode { - internal DistDecode() - : base(new int[PackDef.DC]) - { - } + internal DistDecode() : base(new int[PackDef.DC]) { } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/FilterType.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/FilterType.cs index 32166837..1a6360dc 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/FilterType.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/FilterType.cs @@ -4,7 +4,14 @@ namespace SharpCompress.Compressors.Rar.UnpackV1.Decode { // These values must not be changed, because we use them directly // in RAR5 compression and decompression code. - FILTER_DELTA = 0, FILTER_E8, FILTER_E8E9, FILTER_ARM, - FILTER_AUDIO, FILTER_RGB, FILTER_ITANIUM, FILTER_PPM, FILTER_NONE + FILTER_DELTA = 0, + FILTER_E8, + FILTER_E8E9, + FILTER_ARM, + FILTER_AUDIO, + FILTER_RGB, + FILTER_ITANIUM, + FILTER_PPM, + FILTER_NONE } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/LitDecode.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/LitDecode.cs index 8316c261..035e7ce4 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/LitDecode.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/LitDecode.cs @@ -2,9 +2,6 @@ namespace SharpCompress.Compressors.Rar.UnpackV1.Decode { internal class LitDecode : Decode { - internal LitDecode() - : base(new int[PackDef.NC]) - { - } + internal LitDecode() : base(new int[PackDef.NC]) { } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/LowDistDecode.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/LowDistDecode.cs index a2095bd4..d3f358e8 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/LowDistDecode.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/LowDistDecode.cs @@ -2,9 +2,6 @@ namespace SharpCompress.Compressors.Rar.UnpackV1.Decode { internal class LowDistDecode : Decode { - internal LowDistDecode() - : base(new int[PackDef.LDC]) - { - } + internal LowDistDecode() : base(new int[PackDef.LDC]) { } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/MultDecode.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/MultDecode.cs index e6df223c..6342ac1f 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/MultDecode.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/MultDecode.cs @@ -2,9 +2,6 @@ namespace SharpCompress.Compressors.Rar.UnpackV1.Decode { internal class MultDecode : Decode { - internal MultDecode() - : base(new int[PackDef.MC20]) - { - } + internal MultDecode() : base(new int[PackDef.MC20]) { } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/PackDef.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/PackDef.cs index 163ba5f3..00ee5bb6 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/PackDef.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/PackDef.cs @@ -15,6 +15,7 @@ namespace SharpCompress.Compressors.Rar.UnpackV1.Decode public const int DC = 60; public const int LDC = 17; public const int RC = 28; + // 20171217: NOTE: these constants seem to have been updated in the unrar src code // at some unknown point. updating causes decompression failure, not sure why. // public const int NC = 306; /* alphabet = {0, 1, 2, ..., NC - 1} */ @@ -45,4 +46,4 @@ namespace SharpCompress.Compressors.Rar.UnpackV1.Decode // CODE_ENDFILE, CODE_FILTER, CODE_FILTERDATA //} } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/RepDecode.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/RepDecode.cs index 24d72d16..648630e1 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/RepDecode.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/RepDecode.cs @@ -2,9 +2,6 @@ namespace SharpCompress.Compressors.Rar.UnpackV1.Decode { internal class RepDecode : Decode { - internal RepDecode() - : base(new int[PackDef.RC]) - { - } + internal RepDecode() : base(new int[PackDef.RC]) { } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/PPM/BlockTypes.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/PPM/BlockTypes.cs index b3f79fdc..c25fae4e 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/PPM/BlockTypes.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/PPM/BlockTypes.cs @@ -5,4 +5,4 @@ namespace SharpCompress.Compressors.Rar.UnpackV1.PPM BLOCK_LZ = 0, BLOCK_PPM = 1 } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack.cs index cc33b25f..63dd4875 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack.cs @@ -22,7 +22,6 @@ namespace SharpCompress.Compressors.Rar.UnpackV1 Inp = this; } - public bool FileExtracted { get; private set; } public long DestSize @@ -87,7 +86,28 @@ namespace SharpCompress.Compressors.Rar.UnpackV1 private int lowDistRepCount; - private static readonly int[] DBitLengthCounts = { 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 14, 0, 12 }; + private static readonly int[] DBitLengthCounts = + { + 4, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 14, + 0, + 12 + }; private FileHeader fileHeader; @@ -149,7 +169,9 @@ namespace SharpCompress.Compressors.Rar.UnpackV1 break; default: - throw new InvalidFormatException("unknown rar compression version " + fileHeader.CompressionAlgorithm); + throw new InvalidFormatException( + "unknown rar compression version " + fileHeader.CompressionAlgorithm + ); } } @@ -185,7 +207,9 @@ namespace SharpCompress.Compressors.Rar.UnpackV1 if (DDecode[1] == 0) { - int Dist = 0, BitLength = 0, Slot = 0; + int Dist = 0, + BitLength = 0, + Slot = 0; for (int I = 0; I < DBitLengthCounts.Length; I++, BitLength++) { int count = DBitLengthCounts[I]; @@ -277,7 +301,8 @@ namespace SharpCompress.Compressors.Rar.UnpackV1 } if (NextCh == 4) { - int Distance = 0, Length = 0; + int Distance = 0, + Length = 0; bool failed = false; for (int I = 0; I < 4 && !failed; I++) { @@ -506,10 +531,15 @@ namespace SharpCompress.Compressors.Rar.UnpackV1 // Prg->GlobalData.Alloc(ParentPrg->GlobalData.Size()); // memcpy(&Prg->GlobalData[VM_FIXEDGLOBALSIZE],&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],ParentPrg->GlobalData.Size()-VM_FIXEDGLOBALSIZE); Prg.GlobalData.Clear(); - for (int i = 0; i < ParentPrg.GlobalData.Count - RarVM.VM_FIXEDGLOBALSIZE; i++) + for ( + int i = 0; + i < ParentPrg.GlobalData.Count - RarVM.VM_FIXEDGLOBALSIZE; + i++ + ) { - Prg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i] = - ParentPrg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i]; + Prg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i] = ParentPrg.GlobalData[ + RarVM.VM_FIXEDGLOBALSIZE + i + ]; } } @@ -525,10 +555,15 @@ namespace SharpCompress.Compressors.Rar.UnpackV1 } // memcpy(&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],&Prg->GlobalData[VM_FIXEDGLOBALSIZE],Prg->GlobalData.Size()-VM_FIXEDGLOBALSIZE); - for (int i = 0; i < Prg.GlobalData.Count - RarVM.VM_FIXEDGLOBALSIZE; i++) + for ( + int i = 0; + i < Prg.GlobalData.Count - RarVM.VM_FIXEDGLOBALSIZE; + i++ + ) { - ParentPrg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i] = - Prg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i]; + ParentPrg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i] = Prg.GlobalData[ + RarVM.VM_FIXEDGLOBALSIZE + i + ]; } } else @@ -553,8 +588,12 @@ namespace SharpCompress.Compressors.Rar.UnpackV1 while (I + 1 < prgStack.Count) { UnpackFilter NextFilter = prgStack[I + 1]; - if (NextFilter is null || NextFilter.BlockStart != BlockStart || - NextFilter.BlockLength != FilteredDataSize || NextFilter.NextWindow) + if ( + NextFilter is null + || NextFilter.BlockStart != BlockStart + || NextFilter.BlockLength != FilteredDataSize + || NextFilter.NextWindow + ) { break; } @@ -576,7 +615,11 @@ namespace SharpCompress.Compressors.Rar.UnpackV1 NextPrg.GlobalData.SetSize(pPrg.GlobalData.Count); // memcpy(&NextPrg->GlobalData[VM_FIXEDGLOBALSIZE],&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],ParentPrg->GlobalData.Size()-VM_FIXEDGLOBALSIZE); - for (int i = 0; i < pPrg.GlobalData.Count - RarVM.VM_FIXEDGLOBALSIZE; i++) + for ( + int i = 0; + i < pPrg.GlobalData.Count - RarVM.VM_FIXEDGLOBALSIZE; + i++ + ) { NextPrg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i] = pPrg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i]; @@ -594,7 +637,11 @@ namespace SharpCompress.Compressors.Rar.UnpackV1 } // memcpy(&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],&NextPrg->GlobalData[VM_FIXEDGLOBALSIZE],NextPrg->GlobalData.Size()-VM_FIXEDGLOBALSIZE); - for (int i = 0; i < NextPrg.GlobalData.Count - RarVM.VM_FIXEDGLOBALSIZE; i++) + for ( + int i = 0; + i < NextPrg.GlobalData.Count - RarVM.VM_FIXEDGLOBALSIZE; + i++ + ) { pPrg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i] = NextPrg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i]; @@ -711,7 +758,11 @@ namespace SharpCompress.Compressors.Rar.UnpackV1 int destPtr = unpPtr - distance; // System.out.println(unpPtr+":"+distance); - if (destPtr >= 0 && destPtr < PackDef.MAXWINSIZE - 260 && unpPtr < PackDef.MAXWINSIZE - 260) + if ( + destPtr >= 0 + && destPtr < PackDef.MAXWINSIZE - 260 + && unpPtr < PackDef.MAXWINSIZE - 260 + ) { window[unpPtr++] = window[destPtr++]; @@ -801,7 +852,8 @@ namespace SharpCompress.Compressors.Rar.UnpackV1 private bool ReadEndOfBlock() { int BitField = GetBits(); - bool NewTable, NewFile = false; + bool NewTable, + NewFile = false; if ((BitField & 0x8000) != 0) { NewTable = true; @@ -879,7 +931,7 @@ namespace SharpCompress.Compressors.Rar.UnpackV1 int TableSize = PackDef.HUFF_TABLE_SIZE; - for (int i = 0; i < TableSize;) + for (int i = 0; i < TableSize; ) { if (inAddr > readTop - 5) { @@ -940,7 +992,12 @@ namespace SharpCompress.Compressors.Rar.UnpackV1 UnpackUtility.makeDecodeTables(table, 0, LD, PackDef.NC); UnpackUtility.makeDecodeTables(table, PackDef.NC, DD, PackDef.DC); UnpackUtility.makeDecodeTables(table, PackDef.NC + PackDef.DC, LDD, PackDef.LDC); - UnpackUtility.makeDecodeTables(table, PackDef.NC + PackDef.DC + PackDef.LDC, RD, PackDef.RC); + UnpackUtility.makeDecodeTables( + table, + PackDef.NC + PackDef.DC + PackDef.LDC, + RD, + PackDef.RC + ); // memcpy(unpOldTable,table,sizeof(unpOldTable)); @@ -1065,7 +1122,6 @@ namespace SharpCompress.Compressors.Rar.UnpackV1 UnpackFilter Filter; if (NewFilter) - // new filter code, never used before since VM reset { // too many different filters, corrupt archive @@ -1081,7 +1137,6 @@ namespace SharpCompress.Compressors.Rar.UnpackV1 oldFilterLengths.Add(0); Filter.ExecCount = 0; } - // filter was used in the past else { @@ -1105,9 +1160,11 @@ namespace SharpCompress.Compressors.Rar.UnpackV1 } else { - StackFilter.BlockLength = FiltPos < oldFilterLengths.Count ? oldFilterLengths[FiltPos] : 0; + StackFilter.BlockLength = + FiltPos < oldFilterLengths.Count ? oldFilterLengths[FiltPos] : 0; } - StackFilter.NextWindow = (wrPtr != unpPtr) && ((wrPtr - unpPtr) & PackDef.MAXWINMASK) <= BlockStart; + StackFilter.NextWindow = + (wrPtr != unpPtr) && ((wrPtr - unpPtr) & PackDef.MAXWINMASK) <= BlockStart; // DebugLog("\nNextWindow: UnpPtr=%08x WrPtr=%08x // BlockStart=%08x",UnpPtr,WrPtr,BlockStart); @@ -1123,7 +1180,6 @@ namespace SharpCompress.Compressors.Rar.UnpackV1 StackFilter.Program.InitR[5] = StackFilter.ExecCount; // StackFilter->Prg.InitR[5]=StackFilter->ExecCount; if ((firstByte & 0x10) != 0) - // set registers to optional parameters // if any { @@ -1210,7 +1266,6 @@ namespace SharpCompress.Compressors.Rar.UnpackV1 globalData[0x30 + i] = 0x0; } if ((firstByte & 8) != 0) - // put data block passed as parameter if any { if (Inp.Overflow(3)) @@ -1226,7 +1281,9 @@ namespace SharpCompress.Compressors.Rar.UnpackV1 if (CurSize < DataSize + RarVM.VM_FIXEDGLOBALSIZE) { // StackFilter->Prg.GlobalData.Add(DataSize+VM_FIXEDGLOBALSIZE-CurSize); - StackFilter.Program.GlobalData.SetSize(DataSize + RarVM.VM_FIXEDGLOBALSIZE - CurSize); + StackFilter.Program.GlobalData.SetSize( + DataSize + RarVM.VM_FIXEDGLOBALSIZE - CurSize + ); } int offset = RarVM.VM_FIXEDGLOBALSIZE; globalData = StackFilter.Program.GlobalData; @@ -1256,7 +1313,11 @@ namespace SharpCompress.Compressors.Rar.UnpackV1 // rarVM.SetLowEndianValue((uint // *)&Prg->GlobalData[0x28],int64to32(WrittenFileSize>>32)); - rarVM.SetLowEndianValue(Prg.GlobalData, 0x28, (int)(Utility.URShift(writtenFileSize, 32))); + rarVM.SetLowEndianValue( + Prg.GlobalData, + 0x28, + (int)(Utility.URShift(writtenFileSize, 32)) + ); rarVM.execute(Prg); } } diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack15.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack15.cs index 7a0ae2bd..d463a020 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack15.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack15.cs @@ -35,36 +35,60 @@ namespace SharpCompress.Compressors.Rar.UnpackV1 private readonly int[] oldDist = new int[4]; - private int unpPtr, wrPtr; + private int unpPtr, + wrPtr; private int oldDistPtr; private readonly int[] ChSet = new int[256], - ChSetA = new int[256], - ChSetB = new int[256], - ChSetC = new int[256]; + ChSetA = new int[256], + ChSetB = new int[256], + ChSetC = new int[256]; private readonly int[] Place = new int[256], - PlaceA = new int[256], - PlaceB = new int[256], - PlaceC = new int[256]; + PlaceA = new int[256], + PlaceB = new int[256], + PlaceC = new int[256]; - private readonly int[] NToPl = new int[256], NToPlB = new int[256], NToPlC = new int[256]; + private readonly int[] NToPl = new int[256], + NToPlB = new int[256], + NToPlC = new int[256]; - private int FlagBuf, AvrPlc, AvrPlcB, AvrLn1, AvrLn2, AvrLn3; + private int FlagBuf, + AvrPlc, + AvrPlcB, + AvrLn1, + AvrLn2, + AvrLn3; - private int Buf60, NumHuf, StMode, LCount, FlagsCnt; + private int Buf60, + NumHuf, + StMode, + LCount, + FlagsCnt; - private int Nhfb, Nlzb, MaxDist3; + private int Nhfb, + Nlzb, + MaxDist3; - private int lastDist, lastLength; + private int lastDist, + lastLength; private const int STARTL1 = 2; private static readonly int[] DecL1 = { - 0x8000, 0xa000, 0xc000, 0xd000, 0xe000, 0xea00, 0xee00, 0xf000, 0xf200, 0xf200 - , 0xffff + 0x8000, + 0xa000, + 0xc000, + 0xd000, + 0xe000, + 0xea00, + 0xee00, + 0xf000, + 0xf200, + 0xf200, + 0xffff }; private static readonly int[] PosL1 = { 0, 0, 0, 2, 3, 5, 7, 11, 16, 20, 24, 32, 32 }; @@ -73,32 +97,81 @@ namespace SharpCompress.Compressors.Rar.UnpackV1 private static readonly int[] DecL2 = { - 0xa000, 0xc000, 0xd000, 0xe000, 0xea00, 0xee00, 0xf000, 0xf200, 0xf240, 0xffff + 0xa000, + 0xc000, + 0xd000, + 0xe000, + 0xea00, + 0xee00, + 0xf000, + 0xf200, + 0xf240, + 0xffff }; private static readonly int[] PosL2 = { 0, 0, 0, 0, 5, 7, 9, 13, 18, 22, 26, 34, 36 }; private const int STARTHF0 = 4; - private static readonly int[] DecHf0 = { 0x8000, 0xc000, 0xe000, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xffff }; + private static readonly int[] DecHf0 = + { + 0x8000, + 0xc000, + 0xe000, + 0xf200, + 0xf200, + 0xf200, + 0xf200, + 0xf200, + 0xffff + }; private static readonly int[] PosHf0 = { 0, 0, 0, 0, 0, 8, 16, 24, 33, 33, 33, 33, 33 }; private const int STARTHF1 = 5; - private static readonly int[] DecHf1 = { 0x2000, 0xc000, 0xe000, 0xf000, 0xf200, 0xf200, 0xf7e0, 0xffff }; + private static readonly int[] DecHf1 = + { + 0x2000, + 0xc000, + 0xe000, + 0xf000, + 0xf200, + 0xf200, + 0xf7e0, + 0xffff + }; private static readonly int[] PosHf1 = { 0, 0, 0, 0, 0, 0, 4, 44, 60, 76, 80, 80, 127 }; private const int STARTHF2 = 5; - private static readonly int[] DecHf2 = { 0x1000, 0x2400, 0x8000, 0xc000, 0xfa00, 0xffff, 0xffff, 0xffff }; + private static readonly int[] DecHf2 = + { + 0x1000, + 0x2400, + 0x8000, + 0xc000, + 0xfa00, + 0xffff, + 0xffff, + 0xffff + }; private static readonly int[] PosHf2 = { 0, 0, 0, 0, 0, 0, 2, 7, 53, 117, 233, 0, 0 }; private const int STARTHF3 = 6; - private static readonly int[] DecHf3 = { 0x800, 0x2400, 0xee00, 0xfe80, 0xffff, 0xffff, 0xffff }; + private static readonly int[] DecHf3 = + { + 0x800, + 0x2400, + 0xee00, + 0xfe80, + 0xffff, + 0xffff, + 0xffff + }; private static readonly int[] PosHf3 = { 0, 0, 0, 0, 0, 0, 0, 2, 16, 218, 251, 0, 0 }; @@ -108,20 +181,82 @@ namespace SharpCompress.Compressors.Rar.UnpackV1 private static readonly int[] PosHf4 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0 }; - private static readonly int[] ShortLen1 = { 1, 3, 4, 4, 5, 6, 7, 8, 8, 4, 4, 5, 6, 6, 4, 0 }; + private static readonly int[] ShortLen1 = + { + 1, + 3, + 4, + 4, + 5, + 6, + 7, + 8, + 8, + 4, + 4, + 5, + 6, + 6, + 4, + 0 + }; private static readonly int[] ShortXor1 = { - 0, 0xa0, 0xd0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff, 0xc0, 0x80, 0x90, 0x98 - , 0x9c, 0xb0 + 0, + 0xa0, + 0xd0, + 0xe0, + 0xf0, + 0xf8, + 0xfc, + 0xfe, + 0xff, + 0xc0, + 0x80, + 0x90, + 0x98, + 0x9c, + 0xb0 }; - private static readonly int[] ShortLen2 = { 2, 3, 3, 3, 4, 4, 5, 6, 6, 4, 4, 5, 6, 6, 4, 0 }; + private static readonly int[] ShortLen2 = + { + 2, + 3, + 3, + 3, + 4, + 4, + 5, + 6, + 6, + 4, + 4, + 5, + 6, + 6, + 4, + 0 + }; private static readonly int[] ShortXor2 = { - 0, 0x40, 0x60, 0xa0, 0xd0, 0xe0, 0xf0, 0xf8, 0xfc, 0xc0, 0x80, 0x90, 0x98 - , 0x9c, 0xb0 + 0, + 0x40, + 0x60, + 0xa0, + 0xd0, + 0xe0, + 0xf0, + 0xf8, + 0xfc, + 0xc0, + 0x80, + 0x90, + 0x98, + 0x9c, + 0xb0 }; private void unpack15(bool solid) @@ -269,7 +404,8 @@ namespace SharpCompress.Compressors.Rar.UnpackV1 private void shortLZ() { - int Length, SaveLength; + int Length, + SaveLength; int LastDistance; int Distance; int DistancePlace; @@ -292,7 +428,12 @@ namespace SharpCompress.Compressors.Rar.UnpackV1 { for (Length = 0; ; Length++) { - if (((BitField ^ ShortXor1[Length]) & (~(Utility.URShift(0xff, getShortLen1(Length))))) == 0) + if ( + ( + (BitField ^ ShortXor1[Length]) + & (~(Utility.URShift(0xff, getShortLen1(Length)))) + ) == 0 + ) { break; } @@ -383,8 +524,10 @@ namespace SharpCompress.Compressors.Rar.UnpackV1 { int Length; int Distance; - int DistancePlace, NewDistancePlace; - int OldAvr2, OldAvr3; + int DistancePlace, + NewDistancePlace; + int OldAvr2, + OldAvr3; NumHuf = 0; Nlzb += 16; @@ -506,7 +649,8 @@ namespace SharpCompress.Compressors.Rar.UnpackV1 private void huffDecode() { - int CurByte, NewBytePlace; + int CurByte, + NewBytePlace; int Length; int Distance; int BytePlace; @@ -606,7 +750,8 @@ namespace SharpCompress.Compressors.Rar.UnpackV1 private void getFlagsBuf() { - int Flags, NewFlagsPlace; + int Flags, + NewFlagsPlace; int FlagsPlace = decodeNum(GetBits(), STARTHF2, DecHf2, PosHf2); while (true) @@ -660,7 +805,9 @@ namespace SharpCompress.Compressors.Rar.UnpackV1 private void corrHuff(int[] CharSet, int[] NumToPlace) { - int I, J, pos = 0; + int I, + J, + pos = 0; for (I = 7; I >= 0; I--) { for (J = 0; J < 32; J++, pos++) @@ -695,7 +842,10 @@ namespace SharpCompress.Compressors.Rar.UnpackV1 StartPos++; } AddBits(StartPos); - return ((Utility.URShift((Num - (I != 0 ? DecTab[I - 1] : 0)), (16 - StartPos))) + PosTab[StartPos]); + return ( + (Utility.URShift((Num - (I != 0 ? DecTab[I - 1] : 0)), (16 - StartPos))) + + PosTab[StartPos] + ); } private void oldUnpWriteBuf() diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack20.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack20.cs index eb0ce540..fa28fc0d 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack20.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack20.cs @@ -18,7 +18,10 @@ namespace SharpCompress.Compressors.Rar.UnpackV1 private readonly byte[] UnpOldTable20 = new byte[PackDef.MC20 * 4]; - private int UnpAudioBlock, UnpChannels, UnpCurChannel, UnpChannelDelta; + private int UnpAudioBlock, + UnpChannels, + UnpCurChannel, + UnpChannelDelta; private readonly AudioVariables[] AudV = new AudioVariables[4]; @@ -34,30 +37,171 @@ namespace SharpCompress.Compressors.Rar.UnpackV1 private static readonly int[] LDecode = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, - 56, 64, 80, 96, 112, 128, 160, 192, 224 + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 10, + 12, + 14, + 16, + 20, + 24, + 28, + 32, + 40, + 48, + 56, + 64, + 80, + 96, + 112, + 128, + 160, + 192, + 224 }; - private static ReadOnlySpan LBits => new byte[] - { - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, - 4, 5, 5, 5, 5 - }; + private static ReadOnlySpan LBits => + new byte[] + { + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 4, + 4, + 4, + 4, + 5, + 5, + 5, + 5 + }; private static readonly int[] DDecode = { - 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192, 256, 384, - 512, 768, 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, - 24576, 32768, 49152, 65536, 98304, 131072, 196608, 262144, 327680, - 393216, 458752, 524288, 589824, 655360, 720896, 786432, 851968, - 917504, 983040 + 0, + 1, + 2, + 3, + 4, + 6, + 8, + 12, + 16, + 24, + 32, + 48, + 64, + 96, + 128, + 192, + 256, + 384, + 512, + 768, + 1024, + 1536, + 2048, + 3072, + 4096, + 6144, + 8192, + 12288, + 16384, + 24576, + 32768, + 49152, + 65536, + 98304, + 131072, + 196608, + 262144, + 327680, + 393216, + 458752, + 524288, + 589824, + 655360, + 720896, + 786432, + 851968, + 917504, + 983040 }; private static readonly int[] DBits = { - 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, - 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16 - , 16, 16, 16, 16, 16, 16, 16 + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 2, + 3, + 3, + 4, + 4, + 5, + 5, + 6, + 6, + 7, + 7, + 8, + 8, + 9, + 9, + 10, + 10, + 11, + 11, + 12, + 12, + 13, + 13, + 14, + 14, + 15, + 15, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16 }; private static readonly int[] SDDecode = { 0, 4, 8, 16, 32, 64, 128, 192 }; @@ -249,7 +393,9 @@ namespace SharpCompress.Compressors.Rar.UnpackV1 { byte[] BitLength = new byte[PackDef.BC20]; byte[] Table = new byte[PackDef.MC20 * 4]; - int TableSize, N, I; + int TableSize, + N, + I; if (inAddr > readTop - 25) { if (!unpReadBuf()) @@ -346,7 +492,12 @@ namespace SharpCompress.Compressors.Rar.UnpackV1 { UnpackUtility.makeDecodeTables(Table, 0, LD, PackDef.NC20); UnpackUtility.makeDecodeTables(Table, PackDef.NC20, DD, PackDef.DC20); - UnpackUtility.makeDecodeTables(Table, PackDef.NC20 + PackDef.DC20, RD, PackDef.RC20); + UnpackUtility.makeDecodeTables( + Table, + PackDef.NC20 + PackDef.DC20, + RD, + PackDef.RC20 + ); } // memcpy(UnpOldTable20,Table,sizeof(UnpOldTable20)); @@ -434,7 +585,8 @@ namespace SharpCompress.Compressors.Rar.UnpackV1 if ((v.ByteCount & 0x1F) == 0) { - int MinDif = v.Dif[0], NumMinDif = 0; + int MinDif = v.Dif[0], + NumMinDif = 0; v.Dif[0] = 0; // ->Dif[0]=0; for (int I = 1; I < v.Dif.Length; I++) { diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack50.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack50.cs index d9e68205..a7cc9408 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack50.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack50.cs @@ -9,7 +9,6 @@ namespace SharpCompress.Compressors.Rar.UnpackV1 { internal partial class Unpack { - // Maximum allowed number of compressed bits processed in quick mode. private const int MAX_QUICK_DECODE_BITS = 10; @@ -108,19 +107,68 @@ namespace SharpCompress.Compressors.Rar.UnpackV1 private const int MaxWinMask = PackDef.MAXWINMASK; // TODO: rename var - private int UnpPtr { get { return unpPtr; } set { unpPtr = value; } } - private int ReadBorder { get { return readBorder; } set { readBorder = value; } } - private long DestUnpSize { get { return destUnpSize; } set { destUnpSize = value; } } - private long WrittenFileSize { get { return writtenFileSize; } set { writtenFileSize = value; } } - private byte[] Window { get { return window; } } - private uint LastLength { get { return (uint)lastLength; } set { lastLength = (int)value; } } - private uint OldDistN(int i) { return (uint)oldDist[i]; } - private void SetOldDistN(int i, uint value) { oldDist[i] = (int)value; } - private int WrPtr { get { return wrPtr; } set { wrPtr = value; } } - private Unpack BlockHeader { get { return this; } } - private Unpack Header { get { return this; } } - private int ReadTop { get { return readTop; } set { readTop = value; } } - private List Filters { get { return filters; } } + private int UnpPtr + { + get { return unpPtr; } + set { unpPtr = value; } + } + private int ReadBorder + { + get { return readBorder; } + set { readBorder = value; } + } + private long DestUnpSize + { + get { return destUnpSize; } + set { destUnpSize = value; } + } + private long WrittenFileSize + { + get { return writtenFileSize; } + set { writtenFileSize = value; } + } + private byte[] Window + { + get { return window; } + } + private uint LastLength + { + get { return (uint)lastLength; } + set { lastLength = (int)value; } + } + + private uint OldDistN(int i) + { + return (uint)oldDist[i]; + } + + private void SetOldDistN(int i, uint value) + { + oldDist[i] = (int)value; + } + + private int WrPtr + { + get { return wrPtr; } + set { wrPtr = value; } + } + private Unpack BlockHeader + { + get { return this; } + } + private Unpack Header + { + get { return this; } + } + private int ReadTop + { + get { return readTop; } + set { readTop = value; } + } + private List Filters + { + get { return filters; } + } // TODO: make sure these aren't already somewhere else public int BlockSize; @@ -145,8 +193,7 @@ namespace SharpCompress.Compressors.Rar.UnpackV1 // Check TablesRead5 to be sure that we read tables at least once // regardless of current block header TablePresent flag. // So we can safefly use these tables below. - if (!ReadBlockHeader() || - !ReadTables() || !TablesRead5) + if (!ReadBlockHeader() || !ReadTables() || !TablesRead5) { return; } @@ -162,9 +209,11 @@ namespace SharpCompress.Compressors.Rar.UnpackV1 // We use 'while', because for empty block containing only Huffman table, // we'll be on the block border once again just after reading the table. - while (Inp.InAddr > BlockHeader.BlockStart + BlockHeader.BlockSize - 1 || - Inp.InAddr == BlockHeader.BlockStart + BlockHeader.BlockSize - 1 && - Inp.InBit >= BlockHeader.BlockBitSize) + while ( + Inp.InAddr > BlockHeader.BlockStart + BlockHeader.BlockSize - 1 + || Inp.InAddr == BlockHeader.BlockStart + BlockHeader.BlockSize - 1 + && Inp.InBit >= BlockHeader.BlockBitSize + ) { if (BlockHeader.LastBlockInFile) { @@ -182,7 +231,10 @@ namespace SharpCompress.Compressors.Rar.UnpackV1 } } - if (((WriteBorder - UnpPtr) & MaxWinMask) < PackDef.MAX_LZ_MATCH + 3 && WriteBorder != UnpPtr) + if ( + ((WriteBorder - UnpPtr) & MaxWinMask) < PackDef.MAX_LZ_MATCH + 3 + && WriteBorder != UnpPtr + ) { UnpWriteBuf(); if (WrittenFileSize > DestUnpSize) @@ -213,7 +265,8 @@ namespace SharpCompress.Compressors.Rar.UnpackV1 //uint DBits,Distance=1,DistSlot=DecodeNumber(Inp,&BlockTables.DD); int DBits; - uint Distance = 1, DistSlot = this.DecodeNumber(DD); + uint Distance = 1, + DistSlot = this.DecodeNumber(DD); if (DistSlot < 4) { DBits = 0; @@ -379,7 +432,8 @@ namespace SharpCompress.Compressors.Rar.UnpackV1 // If distance to filter start is that large that due to circular dictionary // mode now it points to old not written yet data, then we set 'NextWindow' // flag and process this filter only after processing that older data. - Filter.NextWindow = WrPtr != UnpPtr && ((WrPtr - UnpPtr) & MaxWinMask) <= Filter.BlockStart; + Filter.NextWindow = + WrPtr != UnpPtr && ((WrPtr - UnpPtr) & MaxWinMask) <= Filter.BlockStart; Filter.uBlockStart = (uint)((Filter.BlockStart + UnpPtr) & MaxWinMask); Filters.Add(Filter); @@ -438,7 +492,10 @@ namespace SharpCompress.Compressors.Rar.UnpackV1 { // We may need to quit from main extraction loop and read new block header // and trees earlier than data in input buffer ends. - ReadBorder = Math.Min(ReadBorder, BlockHeader.BlockStart + BlockHeader.BlockSize - 1); + ReadBorder = Math.Min( + ReadBorder, + BlockHeader.BlockStart + BlockHeader.BlockSize - 1 + ); } return ReadCode != -1; } @@ -581,7 +638,7 @@ namespace SharpCompress.Compressors.Rar.UnpackV1 // // // Choose the nearest among WriteBorder and WrPtr actual written border. // // If border is equal to UnpPtr, it means that we have MaxWinSize data ahead. - // if (WriteBorder==UnpPtr || + // if (WriteBorder==UnpPtr || // WrPtr!=UnpPtr && ((WrPtr-UnpPtr)&MaxWinMask)<((WriteBorder-UnpPtr)&MaxWinMask)) // WriteBorder=WrPtr; // } @@ -766,7 +823,9 @@ namespace SharpCompress.Compressors.Rar.UnpackV1 } Header.BlockSize = BlockSize; - byte CheckSum = (byte)(0x5a ^ BlockFlags ^ BlockSize ^ (BlockSize >> 8) ^ (BlockSize >> 16)); + byte CheckSum = (byte)( + 0x5a ^ BlockFlags ^ BlockSize ^ (BlockSize >> 8) ^ (BlockSize >> 16) + ); if (CheckSum != SavedCheckSum) { return false; @@ -890,7 +949,6 @@ namespace SharpCompress.Compressors.Rar.UnpackV1 // { // Filters.SoftReset(); // } - } } -#endif \ No newline at end of file +#endif diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/UnpackFilter.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/UnpackFilter.cs index 66d5d887..82fb4e5e 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/UnpackFilter.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/UnpackFilter.cs @@ -13,8 +13,16 @@ namespace SharpCompress.Compressors.Rar.UnpackV1 } // TODO uint - internal uint uBlockStart { get { return (uint)BlockStart; } set { BlockStart = (int)value; } } - internal uint uBlockLength { get { return (uint)BlockLength; } set { BlockLength = (int)value; } } + internal uint uBlockStart + { + get { return (uint)BlockStart; } + set { BlockStart = (int)value; } + } + internal uint uBlockLength + { + get { return (uint)BlockLength; } + set { BlockLength = (int)value; } + } internal int BlockStart { get; set; } @@ -30,4 +38,4 @@ namespace SharpCompress.Compressors.Rar.UnpackV1 internal VMPreparedProgram Program { get; set; } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/UnpackInline.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/UnpackInline.cs index e509afa2..c49007f7 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/UnpackInline.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/UnpackInline.cs @@ -1,5 +1,4 @@ - -namespace SharpCompress.Compressors.Rar.UnpackV1 +namespace SharpCompress.Compressors.Rar.UnpackV1 { internal partial class Unpack { diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/UnpackUtility.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/UnpackUtility.cs index ec04db1c..b00ffcfa 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/UnpackUtility.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/UnpackUtility.cs @@ -174,7 +174,9 @@ namespace SharpCompress.Compressors.Rar.UnpackV1 } } input.AddBits(bits); - int N = dec.DecodePos[bits] + (Utility.URShift(((int)bitField - decodeLen[bits - 1]), (16 - bits))); + int N = + dec.DecodePos[bits] + + (Utility.URShift(((int)bitField - decodeLen[bits - 1]), (16 - bits))); if (N >= dec.MaxNum) { N = 0; @@ -182,12 +184,18 @@ namespace SharpCompress.Compressors.Rar.UnpackV1 return (dec.DecodeNum[N]); } - internal static void makeDecodeTables(byte[] lenTab, int offset, Decode.Decode dec, int size) + internal static void makeDecodeTables( + byte[] lenTab, + int offset, + Decode.Decode dec, + int size + ) { Span lenCount = stackalloc int[16]; Span tmpPos = stackalloc int[16]; int i; - long M, N; + long M, + N; new Span(dec.DecodeNum).Clear(); // memset(Dec->DecodeNum,0,Size*sizeof(*Dec->DecodeNum)); @@ -196,7 +204,11 @@ namespace SharpCompress.Compressors.Rar.UnpackV1 lenCount[lenTab[offset + i] & 0xF]++; } lenCount[0] = 0; - for (tmpPos[0] = 0, dec.DecodePos[0] = 0, dec.DecodeLen[0] = 0, N = 0, i = 1; i < 16; i++) + for ( + tmpPos[0] = 0, dec.DecodePos[0] = 0, dec.DecodeLen[0] = 0, N = 0, i = 1; + i < 16; + i++ + ) { N = 2 * (N + lenCount[i]); M = N << (15 - i); diff --git a/src/SharpCompress/Compressors/Rar/UnpackV2017/BitInput.getbits_cpp.cs b/src/SharpCompress/Compressors/Rar/UnpackV2017/BitInput.getbits_cpp.cs index c1de6517..b06d56a2 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV2017/BitInput.getbits_cpp.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV2017/BitInput.getbits_cpp.cs @@ -14,7 +14,6 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 { internal partial class BitInput { - public BitInput(bool AllocBuffer) { ExternalBuffer = false; @@ -37,7 +36,6 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 } } - //BitInput::~BitInput() //{ // if (!ExternalBuffer) @@ -45,15 +43,13 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 //} // - public - void faddbits(uint Bits) + public void faddbits(uint Bits) { // Function wrapped version of inline addbits to save code size. addbits(Bits); } - public - uint fgetbits() + public uint fgetbits() { // Function wrapped version of inline getbits to save code size. return getbits(); @@ -66,6 +62,5 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 InBuf = Buf; ExternalBuffer = true; } - } } diff --git a/src/SharpCompress/Compressors/Rar/UnpackV2017/BitInput.getbits_hpp.cs b/src/SharpCompress/Compressors/Rar/UnpackV2017/BitInput.getbits_hpp.cs index 14867ed8..3acb8f28 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV2017/BitInput.getbits_hpp.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV2017/BitInput.getbits_hpp.cs @@ -1,12 +1,11 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 { - internal partial class BitInput { public const int MAX_SIZE = 0x8000; // Size of input buffer. public int InAddr; // Curent byte position in the buffer. - public int InBit; // Current bit position in the current byte. + public int InBit; // Current bit position in the current byte. public bool ExternalBuffer; @@ -15,8 +14,7 @@ public byte[] InBuf; // Dynamically allocated input buffer. - public - void InitBitInput() + public void InitBitInput() { InAddr = InBit = 0; } @@ -66,5 +64,4 @@ //void SetExternalBuffer(byte *Buf); } - } diff --git a/src/SharpCompress/Compressors/Rar/UnpackV2017/FragmentedWindow.unpack50frag_cpp.cs b/src/SharpCompress/Compressors/Rar/UnpackV2017/FragmentedWindow.unpack50frag_cpp.cs index 66f8d06b..7b2a378d 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV2017/FragmentedWindow.unpack50frag_cpp.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV2017/FragmentedWindow.unpack50frag_cpp.cs @@ -17,14 +17,12 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 { internal partial class FragmentedWindow { - public FragmentedWindow() { //memset(Mem,0,sizeof(Mem)); //memset(MemSize,0,sizeof(MemSize)); } - //FragmentedWindow::~FragmentedWindow() //{ // Reset(); @@ -42,7 +40,6 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 } } - public void Init(size_t WinSize) { Reset(); @@ -87,13 +84,12 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 BlockNum++; } if (TotalSize < WinSize) // Not found enough free blocks. - //throw std::bad_alloc(); + //throw std::bad_alloc(); { throw new InvalidOperationException(); } } - public byte this[size_t Item] { get @@ -139,18 +135,24 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 if (Item < MemSize[0]) { //return Mem[0][Item]; - buf = Mem[0]; offset = Item; return; + buf = Mem[0]; + offset = Item; + return; } for (uint I = 1; I < MemSize.Length; I++) { if (Item < MemSize[I]) { //return Mem[I][Item-MemSize[I-1]]; - buf = Mem[I]; offset = Item - MemSize[I - 1]; return; + buf = Mem[I]; + offset = Item - MemSize[I - 1]; + return; } } //return Mem[0][0]; // Must never happen; - buf = Mem[0]; offset = 0; return; // Must never happen; + buf = Mem[0]; + offset = 0; + return; // Must never happen; } public void CopyString(uint Length, uint Distance, ref size_t UnpPtr, size_t MaxWinMask) @@ -165,7 +167,6 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 } } - public void CopyData(byte[] Dest, size_t destOffset, size_t WinPos, size_t Size) { for (size_t I = 0; I < Size; I++) @@ -174,7 +175,6 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 } } - public size_t GetBlockSize(size_t StartPos, size_t RequiredSize) { for (uint I = 0; I < MemSize.Length; I++) @@ -187,6 +187,5 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 return 0; // Must never be here. } - } } diff --git a/src/SharpCompress/Compressors/Rar/UnpackV2017/PackDef.compress_hpp.cs b/src/SharpCompress/Compressors/Rar/UnpackV2017/PackDef.compress_hpp.cs index 34021193..9863446d 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV2017/PackDef.compress_hpp.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV2017/PackDef.compress_hpp.cs @@ -2,7 +2,6 @@ { internal static class PackDef { - // Combine pack and unpack constants to class to avoid polluting global // namespace with numerous short names. public const uint MAX_LZ_MATCH = 0x1001; @@ -51,6 +50,5 @@ public const int FILTER_PPM = 7; public const int FILTER_NONE = 8; //} - } } diff --git a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.cs b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.cs index 7953fb89..f840edf7 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.cs @@ -43,7 +43,7 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 public void DoUnpack(FileHeader fileHeader, Stream readStream, Stream writeStream) { // as of 12/2017 .NET limits array indexing to using a signed integer - // MaxWinSize causes unpack to use a fragmented window when the file + // MaxWinSize causes unpack to use a fragmented window when the file // window size exceeds MaxWinSize // uggh, that's not how this variable is used, it's the size of the currently allocated window buffer //x MaxWinSize = ((uint)int.MaxValue) + 1; @@ -90,7 +90,10 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 public bool Suspended { get; set; } - public long DestSize { get => DestUnpSize; } + public long DestSize + { + get => DestUnpSize; + } public int Char { @@ -105,12 +108,15 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 } } - public int PpmEscChar { get => PPMEscChar; set => PPMEscChar = value; } + public int PpmEscChar + { + get => PPMEscChar; + set => PPMEscChar = value; + } public static byte[] EnsureCapacity(byte[] array, int length) { return array.Length < length ? new byte[length] : array; } - } } diff --git a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.rawint_hpp.cs b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.rawint_hpp.cs index 818d4295..69281b36 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.rawint_hpp.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.rawint_hpp.cs @@ -27,7 +27,9 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 private uint32 RawGet4(byte[] D, int offset) { - return (uint)(D[offset] + (D[offset + 1] << 8) + (D[offset + 2] << 16) + (D[offset + 3] << 24)); + return (uint)( + D[offset] + (D[offset + 1] << 8) + (D[offset + 2] << 16) + (D[offset + 3] << 24) + ); } //inline uint64 RawGet8(const void *Data) @@ -117,6 +119,5 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 // return (rotl32(i,24)&0xFF00FF00)|(rotl32(i,8)&0x00FF00FF); //#endif //} - } } diff --git a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack15_cpp.cs b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack15_cpp.cs index d3f2bd3a..b661725d 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack15_cpp.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack15_cpp.cs @@ -7,43 +7,102 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 { private const int STARTL1 = 2; - private static readonly uint[] DecL1 ={0x8000,0xa000,0xc000,0xd000,0xe000,0xea00, - 0xee00,0xf000,0xf200,0xf200,0xffff}; + private static readonly uint[] DecL1 = + { + 0x8000, + 0xa000, + 0xc000, + 0xd000, + 0xe000, + 0xea00, + 0xee00, + 0xf000, + 0xf200, + 0xf200, + 0xffff + }; private static readonly uint[] PosL1 = { 0, 0, 0, 2, 3, 5, 7, 11, 16, 20, 24, 32, 32 }; private const int STARTL2 = 3; - private static readonly uint[] DecL2 ={0xa000,0xc000,0xd000,0xe000,0xea00,0xee00, - 0xf000,0xf200,0xf240,0xffff}; + private static readonly uint[] DecL2 = + { + 0xa000, + 0xc000, + 0xd000, + 0xe000, + 0xea00, + 0xee00, + 0xf000, + 0xf200, + 0xf240, + 0xffff + }; private static readonly uint[] PosL2 = { 0, 0, 0, 0, 5, 7, 9, 13, 18, 22, 26, 34, 36 }; private const int STARTHF0 = 4; - private static readonly uint[] DecHf0 ={0x8000,0xc000,0xe000,0xf200,0xf200,0xf200, - 0xf200,0xf200,0xffff}; + private static readonly uint[] DecHf0 = + { + 0x8000, + 0xc000, + 0xe000, + 0xf200, + 0xf200, + 0xf200, + 0xf200, + 0xf200, + 0xffff + }; private static readonly uint[] PosHf0 = { 0, 0, 0, 0, 0, 8, 16, 24, 33, 33, 33, 33, 33 }; private const int STARTHF1 = 5; - private static readonly uint[] DecHf1 ={0x2000,0xc000,0xe000,0xf000,0xf200,0xf200, - 0xf7e0,0xffff}; + private static readonly uint[] DecHf1 = + { + 0x2000, + 0xc000, + 0xe000, + 0xf000, + 0xf200, + 0xf200, + 0xf7e0, + 0xffff + }; private static readonly uint[] PosHf1 = { 0, 0, 0, 0, 0, 0, 4, 44, 60, 76, 80, 80, 127 }; private const int STARTHF2 = 5; - private static readonly uint[] DecHf2 ={0x1000,0x2400,0x8000,0xc000,0xfa00,0xffff, - 0xffff,0xffff}; + private static readonly uint[] DecHf2 = + { + 0x1000, + 0x2400, + 0x8000, + 0xc000, + 0xfa00, + 0xffff, + 0xffff, + 0xffff + }; private static readonly uint[] PosHf2 = { 0, 0, 0, 0, 0, 0, 2, 7, 53, 117, 233, 0, 0 }; private const int STARTHF3 = 6; - private static readonly uint[] DecHf3 ={0x800,0x2400,0xee00,0xfe80,0xffff,0xffff, - 0xffff}; + private static readonly uint[] DecHf3 = + { + 0x800, + 0x2400, + 0xee00, + 0xfe80, + 0xffff, + 0xffff, + 0xffff + }; private static readonly uint[] PosHf3 = { 0, 0, 0, 0, 0, 0, 0, 2, 16, 218, 251, 0, 0 }; @@ -141,25 +200,100 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 UnpWriteBuf20(); } - //#define GetShortLen1(pos) ((pos)==1 ? Buf60+3:ShortLen1[pos]) - private uint GetShortLen1(uint pos) { return ((pos) == 1 ? (uint)(Buf60 + 3) : ShortLen1[pos]); } + private uint GetShortLen1(uint pos) + { + return ((pos) == 1 ? (uint)(Buf60 + 3) : ShortLen1[pos]); + } + //#define GetShortLen2(pos) ((pos)==3 ? Buf60+3:ShortLen2[pos]) - private uint GetShortLen2(uint pos) { return ((pos) == 3 ? (uint)(Buf60 + 3) : ShortLen2[pos]); } + private uint GetShortLen2(uint pos) + { + return ((pos) == 3 ? (uint)(Buf60 + 3) : ShortLen2[pos]); + } internal static class Unpack15Local { - public static readonly uint[] ShortLen1 = { 1, 3, 4, 4, 5, 6, 7, 8, 8, 4, 4, 5, 6, 6, 4, 0 }; - public static readonly uint[] ShortXor1 ={0,0xa0,0xd0,0xe0,0xf0,0xf8,0xfc,0xfe, - 0xff,0xc0,0x80,0x90,0x98,0x9c,0xb0}; - public static readonly uint[] ShortLen2 = { 2, 3, 3, 3, 4, 4, 5, 6, 6, 4, 4, 5, 6, 6, 4, 0 }; - public static readonly uint[] ShortXor2 ={0,0x40,0x60,0xa0,0xd0,0xe0,0xf0,0xf8, - 0xfc,0xc0,0x80,0x90,0x98,0x9c,0xb0}; + public static readonly uint[] ShortLen1 = + { + 1, + 3, + 4, + 4, + 5, + 6, + 7, + 8, + 8, + 4, + 4, + 5, + 6, + 6, + 4, + 0 + }; + public static readonly uint[] ShortXor1 = + { + 0, + 0xa0, + 0xd0, + 0xe0, + 0xf0, + 0xf8, + 0xfc, + 0xfe, + 0xff, + 0xc0, + 0x80, + 0x90, + 0x98, + 0x9c, + 0xb0 + }; + public static readonly uint[] ShortLen2 = + { + 2, + 3, + 3, + 3, + 4, + 4, + 5, + 6, + 6, + 4, + 4, + 5, + 6, + 6, + 4, + 0 + }; + public static readonly uint[] ShortXor2 = + { + 0, + 0x40, + 0x60, + 0xa0, + 0xd0, + 0xe0, + 0xf0, + 0xf8, + 0xfc, + 0xc0, + 0x80, + 0x90, + 0x98, + 0x9c, + 0xb0 + }; } private void ShortLZ() { - uint Length, SaveLength; + uint Length, + SaveLength; uint LastDistance; uint Distance; int DistancePlace; @@ -187,7 +321,10 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 { for (Length = 0; ; Length++) { - if (((BitField ^ ShortXor1[Length]) & (~(0xff >> (int)GetShortLen1(Length)))) == 0) + if ( + ((BitField ^ ShortXor1[Length]) & (~(0xff >> (int)GetShortLen1(Length)))) + == 0 + ) { break; } @@ -199,7 +336,10 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 { for (Length = 0; ; Length++) { - if (((BitField ^ ShortXor2[Length]) & (~(0xff >> (int)GetShortLen2(Length)))) == 0) + if ( + ((BitField ^ ShortXor2[Length]) & (~(0xff >> (int)GetShortLen2(Length)))) + == 0 + ) { break; } @@ -279,8 +419,10 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 { uint Length; uint Distance; - uint DistancePlace, NewDistancePlace; - uint OldAvr2, OldAvr3; + uint DistancePlace, + NewDistancePlace; + uint OldAvr2, + OldAvr3; NumHuf = 0; Nlzb += 16; @@ -296,13 +438,11 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 { Length = DecodeNum(BitField, STARTL2, DecL2, PosL2); } - else - if (AvrLn2 >= 64) + else if (AvrLn2 >= 64) { Length = DecodeNum(BitField, STARTL1, DecL1, PosL1); } - else - if (BitField < 0x100) + else if (BitField < 0x100) { Length = BitField; Inp.faddbits(16); @@ -325,8 +465,7 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 { DistancePlace = DecodeNum(BitField, STARTHF2, DecHf2, PosHf2); } - else - if (AvrPlcB > 0x6ff) + else if (AvrPlcB > 0x6ff) { DistancePlace = DecodeNum(BitField, STARTHF1, DecHf1, PosHf1); } @@ -365,8 +504,7 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 AvrLn3++; AvrLn3 -= AvrLn3 >> 8; } - else - if (AvrLn3 > 0) + else if (AvrLn3 > 0) { AvrLn3--; } @@ -401,7 +539,8 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 private void HuffDecode() { - uint CurByte, NewBytePlace; + uint CurByte, + NewBytePlace; uint Length; uint Distance; int BytePlace; @@ -412,18 +551,15 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 { BytePlace = (int)DecodeNum(BitField, STARTHF4, DecHf4, PosHf4); } - else - if (AvrPlc > 0x5dff) + else if (AvrPlc > 0x5dff) { BytePlace = (int)DecodeNum(BitField, STARTHF3, DecHf3, PosHf3); } - else - if (AvrPlc > 0x35ff) + else if (AvrPlc > 0x35ff) { BytePlace = (int)DecodeNum(BitField, STARTHF2, DecHf2, PosHf2); } - else - if (AvrPlc > 0x0dff) + else if (AvrPlc > 0x0dff) { BytePlace = (int)DecodeNum(BitField, STARTHF1, DecHf1, PosHf1); } @@ -461,8 +597,7 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 } } } - else - if (NumHuf++ >= 16 && FlagsCnt == 0) + else if (NumHuf++ >= 16 && FlagsCnt == 0) { StMode = 1; } @@ -499,7 +634,8 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 private void GetFlagsBuf() { - uint Flags, NewFlagsPlace; + uint Flags, + NewFlagsPlace; uint FlagsPlace = DecodeNum(Inp.fgetbits(), STARTHF2, DecHf2, PosHf2); // Our Huffman table stores 257 items and needs all them in other parts @@ -562,7 +698,8 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 private void CorrHuff(ushort[] CharSet, byte[] NumToPlace) { - int I, J; + int I, + J; for (I = 7; I >= 0; I--) for (J = 0; J < 32; J++) { @@ -595,8 +732,9 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 } Inp.faddbits(StartPos); - return (((Num - (I != 0 ? DecTab[I - 1] : 0)) >> (int)(16 - StartPos)) + PosTab[StartPos]); + return ( + ((Num - (I != 0 ? DecTab[I - 1] : 0)) >> (int)(16 - StartPos)) + PosTab[StartPos] + ); } - } } diff --git a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack20_cpp.cs b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack20_cpp.cs index 7f59f6dd..52133cf9 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack20_cpp.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack20_cpp.cs @@ -25,13 +25,172 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 CopyString(Length, Distance); } - internal static class Unpack20Local { - public static readonly byte[] LDecode = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224 }; - public static readonly byte[] LBits = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5 }; - public static readonly uint[] DDecode = { 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576, 32768U, 49152U, 65536, 98304, 131072, 196608, 262144, 327680, 393216, 458752, 524288, 589824, 655360, 720896, 786432, 851968, 917504, 983040 }; - public static readonly byte[] DBits = { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16 }; + public static readonly byte[] LDecode = + { + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 10, + 12, + 14, + 16, + 20, + 24, + 28, + 32, + 40, + 48, + 56, + 64, + 80, + 96, + 112, + 128, + 160, + 192, + 224 + }; + public static readonly byte[] LBits = + { + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 4, + 4, + 4, + 4, + 5, + 5, + 5, + 5 + }; + public static readonly uint[] DDecode = + { + 0, + 1, + 2, + 3, + 4, + 6, + 8, + 12, + 16, + 24, + 32, + 48, + 64, + 96, + 128, + 192, + 256, + 384, + 512, + 768, + 1024, + 1536, + 2048, + 3072, + 4096, + 6144, + 8192, + 12288, + 16384, + 24576, + 32768U, + 49152U, + 65536, + 98304, + 131072, + 196608, + 262144, + 327680, + 393216, + 458752, + 524288, + 589824, + 655360, + 720896, + 786432, + 851968, + 917504, + 983040 + }; + public static readonly byte[] DBits = + { + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 2, + 3, + 3, + 4, + 4, + 5, + 5, + 6, + 6, + 7, + 7, + 8, + 8, + 9, + 9, + 10, + 10, + 11, + 11, + 12, + 12, + 13, + 13, + 14, + 14, + 15, + 15, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16 + }; public static readonly byte[] SDDecode = { 0, 4, 8, 16, 32, 64, 128, 192 }; public static readonly byte[] SDBits = { 2, 2, 3, 4, 5, 6, 6, 6 }; } @@ -260,7 +419,7 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 Inp.addbits(4); } MakeDecodeTables(BitLength, 0, BlockTables.BD, BC20); - for (uint I = 0; I < TableSize;) + for (uint I = 0; I < TableSize; ) { if (Inp.InAddr > ReadTop - 5) { @@ -276,8 +435,7 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 Table[I] = (byte)((Number + UnpOldTable20[I]) & 0xf); I++; } - else - if (Number == 16) + else if (Number == 16) { uint N = (Inp.getbits() >> 14) + 3; Inp.addbits(2); @@ -348,8 +506,7 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 ReadTables20(); } } - else - if (DecodeNumber(Inp, BlockTables.LD) == 269) + else if (DecodeNumber(Inp, BlockTables.LD) == 269) { ReadTables20(); } @@ -382,7 +539,13 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 V.D3 = V.D2; V.D2 = V.LastDelta - V.D1; V.D1 = V.LastDelta; - int PCh = 8 * V.LastChar + V.K1 * V.D1 + V.K2 * V.D2 + V.K3 * V.D3 + V.K4 * V.D4 + V.K5 * UnpChannelDelta; + int PCh = + 8 * V.LastChar + + V.K1 * V.D1 + + V.K2 * V.D2 + + V.K3 * V.D3 + + V.K4 * V.D4 + + V.K5 * UnpChannelDelta; PCh = (PCh >> 3) & 0xFF; uint Ch = (uint)(PCh - Delta); @@ -409,7 +572,8 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 if ((V.ByteCount & 0x1F) == 0) { - uint MinDif = V.Dif[0], NumMinDif = 0; + uint MinDif = V.Dif[0], + NumMinDif = 0; V.Dif[0] = 0; for (uint I = 1; I < V.Dif.Length; I++) { @@ -496,6 +660,5 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 } return (byte)Ch; } - } } diff --git a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack30_cpp.cs b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack30_cpp.cs index 1647b902..8491f7af 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack30_cpp.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack30_cpp.cs @@ -307,7 +307,7 @@ bool ReadEndOfBlock() bool ReadVMCode() { - // Entire VM code is guaranteed to fully present in block defined + // Entire VM code is guaranteed to fully present in block defined // by current Huffman table. Compressor checks that VM code does not cross // Huffman block boundaries. uint FirstByte=Inp.getbits()>>8; @@ -418,7 +418,7 @@ bool AddVMCode(uint FirstByte,byte[] Code,int CodeSize) Filters30[Filters30.Count-1]=Filter=new UnpackFilter30(); StackFilter.ParentFilter=(uint)(Filters30.Count-1); - // Reserve one item to store the data block length of our new filter + // Reserve one item to store the data block length of our new filter // entry. We'll set it to real block length below, after reading it. // But we need to initialize it now, because when processing corrupt // data, we can access this item even before we set it to real value. @@ -466,7 +466,7 @@ bool AddVMCode(uint FirstByte,byte[] Code,int CodeSize) else { // Set the data block size to same value as the previous block size - // for same filter. It is possible for corrupt data to access a new + // for same filter. It is possible for corrupt data to access a new // and not filled yet item of OldFilterLengths array here. This is why // we set new OldFilterLengths items to zero above. StackFilter.BlockLength=FiltPos BlockHeader.BlockStart + BlockHeader.BlockSize - 1 || - Inp.InAddr == BlockHeader.BlockStart + BlockHeader.BlockSize - 1 && - Inp.InBit >= BlockHeader.BlockBitSize) + while ( + Inp.InAddr > BlockHeader.BlockStart + BlockHeader.BlockSize - 1 + || Inp.InAddr == BlockHeader.BlockStart + BlockHeader.BlockSize - 1 + && Inp.InBit >= BlockHeader.BlockBitSize + ) { if (BlockHeader.LastBlockInFile) { FileDone = true; break; } - if (!ReadBlockHeader(Inp, ref BlockHeader) || !ReadTables(Inp, ref BlockHeader, ref BlockTables)) + if ( + !ReadBlockHeader(Inp, ref BlockHeader) + || !ReadTables(Inp, ref BlockHeader, ref BlockTables) + ) { return; } @@ -71,7 +79,10 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 } } - if (((WriteBorder - UnpPtr) & MaxWinMask) < MAX_LZ_MATCH + 3 && WriteBorder != UnpPtr) + if ( + ((WriteBorder - UnpPtr) & MaxWinMask) < MAX_LZ_MATCH + 3 + && WriteBorder != UnpPtr + ) { UnpWriteBuf(); if (WrittenFileSize > DestUnpSize) @@ -104,7 +115,9 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 { uint Length = SlotToLength(Inp, MainSlot - 262); - uint DBits, Distance = 1, DistSlot = DecodeNumber(Inp, BlockTables.DD); + uint DBits, + Distance = 1, + DistSlot = DecodeNumber(Inp, BlockTables.DD); if (DistSlot < 4) { DBits = 0; @@ -273,7 +286,8 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 // If distance to filter start is that large that due to circular dictionary // mode now it points to old not written yet data, then we set 'NextWindow' // flag and process this filter only after processing that older data. - Filter.NextWindow = WrPtr != UnpPtr && ((WrPtr - UnpPtr) & MaxWinMask) <= Filter.BlockStart; + Filter.NextWindow = + WrPtr != UnpPtr && ((WrPtr - UnpPtr) & MaxWinMask) <= Filter.BlockStart; Filter.BlockStart = (uint)((Filter.BlockStart + UnpPtr) & MaxWinMask); Filters.Add(Filter); @@ -328,7 +342,10 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 { // We may need to quit from main extraction loop and read new block header // and trees earlier than data in input buffer ends. - ReadBorder = Math.Min(ReadBorder, BlockHeader.BlockStart + BlockHeader.BlockSize - 1); + ReadBorder = Math.Min( + ReadBorder, + BlockHeader.BlockStart + BlockHeader.BlockSize - 1 + ); } return ReadCode != -1; } @@ -393,7 +410,10 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 uint BlockEnd = (BlockStart + BlockLength) & MaxWinMask; //x FilterSrcMemory.Alloc(BlockLength); - FilterSrcMemory = EnsureCapacity(FilterSrcMemory, checked((int)BlockLength)); + FilterSrcMemory = EnsureCapacity( + FilterSrcMemory, + checked((int)BlockLength) + ); byte[] Mem = FilterSrcMemory; if (BlockStart < BlockEnd || BlockEnd == 0) { @@ -502,8 +522,11 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 // Choose the nearest among WriteBorder and WrPtr actual written border. // If border is equal to UnpPtr, it means that we have MaxWinSize data ahead. - if (WriteBorder == UnpPtr || - WrPtr != UnpPtr && ((WrPtr - UnpPtr) & MaxWinMask) < ((WriteBorder - UnpPtr) & MaxWinMask)) + if ( + WriteBorder == UnpPtr + || WrPtr != UnpPtr + && ((WrPtr - UnpPtr) & MaxWinMask) < ((WriteBorder - UnpPtr) & MaxWinMask) + ) { WriteBorder = WrPtr; } @@ -517,6 +540,7 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 { case FILTER_E8: case FILTER_E8E9: + { uint FileOffset = (uint)WrittenFileSize; @@ -524,7 +548,7 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 byte CmpByte2 = Flt.Type == FILTER_E8E9 ? (byte)0xe9 : (byte)0xe8; // DataSize is unsigned, so we use "CurPos+4" and not "DataSize-4" // to avoid overflow for DataSize<4. - for (uint CurPos = 0; CurPos + 4 < DataSize;) + for (uint CurPos = 0; CurPos + 4 < DataSize; ) { //x byte CurByte=*(Data++); byte CurByte = __d[Data++]; @@ -536,15 +560,14 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 // We check 0x80000000 bit instead of '< 0' comparison // not assuming int32 presence or uint size and endianness. - if ((Addr & 0x80000000) != 0) // Addr<0 + if ((Addr & 0x80000000) != 0) // Addr<0 { - if (((Addr + Offset) & 0x80000000) == 0) // Addr+Offset>=0 + if (((Addr + Offset) & 0x80000000) == 0) // Addr+Offset>=0 { RawPut4(Addr + FileSize, __d, Data); } } - else - if (((Addr - FileSize) & 0x80000000) != 0) // Addr> 8); @@ -575,29 +602,29 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 } return SrcData; case FILTER_DELTA: + { + // Unlike RAR3, we do not need to reject excessive channel + // values here, since RAR5 uses only 5 bits to store channel. + uint Channels = Flt.Channels, + SrcPos = 0; + + //x FilterDstMemory.Alloc(DataSize); + FilterDstMemory = EnsureCapacity(FilterDstMemory, checked((int)DataSize)); + + byte[] DstData = FilterDstMemory; + + // Bytes from same channels are grouped to continual data blocks, + // so we need to place them back to their interleaving positions. + for (uint CurChannel = 0; CurChannel < Channels; CurChannel++) { - // Unlike RAR3, we do not need to reject excessive channel - // values here, since RAR5 uses only 5 bits to store channel. - uint Channels = Flt.Channels, SrcPos = 0; - - //x FilterDstMemory.Alloc(DataSize); - FilterDstMemory = EnsureCapacity(FilterDstMemory, checked((int)DataSize)); - - byte[] DstData = FilterDstMemory; - - // Bytes from same channels are grouped to continual data blocks, - // so we need to place them back to their interleaving positions. - for (uint CurChannel = 0; CurChannel < Channels; CurChannel++) + byte PrevByte = 0; + for (uint DestPos = CurChannel; DestPos < DataSize; DestPos += Channels) { - byte PrevByte = 0; - for (uint DestPos = CurChannel; DestPos < DataSize; DestPos += Channels) - { - DstData[DestPos] = (PrevByte -= __d[Data + SrcPos++]); - } + DstData[DestPos] = (PrevByte -= __d[Data + SrcPos++]); } - return DstData; } - + return DstData; + } } return null; } @@ -627,8 +654,7 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 StartPtr = (StartPtr + BlockSize) & MaxWinMask; } } - else - if (EndPtr < StartPtr) + else if (EndPtr < StartPtr) { UnpWriteData(Window, StartPtr, MaxWinSize - StartPtr); UnpWriteData(Window, 0, EndPtr); @@ -703,7 +729,9 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 } Header.BlockSize = BlockSize; - byte CheckSum = (byte)(0x5a ^ BlockFlags ^ BlockSize ^ (BlockSize >> 8) ^ (BlockSize >> 16)); + byte CheckSum = (byte)( + 0x5a ^ BlockFlags ^ BlockSize ^ (BlockSize >> 8) ^ (BlockSize >> 16) + ); if (CheckSum != SavedCheckSum) { return false; @@ -717,7 +745,11 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 return true; } - private bool ReadTables(BitInput Inp, ref UnpackBlockHeader Header, ref UnpackBlockTables Tables) + private bool ReadTables( + BitInput Inp, + ref UnpackBlockHeader Header, + ref UnpackBlockTables Tables + ) { if (!Header.TablePresent) { @@ -766,7 +798,7 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 byte[] Table = new byte[HUFF_TABLE_SIZE]; const uint TableSize = HUFF_TABLE_SIZE; - for (uint I = 0; I < TableSize;) + for (uint I = 0; I < TableSize; ) { if (!Inp.ExternalBuffer && Inp.InAddr > ReadTop - 5) { @@ -782,8 +814,7 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 Table[I] = (byte)Number; I++; } - else - if (Number < 18) + else if (Number < 18) { uint N; if (Number == 16) @@ -851,6 +882,5 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 //Filters.SoftReset(); Filters.Clear(); } - } } diff --git a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack_cpp.cs b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack_cpp.cs index 48df0608..17eecba5 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack_cpp.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack_cpp.cs @@ -19,10 +19,10 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 { internal sealed partial class Unpack : BitInput { - - public Unpack(/* ComprDataIO *DataIO */) - //:Inp(true),VMCodeInp(true) - : base(true) + public Unpack( /* ComprDataIO *DataIO */ + ) + //:Inp(true),VMCodeInp(true) + : base(true) { _UnpackCtor(); @@ -33,10 +33,10 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 UnpAllBuf = false; UnpSomeRead = false; #if RarV2017_RAR_SMP - MaxUserThreads=1; - UnpThreadPool=CreateThreadPool(); - ReadBufMT=null; - UnpThreadData=null; + MaxUserThreads = 1; + UnpThreadPool = CreateThreadPool(); + ReadBufMT = null; + UnpThreadData = null; #endif MaxWinSize = 0; MaxWinMask = 0; @@ -73,7 +73,9 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 if (WinSize == 0) //ErrHandler.MemoryError(); { - throw new InvalidFormatException("invalid window size (possibly due to a rar file with a 4GB being unpacked on a 32-bit platform)"); + throw new InvalidFormatException( + "invalid window size (possibly due to a rar file with a 4GB being unpacked on a 32-bit platform)" + ); } // Minimum window size must be at least twice more than maximum possible @@ -150,7 +152,9 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 { for (size_t I = 1; I <= MaxWinSize; I++) { - NewWindow[(UnpPtr - I) & (WinSize - 1)] = Window[(UnpPtr - I) & (MaxWinSize - 1)]; + NewWindow[(UnpPtr - I) & (WinSize - 1)] = Window[ + (UnpPtr - I) & (MaxWinSize - 1) + ]; } } @@ -198,24 +202,25 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 #endif case 50: // RAR 5.0 compression algorithm. #if RarV2017_RAR_SMP - if (MaxUserThreads>1) - { -// We do not use the multithreaded unpack routine to repack RAR archives -// in 'suspended' mode, because unlike the single threaded code it can -// write more than one dictionary for same loop pass. So we would need -// larger buffers of unknown size. Also we do not support multithreading -// in fragmented window mode. - if (!Fragmented) - { - Unpack5MT(Solid); - break; - } - } + if (MaxUserThreads > 1) + { + // We do not use the multithreaded unpack routine to repack RAR archives + // in 'suspended' mode, because unlike the single threaded code it can + // write more than one dictionary for same loop pass. So we would need + // larger buffers of unknown size. Also we do not support multithreading + // in fragmented window mode. + if (!Fragmented) + { + Unpack5MT(Solid); + break; + } + } #endif Unpack5(Solid); break; #if !Rar2017_NOSTRICT - default: throw new InvalidFormatException("unknown compression method " + Method); + default: + throw new InvalidFormatException("unknown compression method " + Method); #endif } } @@ -246,7 +251,7 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 //memset(&BlockHeader,0,sizeof(BlockHeader)); BlockHeader = new UnpackBlockHeader(); - BlockHeader.BlockSize = -1; // '-1' means not defined yet. + BlockHeader.BlockSize = -1; // '-1' means not defined yet. #if !RarV2017_SFX_MODULE UnpInitData20(Solid); #endif @@ -254,7 +259,6 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 UnpInitData50(Solid); } - // LengthTable contains the length in bits for every element of alphabet. // Dec is the structure to decode Huffman code/ // Size is size of length table and DecodeNum field in Dec structure, @@ -370,7 +374,9 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 // Find the upper limit for current bit field and adjust the bit length // accordingly if necessary. - while (CurBitLength < Dec.DecodeLen.Length && BitField >= Dec.DecodeLen[CurBitLength]) + while ( + CurBitLength < Dec.DecodeLen.Length && BitField >= Dec.DecodeLen[CurBitLength] + ) { CurBitLength++; } @@ -391,8 +397,10 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 // of first position for current bit length and right aligned distance // between our bit field and start code for current bit length. uint Pos; - if (CurBitLength < Dec.DecodePos.Length && - (Pos = Dec.DecodePos[CurBitLength] + Dist) < Size) + if ( + CurBitLength < Dec.DecodePos.Length + && (Pos = Dec.DecodePos[CurBitLength] + Dist) < Size + ) { // Define the code to alphabet number translation. Dec.QuickNum[Code] = Dec.DecodeNum[Pos]; @@ -404,6 +412,5 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 } } } - } } diff --git a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpackinline_cpp.cs b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpackinline_cpp.cs index 228be40b..8c585af2 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpackinline_cpp.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpackinline_cpp.cs @@ -76,7 +76,7 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 // // // This memcpy expanded inline by MSVC. We could also use uint64 // // assignment, which seems to provide about the same speed. - // memcpy(Dest,Src,8); + // memcpy(Dest,Src,8); // // Src+=8; // Dest+=8; @@ -155,7 +155,8 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 private uint SlotToLength(BitInput Inp, uint Slot) { - uint LBits, Length = 2; + uint LBits, + Length = 2; if (Slot < 8) { LBits = 0; @@ -174,6 +175,5 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 } return Length; } - } } diff --git a/src/SharpCompress/Compressors/Rar/VM/BitInput.cs b/src/SharpCompress/Compressors/Rar/VM/BitInput.cs index c0656086..b90d40d8 100644 --- a/src/SharpCompress/Compressors/Rar/VM/BitInput.cs +++ b/src/SharpCompress/Compressors/Rar/VM/BitInput.cs @@ -9,11 +9,18 @@ namespace SharpCompress.Compressors.Rar.VM public int inBit; // TODO: rename var - public int InAddr { get { return inAddr; } set { inAddr = value; } } - public int InBit { get { return inBit; } set { inBit = value; } } + public int InAddr + { + get { return inAddr; } + set { inAddr = value; } + } + public int InBit + { + get { return inBit; } + set { inBit = value; } + } public bool ExternalBuffer; - /// internal BitInput() { @@ -57,11 +64,11 @@ namespace SharpCompress.Compressors.Rar.VM return (uint)GetBits(); } - /// + /// /// (also named fgetbits) /// /// - /// the bits (unsigned short) + /// the bits (unsigned short) /// internal int GetBits() { @@ -71,9 +78,18 @@ namespace SharpCompress.Compressors.Rar.VM // BitField|=(int)(inBuf[inAddr+2])&0xFF; // BitField >>>= (8-inBit); // return (BitField & 0xffff); - return ((Utility.URShift((((InBuf[inAddr] & 0xff) << 16) - + ((InBuf[inAddr + 1] & 0xff) << 8) - + ((InBuf[inAddr + 2] & 0xff))), (8 - inBit))) & 0xffff); + return ( + ( + Utility.URShift( + ( + ((InBuf[inAddr] & 0xff) << 16) + + ((InBuf[inAddr + 1] & 0xff) << 8) + + ((InBuf[inAddr + 2] & 0xff)) + ), + (8 - inBit) + ) + ) & 0xffff + ); } /// Indicates an Overfow @@ -86,4 +102,4 @@ namespace SharpCompress.Compressors.Rar.VM return (inAddr + IncPtr >= MAX_SIZE); } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/Rar/VM/RarVM.cs b/src/SharpCompress/Compressors/Rar/VM/RarVM.cs index d7180efb..3ab8e2ca 100644 --- a/src/SharpCompress/Compressors/Rar/VM/RarVM.cs +++ b/src/SharpCompress/Compressors/Rar/VM/RarVM.cs @@ -132,7 +132,6 @@ namespace SharpCompress.Compressors.Rar.VM public void execute(VMPreparedProgram prg) { for (int i = 0; i < prg.InitR.Length; i++) - // memcpy(R,Prg->InitR,sizeof(Prg->InitR)); { R[i] = prg.InitR[i]; @@ -142,17 +141,16 @@ namespace SharpCompress.Compressors.Rar.VM if (globalSize != 0) { for (int i = 0; i < globalSize; i++) - // memcpy(Mem+VM_GLOBALMEMADDR,&Prg->GlobalData[0],GlobalSize); { Mem[VM_GLOBALMEMADDR + i] = prg.GlobalData[i]; } } - long staticSize = Math.Min(prg.StaticData.Count, VM_GLOBALMEMSIZE - globalSize) & 0xffFFffFF; + long staticSize = + Math.Min(prg.StaticData.Count, VM_GLOBALMEMSIZE - globalSize) & 0xffFFffFF; if (staticSize != 0) { for (int i = 0; i < staticSize; i++) - // memcpy(Mem+VM_GLOBALMEMADDR+GlobalSize,&Prg->StaticData[0],StaticSize); { Mem[VM_GLOBALMEMADDR + (int)globalSize + i] = prg.StaticData[i]; @@ -162,10 +160,8 @@ namespace SharpCompress.Compressors.Rar.VM flags = 0; //UPGRADE_NOTE: There is an untranslated Statement. Please refer to original code. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1153'" - List preparedCode = prg.AltCommands.Count != 0 - ? prg - .AltCommands - : prg.Commands; + List preparedCode = + prg.AltCommands.Count != 0 ? prg.AltCommands : prg.Commands; if (!ExecuteCode(preparedCode, prg.CommandCount)) { @@ -184,14 +180,16 @@ namespace SharpCompress.Compressors.Rar.VM prg.GlobalData.Clear(); - int dataSize = Math.Min(GetValue(false, Mem, VM_GLOBALMEMADDR + 0x30), VM_GLOBALMEMSIZE - VM_FIXEDGLOBALSIZE); + int dataSize = Math.Min( + GetValue(false, Mem, VM_GLOBALMEMADDR + 0x30), + VM_GLOBALMEMSIZE - VM_FIXEDGLOBALSIZE + ); if (dataSize != 0) { //prg.GlobalData.Clear(); // ->GlobalData.Add(dataSize+VM_FIXEDGLOBALSIZE); prg.GlobalData.Capacity = dataSize + VM_FIXEDGLOBALSIZE; for (int i = 0; i < dataSize + VM_FIXEDGLOBALSIZE; i++) - // memcpy(&Prg->GlobalData[0],&Mem[VM_GLOBALMEMADDR],DataSize+VM_FIXEDGLOBALSIZE); { prg.GlobalData.Add(Mem[VM_GLOBALMEMADDR + i]); @@ -215,8 +213,7 @@ namespace SharpCompress.Compressors.Rar.VM return true; } - private bool ExecuteCode(List preparedCode, - int cmdCount) + private bool ExecuteCode(List preparedCode, int cmdCount) { maxOpCount = 25000000; codeSize = cmdCount; @@ -244,6 +241,7 @@ namespace SharpCompress.Compressors.Rar.VM break; case VMCommands.VM_CMP: + { VMFlags value1 = (VMFlags)GetValue(cmd.IsByteMode, Mem, op1); VMFlags result = value1 - GetValue(cmd.IsByteMode, Mem, op2); @@ -254,12 +252,15 @@ namespace SharpCompress.Compressors.Rar.VM } else { - flags = (VMFlags)((result > value1) ? 1 : 0 | (int)(result & VMFlags.VM_FS)); + flags = (VMFlags)( + (result > value1) ? 1 : 0 | (int)(result & VMFlags.VM_FS) + ); } } break; case VMCommands.VM_CMPB: + { VMFlags value1 = (VMFlags)GetValue(true, Mem, op1); VMFlags result = value1 - GetValue(true, Mem, op2); @@ -269,12 +270,15 @@ namespace SharpCompress.Compressors.Rar.VM } else { - flags = (VMFlags)((result > value1) ? 1 : 0 | (int)(result & VMFlags.VM_FS)); + flags = (VMFlags)( + (result > value1) ? 1 : 0 | (int)(result & VMFlags.VM_FS) + ); } } break; case VMCommands.VM_CMPD: + { VMFlags value1 = (VMFlags)GetValue(false, Mem, op1); VMFlags result = value1 - GetValue(false, Mem, op2); @@ -284,87 +288,127 @@ namespace SharpCompress.Compressors.Rar.VM } else { - flags = (VMFlags)((result > value1) ? 1 : 0 | (int)(result & VMFlags.VM_FS)); + flags = (VMFlags)( + (result > value1) ? 1 : 0 | (int)(result & VMFlags.VM_FS) + ); } } break; case VMCommands.VM_ADD: + { int value1 = GetValue(cmd.IsByteMode, Mem, op1); - int result = - (int) - (((value1 + (long)GetValue(cmd.IsByteMode, Mem, op2))) & - unchecked((int)0xffffffff)); + int result = (int)( + ((value1 + (long)GetValue(cmd.IsByteMode, Mem, op2))) + & unchecked((int)0xffffffff) + ); if (cmd.IsByteMode) { result &= 0xff; - flags = - (VMFlags) - ((result < value1) - ? 1 - : 0 | - (result == 0 - ? (int)VMFlags.VM_FZ - : (((result & 0x80) != 0) ? (int)VMFlags.VM_FS : 0))); + flags = (VMFlags)( + (result < value1) + ? 1 + : 0 + | ( + result == 0 + ? (int)VMFlags.VM_FZ + : ( + ((result & 0x80) != 0) + ? (int)VMFlags.VM_FS + : 0 + ) + ) + ); // Flags=(Result value1) ? 1 : 0 | (result & (int)VMFlags.VM_FS))); + int result = (int)( + value1 + & 0xffFFffFF - GetValue(cmd.IsByteMode, Mem, op2) + & unchecked((int)0xFFffFFff) + ); + flags = (VMFlags)( + (result == 0) + ? (int)VMFlags.VM_FZ + : ((result > value1) ? 1 : 0 | (result & (int)VMFlags.VM_FS)) + ); SetValue(cmd.IsByteMode, Mem, op1, result); // (Cmd->ByteMode,Op1,Result); } break; case VMCommands.VM_SUBB: - SetValue(true, Mem, op1, - (int) - (GetValue(true, Mem, op1) & 0xFFffFFff - GetValue(true, Mem, op2) & - unchecked((int)0xFFffFFff))); + SetValue( + true, + Mem, + op1, + (int)( + GetValue(true, Mem, op1) + & 0xFFffFFff - GetValue(true, Mem, op2) + & unchecked((int)0xFFffFFff) + ) + ); break; case VMCommands.VM_SUBD: - SetValue(false, Mem, op1, - (int) - (GetValue(false, Mem, op1) & 0xFFffFFff - GetValue(false, Mem, op2) & - unchecked((int)0xFFffFFff))); + SetValue( + false, + Mem, + op1, + (int)( + GetValue(false, Mem, op1) + & 0xFFffFFff - GetValue(false, Mem, op2) + & unchecked((int)0xFFffFFff) + ) + ); break; case VMCommands.VM_JZ: @@ -384,31 +428,49 @@ namespace SharpCompress.Compressors.Rar.VM break; case VMCommands.VM_INC: + { - int result = (int)(GetValue(cmd.IsByteMode, Mem, op1) & 0xFFffFFffL + 1L); + int result = (int)( + GetValue(cmd.IsByteMode, Mem, op1) & 0xFFffFFffL + 1L + ); if (cmd.IsByteMode) { result &= 0xff; } SetValue(cmd.IsByteMode, Mem, op1, result); - flags = (VMFlags)(result == 0 ? (int)VMFlags.VM_FZ : result & (int)VMFlags.VM_FS); + flags = (VMFlags)( + result == 0 ? (int)VMFlags.VM_FZ : result & (int)VMFlags.VM_FS + ); } break; case VMCommands.VM_INCB: - SetValue(true, Mem, op1, (int)(GetValue(true, Mem, op1) & 0xFFffFFffL + 1L)); + SetValue( + true, + Mem, + op1, + (int)(GetValue(true, Mem, op1) & 0xFFffFFffL + 1L) + ); break; case VMCommands.VM_INCD: - SetValue(false, Mem, op1, (int)(GetValue(false, Mem, op1) & 0xFFffFFffL + 1L)); + SetValue( + false, + Mem, + op1, + (int)(GetValue(false, Mem, op1) & 0xFFffFFffL + 1L) + ); break; case VMCommands.VM_DEC: + { int result = (int)(GetValue(cmd.IsByteMode, Mem, op1) & 0xFFffFFff - 1); SetValue(cmd.IsByteMode, Mem, op1, result); - flags = (VMFlags)(result == 0 ? (int)VMFlags.VM_FZ : result & (int)VMFlags.VM_FS); + flags = (VMFlags)( + result == 0 ? (int)VMFlags.VM_FZ : result & (int)VMFlags.VM_FS + ); } break; @@ -417,7 +479,12 @@ namespace SharpCompress.Compressors.Rar.VM break; case VMCommands.VM_DECD: - SetValue(false, Mem, op1, (int)(GetValue(false, Mem, op1) & 0xFFffFFff - 1)); + SetValue( + false, + Mem, + op1, + (int)(GetValue(false, Mem, op1) & 0xFFffFFff - 1) + ); break; case VMCommands.VM_JMP: @@ -425,33 +492,53 @@ namespace SharpCompress.Compressors.Rar.VM continue; case VMCommands.VM_XOR: + { - int result = GetValue(cmd.IsByteMode, Mem, op1) ^ GetValue(cmd.IsByteMode, Mem, op2); - flags = (VMFlags)(result == 0 ? (int)VMFlags.VM_FZ : result & (int)VMFlags.VM_FS); + int result = + GetValue(cmd.IsByteMode, Mem, op1) + ^ GetValue(cmd.IsByteMode, Mem, op2); + flags = (VMFlags)( + result == 0 ? (int)VMFlags.VM_FZ : result & (int)VMFlags.VM_FS + ); SetValue(cmd.IsByteMode, Mem, op1, result); } break; case VMCommands.VM_AND: + { - int result = GetValue(cmd.IsByteMode, Mem, op1) & GetValue(cmd.IsByteMode, Mem, op2); - flags = (VMFlags)(result == 0 ? (int)VMFlags.VM_FZ : result & (int)VMFlags.VM_FS); + int result = + GetValue(cmd.IsByteMode, Mem, op1) + & GetValue(cmd.IsByteMode, Mem, op2); + flags = (VMFlags)( + result == 0 ? (int)VMFlags.VM_FZ : result & (int)VMFlags.VM_FS + ); SetValue(cmd.IsByteMode, Mem, op1, result); } break; case VMCommands.VM_OR: + { - int result = GetValue(cmd.IsByteMode, Mem, op1) | GetValue(cmd.IsByteMode, Mem, op2); - flags = (VMFlags)(result == 0 ? (int)VMFlags.VM_FZ : result & (int)VMFlags.VM_FS); + int result = + GetValue(cmd.IsByteMode, Mem, op1) + | GetValue(cmd.IsByteMode, Mem, op2); + flags = (VMFlags)( + result == 0 ? (int)VMFlags.VM_FZ : result & (int)VMFlags.VM_FS + ); SetValue(cmd.IsByteMode, Mem, op1, result); } break; case VMCommands.VM_TEST: + { - int result = GetValue(cmd.IsByteMode, Mem, op1) & GetValue(cmd.IsByteMode, Mem, op2); - flags = (VMFlags)(result == 0 ? (int)VMFlags.VM_FZ : result & (int)VMFlags.VM_FS); + int result = + GetValue(cmd.IsByteMode, Mem, op1) + & GetValue(cmd.IsByteMode, Mem, op2); + flags = (VMFlags)( + result == 0 ? (int)VMFlags.VM_FZ : result & (int)VMFlags.VM_FS + ); } break; @@ -524,54 +611,60 @@ namespace SharpCompress.Compressors.Rar.VM break; case VMCommands.VM_SHL: + { int value1 = GetValue(cmd.IsByteMode, Mem, op1); int value2 = GetValue(cmd.IsByteMode, Mem, op2); int result = value1 << value2; - flags = - (VMFlags) - ((result == 0 ? (int)VMFlags.VM_FZ : (result & (int)VMFlags.VM_FS)) | - (((value1 << (value2 - 1)) & unchecked((int)0x80000000)) != 0 - ? (int)VMFlags.VM_FC - : 0)); + flags = (VMFlags)( + (result == 0 ? (int)VMFlags.VM_FZ : (result & (int)VMFlags.VM_FS)) + | ( + ((value1 << (value2 - 1)) & unchecked((int)0x80000000)) != 0 + ? (int)VMFlags.VM_FC + : 0 + ) + ); SetValue(cmd.IsByteMode, Mem, op1, result); } break; case VMCommands.VM_SHR: + { int value1 = GetValue(cmd.IsByteMode, Mem, op1); int value2 = GetValue(cmd.IsByteMode, Mem, op2); int result = Utility.URShift(value1, value2); - flags = - (VMFlags) - ((result == 0 ? (int)VMFlags.VM_FZ : (result & (int)VMFlags.VM_FS)) | - ((Utility.URShift(value1, (value2 - 1))) & (int)VMFlags.VM_FC)); + flags = (VMFlags)( + (result == 0 ? (int)VMFlags.VM_FZ : (result & (int)VMFlags.VM_FS)) + | ((Utility.URShift(value1, (value2 - 1))) & (int)VMFlags.VM_FC) + ); SetValue(cmd.IsByteMode, Mem, op1, result); } break; case VMCommands.VM_SAR: + { int value1 = GetValue(cmd.IsByteMode, Mem, op1); int value2 = GetValue(cmd.IsByteMode, Mem, op2); int result = value1 >> value2; - flags = - (VMFlags) - ((result == 0 ? (int)VMFlags.VM_FZ : (result & (int)VMFlags.VM_FS)) | - ((value1 >> (value2 - 1)) & (int)VMFlags.VM_FC)); + flags = (VMFlags)( + (result == 0 ? (int)VMFlags.VM_FZ : (result & (int)VMFlags.VM_FS)) + | ((value1 >> (value2 - 1)) & (int)VMFlags.VM_FC) + ); SetValue(cmd.IsByteMode, Mem, op1, result); } break; case VMCommands.VM_NEG: + { int result = -GetValue(cmd.IsByteMode, Mem, op1); - flags = - (VMFlags) - (result == 0 - ? (int)VMFlags.VM_FZ - : (int)VMFlags.VM_FC | (result & (int)VMFlags.VM_FS)); + flags = (VMFlags)( + result == 0 + ? (int)VMFlags.VM_FZ + : (int)VMFlags.VM_FC | (result & (int)VMFlags.VM_FS) + ); SetValue(cmd.IsByteMode, Mem, op1, result); } break; @@ -585,6 +678,7 @@ namespace SharpCompress.Compressors.Rar.VM break; case VMCommands.VM_PUSHA: + { for (int i = 0, SP = R[7] - 4; i < regCount; i++, SP -= 4) { @@ -595,6 +689,7 @@ namespace SharpCompress.Compressors.Rar.VM break; case VMCommands.VM_POPA: + { for (int i = 0, SP = R[7]; i < regCount; i++, SP += 4) { @@ -622,6 +717,7 @@ namespace SharpCompress.Compressors.Rar.VM break; case VMCommands.VM_XCHG: + { int value1 = GetValue(cmd.IsByteMode, Mem, op1); SetValue(cmd.IsByteMode, Mem, op1, GetValue(cmd.IsByteMode, Mem, op2)); @@ -630,17 +726,21 @@ namespace SharpCompress.Compressors.Rar.VM break; case VMCommands.VM_MUL: + { - int result = - (int) - ((GetValue(cmd.IsByteMode, Mem, op1) & - 0xFFffFFff * GetValue(cmd.IsByteMode, Mem, op2) & unchecked((int)0xFFffFFff)) & - unchecked((int)0xFFffFFff)); + int result = (int)( + ( + GetValue(cmd.IsByteMode, Mem, op1) + & 0xFFffFFff * GetValue(cmd.IsByteMode, Mem, op2) + & unchecked((int)0xFFffFFff) + ) & unchecked((int)0xFFffFFff) + ); SetValue(cmd.IsByteMode, Mem, op1, result); } break; case VMCommands.VM_DIV: + { int divider = GetValue(cmd.IsByteMode, Mem, op2); if (divider != 0) @@ -652,44 +752,60 @@ namespace SharpCompress.Compressors.Rar.VM break; case VMCommands.VM_ADC: + { int value1 = GetValue(cmd.IsByteMode, Mem, op1); int FC = (int)(flags & VMFlags.VM_FC); - int result = - (int) - (value1 & 0xFFffFFff + GetValue(cmd.IsByteMode, Mem, op2) & - 0xFFffFFff + FC & unchecked((int)0xFFffFFff)); + int result = (int)( + value1 + & 0xFFffFFff + GetValue(cmd.IsByteMode, Mem, op2) + & 0xFFffFFff + FC + & unchecked((int)0xFFffFFff) + ); if (cmd.IsByteMode) { result &= 0xff; } - flags = - (VMFlags) - ((result < value1 || result == value1 && FC != 0) - ? 1 - : 0 | (result == 0 ? (int)VMFlags.VM_FZ : (result & (int)VMFlags.VM_FS))); + flags = (VMFlags)( + (result < value1 || result == value1 && FC != 0) + ? 1 + : 0 + | ( + result == 0 + ? (int)VMFlags.VM_FZ + : (result & (int)VMFlags.VM_FS) + ) + ); SetValue(cmd.IsByteMode, Mem, op1, result); } break; case VMCommands.VM_SBB: + { int value1 = GetValue(cmd.IsByteMode, Mem, op1); int FC = (int)(flags & VMFlags.VM_FC); - int result = - (int) - (value1 & 0xFFffFFff - GetValue(cmd.IsByteMode, Mem, op2) & - 0xFFffFFff - FC & unchecked((int)0xFFffFFff)); + int result = (int)( + value1 + & 0xFFffFFff - GetValue(cmd.IsByteMode, Mem, op2) + & 0xFFffFFff - FC + & unchecked((int)0xFFffFFff) + ); if (cmd.IsByteMode) { result &= 0xff; } - flags = - (VMFlags) - ((result > value1 || result == value1 && FC != 0) - ? 1 - : 0 | (result == 0 ? (int)VMFlags.VM_FZ : (result & (int)VMFlags.VM_FS))); + flags = (VMFlags)( + (result > value1 || result == value1 && FC != 0) + ? 1 + : 0 + | ( + result == 0 + ? (int)VMFlags.VM_FZ + : (result & (int)VMFlags.VM_FS) + ) + ); SetValue(cmd.IsByteMode, Mem, op1, result); } break; @@ -785,7 +901,9 @@ namespace SharpCompress.Compressors.Rar.VM curCmd.OpCode = (VMCommands)((data >> 10) - 24); AddBits(6); } - if ((VMCmdFlags.VM_CmdFlags[(int)curCmd.OpCode] & VMCmdFlags.VMCF_BYTEMODE) != 0) + if ( + (VMCmdFlags.VM_CmdFlags[(int)curCmd.OpCode] & VMCmdFlags.VMCF_BYTEMODE) != 0 + ) { curCmd.IsByteMode = (GetBits() >> 15) == 1 ? true : false; AddBits(1); @@ -797,7 +915,9 @@ namespace SharpCompress.Compressors.Rar.VM curCmd.Op1.Type = VMOpType.VM_OPNONE; curCmd.Op2.Type = VMOpType.VM_OPNONE; - int opNum = (VMCmdFlags.VM_CmdFlags[(int)curCmd.OpCode] & VMCmdFlags.VMCF_OPMASK); + int opNum = ( + VMCmdFlags.VM_CmdFlags[(int)curCmd.OpCode] & VMCmdFlags.VMCF_OPMASK + ); // TODO >>> CurCmd->Op1.Addr=CurCmd->Op2.Addr=NULL; << 0) @@ -809,9 +929,13 @@ namespace SharpCompress.Compressors.Rar.VM } else { - if (curCmd.Op1.Type == VMOpType.VM_OPINT && - (VMCmdFlags.VM_CmdFlags[(int)curCmd.OpCode] & - (VMCmdFlags.VMCF_JUMP | VMCmdFlags.VMCF_PROC)) != 0) + if ( + curCmd.Op1.Type == VMOpType.VM_OPINT + && ( + VMCmdFlags.VM_CmdFlags[(int)curCmd.OpCode] + & (VMCmdFlags.VMCF_JUMP | VMCmdFlags.VMCF_PROC) + ) != 0 + ) { int distance = curCmd.Op1.Data; if (distance >= 256) @@ -958,7 +1082,16 @@ namespace SharpCompress.Compressors.Rar.VM for (int i = commands.IndexOf(cmd) + 1; i < commands.Count; i++) { int flags = VMCmdFlags.VM_CmdFlags[(int)commands[i].OpCode]; - if ((flags & (VMCmdFlags.VMCF_JUMP | VMCmdFlags.VMCF_PROC | VMCmdFlags.VMCF_USEFLAGS)) != 0) + if ( + ( + flags + & ( + VMCmdFlags.VMCF_JUMP + | VMCmdFlags.VMCF_PROC + | VMCmdFlags.VMCF_USEFLAGS + ) + ) != 0 + ) { flagsRequired = true; break; @@ -1039,20 +1172,13 @@ namespace SharpCompress.Compressors.Rar.VM { VMStandardFilterSignature[] stdList = { - new VMStandardFilterSignature(53, 0xad576887, - VMStandardFilters.VMSF_E8), - new VMStandardFilterSignature(57, 0x3cd7e57e, - VMStandardFilters.VMSF_E8E9), - new VMStandardFilterSignature(120, 0x3769893f, - VMStandardFilters.VMSF_ITANIUM), - new VMStandardFilterSignature(29, 0x0e06077d, - VMStandardFilters.VMSF_DELTA), - new VMStandardFilterSignature(149, 0x1c2c5dc8, - VMStandardFilters.VMSF_RGB), - new VMStandardFilterSignature(216, 0xbc85e701, - VMStandardFilters.VMSF_AUDIO), - new VMStandardFilterSignature(40, 0x46b9c560, - VMStandardFilters.VMSF_UPCASE) + new VMStandardFilterSignature(53, 0xad576887, VMStandardFilters.VMSF_E8), + new VMStandardFilterSignature(57, 0x3cd7e57e, VMStandardFilters.VMSF_E8E9), + new VMStandardFilterSignature(120, 0x3769893f, VMStandardFilters.VMSF_ITANIUM), + new VMStandardFilterSignature(29, 0x0e06077d, VMStandardFilters.VMSF_DELTA), + new VMStandardFilterSignature(149, 0x1c2c5dc8, VMStandardFilters.VMSF_RGB), + new VMStandardFilterSignature(216, 0xbc85e701, VMStandardFilters.VMSF_AUDIO), + new VMStandardFilterSignature(40, 0x46b9c560, VMStandardFilters.VMSF_UPCASE) }; uint CodeCRC = RarCRC.CheckCrc(0xffffffff, code, 0, code.Length) ^ 0xffffffff; for (int i = 0; i < stdList.Length; i++) @@ -1071,6 +1197,7 @@ namespace SharpCompress.Compressors.Rar.VM { case VMStandardFilters.VMSF_E8: case VMStandardFilters.VMSF_E8E9: + { int dataSize = R[4]; long fileOffset = R[6] & unchecked((int)0xFFffFFff); @@ -1080,8 +1207,10 @@ namespace SharpCompress.Compressors.Rar.VM break; } int fileSize = 0x1000000; - byte cmpByte2 = (byte)((filterType == VMStandardFilters.VMSF_E8E9) ? 0xe9 : 0xe8); - for (int curPos = 0; curPos < dataSize - 4;) + byte cmpByte2 = (byte)( + (filterType == VMStandardFilters.VMSF_E8E9) ? 0xe9 : 0xe8 + ); + for (int curPos = 0; curPos < dataSize - 4; ) { byte curByte = Mem[curPos++]; if (curByte == 0xe8 || curByte == cmpByte2) @@ -1123,6 +1252,7 @@ namespace SharpCompress.Compressors.Rar.VM break; case VMStandardFilters.VMSF_ITANIUM: + { int dataSize = R[4]; long fileOffset = R[6] & unchecked((int)0xFFffFFff); @@ -1150,12 +1280,24 @@ namespace SharpCompress.Compressors.Rar.VM if ((cmdMask & (1 << i)) != 0) { int startPos = i * 41 + 5; - int opType = filterItanium_GetBits(curPos, startPos + 37, 4); + int opType = filterItanium_GetBits( + curPos, + startPos + 37, + 4 + ); if (opType == 5) { - int offset = filterItanium_GetBits(curPos, startPos + 13, 20); - filterItanium_SetBits(curPos, (int)(offset - fileOffset) & 0xfffff, - startPos + 13, 20); + int offset = filterItanium_GetBits( + curPos, + startPos + 13, + 20 + ); + filterItanium_SetBits( + curPos, + (int)(offset - fileOffset) & 0xfffff, + startPos + 13, + 20 + ); } } } @@ -1168,6 +1310,7 @@ namespace SharpCompress.Compressors.Rar.VM break; case VMStandardFilters.VMSF_DELTA: + { int dataSize = R[4] & unchecked((int)0xFFffFFff); int channels = R[0] & unchecked((int)0xFFffFFff); @@ -1185,7 +1328,11 @@ namespace SharpCompress.Compressors.Rar.VM for (int curChannel = 0; curChannel < channels; curChannel++) { byte PrevByte = 0; - for (int destPos = dataSize + curChannel; destPos < border; destPos += channels) + for ( + int destPos = dataSize + curChannel; + destPos < border; + destPos += channels + ) { Mem[destPos] = (PrevByte = (byte)(PrevByte - Mem[srcPos++])); } @@ -1194,9 +1341,12 @@ namespace SharpCompress.Compressors.Rar.VM break; case VMStandardFilters.VMSF_RGB: + { // byte *SrcData=Mem,*DestData=SrcData+DataSize; - int dataSize = R[4], width = R[0] - 3, posR = R[1]; + int dataSize = R[4], + width = R[0] - 3, + posR = R[1]; int channels = 3; int srcPos = 0; int destDataPos = dataSize; @@ -1257,8 +1407,10 @@ namespace SharpCompress.Compressors.Rar.VM break; case VMStandardFilters.VMSF_AUDIO: + { - int dataSize = R[4], channels = R[0]; + int dataSize = R[4], + channels = R[0]; int srcPos = 0; int destDataPos = dataSize; @@ -1273,10 +1425,18 @@ namespace SharpCompress.Compressors.Rar.VM long prevByte = 0; long prevDelta = 0; long[] Dif = new long[7]; - int D1 = 0, D2 = 0, D3; - int K1 = 0, K2 = 0, K3 = 0; + int D1 = 0, + D2 = 0, + D3; + int K1 = 0, + K2 = 0, + K3 = 0; - for (int i = curChannel, byteCount = 0; i < dataSize; i += channels, byteCount++) + for ( + int i = curChannel, byteCount = 0; + i < dataSize; + i += channels, byteCount++ + ) { D3 = D2; D2 = (int)(prevDelta - D1); @@ -1315,7 +1475,8 @@ namespace SharpCompress.Compressors.Rar.VM if ((byteCount & 0x1f) == 0) { - long minDif = Dif[0], numMinDif = 0; + long minDif = Dif[0], + numMinDif = 0; Dif[0] = 0; for (int j = 1; j < Dif.Length; j++) { @@ -1377,8 +1538,11 @@ namespace SharpCompress.Compressors.Rar.VM break; case VMStandardFilters.VMSF_UPCASE: + { - int dataSize = R[4], srcPos = 0, destPos = dataSize; + int dataSize = R[4], + srcPos = 0, + destPos = dataSize; if (dataSize >= VM_GLOBALMEMADDR / 2) { break; diff --git a/src/SharpCompress/Compressors/Rar/VM/VMCmdFlags.cs b/src/SharpCompress/Compressors/Rar/VM/VMCmdFlags.cs index 55ae8dfe..d599a558 100644 --- a/src/SharpCompress/Compressors/Rar/VM/VMCmdFlags.cs +++ b/src/SharpCompress/Compressors/Rar/VM/VMCmdFlags.cs @@ -14,13 +14,15 @@ namespace SharpCompress.Compressors.Rar.VM public static byte[] VM_CmdFlags = { - VMCF_OP2 | VMCF_BYTEMODE, VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, + VMCF_OP2 | VMCF_BYTEMODE, + VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS, VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS, VMCF_OP1 | VMCF_BYTEMODE | VMCF_CHFLAGS, - VMCF_OP1 | VMCF_BYTEMODE | VMCF_CHFLAGS, VMCF_OP1 | VMCF_JUMP, + VMCF_OP1 | VMCF_BYTEMODE | VMCF_CHFLAGS, + VMCF_OP1 | VMCF_JUMP, VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, @@ -30,17 +32,28 @@ namespace SharpCompress.Compressors.Rar.VM VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS, VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS, VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS, - VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS, VMCF_OP1, VMCF_OP1, - VMCF_OP1 | VMCF_PROC, VMCF_OP0 | VMCF_PROC, VMCF_OP1 | VMCF_BYTEMODE, + VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS, + VMCF_OP1, + VMCF_OP1, + VMCF_OP1 | VMCF_PROC, + VMCF_OP0 | VMCF_PROC, + VMCF_OP1 | VMCF_BYTEMODE, VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, - VMCF_OP1 | VMCF_BYTEMODE | VMCF_CHFLAGS, VMCF_OP0, VMCF_OP0, - VMCF_OP0 | VMCF_USEFLAGS, VMCF_OP0 | VMCF_CHFLAGS, VMCF_OP2, VMCF_OP2, - VMCF_OP2 | VMCF_BYTEMODE, VMCF_OP2 | VMCF_BYTEMODE, + VMCF_OP1 | VMCF_BYTEMODE | VMCF_CHFLAGS, + VMCF_OP0, + VMCF_OP0, + VMCF_OP0 | VMCF_USEFLAGS, + VMCF_OP0 | VMCF_CHFLAGS, + VMCF_OP2, + VMCF_OP2, + VMCF_OP2 | VMCF_BYTEMODE, + VMCF_OP2 | VMCF_BYTEMODE, VMCF_OP2 | VMCF_BYTEMODE, VMCF_OP2 | VMCF_BYTEMODE | VMCF_USEFLAGS | VMCF_CHFLAGS, - VMCF_OP2 | VMCF_BYTEMODE | VMCF_USEFLAGS | VMCF_CHFLAGS, VMCF_OP0 + VMCF_OP2 | VMCF_BYTEMODE | VMCF_USEFLAGS | VMCF_CHFLAGS, + VMCF_OP0 }; } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/Rar/VM/VMCommands.cs b/src/SharpCompress/Compressors/Rar/VM/VMCommands.cs index 5164c4c5..46fde3f7 100644 --- a/src/SharpCompress/Compressors/Rar/VM/VMCommands.cs +++ b/src/SharpCompress/Compressors/Rar/VM/VMCommands.cs @@ -10,48 +10,42 @@ namespace SharpCompress.Compressors.Rar.VM VM_JNZ = 5, VM_INC = 6, - VM_DEC = - 7, + VM_DEC = 7, VM_JMP = 8, VM_XOR = 9, VM_AND = 10, VM_OR = 11, VM_TEST = 12, - VM_JS = - 13, + VM_JS = 13, VM_JNS = 14, VM_JB = 15, VM_JBE = 16, VM_JA = 17, VM_JAE = 18, - VM_PUSH = - 19, + VM_PUSH = 19, VM_POP = 20, VM_CALL = 21, VM_RET = 22, VM_NOT = 23, VM_SHL = 24, - VM_SHR = - 25, + VM_SHR = 25, VM_SAR = 26, VM_NEG = 27, VM_PUSHA = 28, VM_POPA = 29, VM_PUSHF = 30, - VM_POPF = - 31, + VM_POPF = 31, VM_MOVZX = 32, VM_MOVSX = 33, VM_XCHG = 34, VM_MUL = 35, VM_DIV = 36, - VM_ADC = - 37, + VM_ADC = 37, VM_SBB = 38, VM_PRINT = 39, @@ -67,12 +61,11 @@ namespace SharpCompress.Compressors.Rar.VM VM_INCB = 48, VM_INCD = 49, - VM_DECB = - 50, + VM_DECB = 50, VM_DECD = 51, VM_NEGB = 52, VM_NEGD = 53, VM_STANDARD = 54 } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/Rar/VM/VMFlags.cs b/src/SharpCompress/Compressors/Rar/VM/VMFlags.cs index f0c8fd72..d8b23ba8 100644 --- a/src/SharpCompress/Compressors/Rar/VM/VMFlags.cs +++ b/src/SharpCompress/Compressors/Rar/VM/VMFlags.cs @@ -7,4 +7,4 @@ namespace SharpCompress.Compressors.Rar.VM VM_FZ = 2, VM_FS = 80000000 } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/Rar/VM/VMOpType.cs b/src/SharpCompress/Compressors/Rar/VM/VMOpType.cs index 9ea99d1a..8c72eb74 100644 --- a/src/SharpCompress/Compressors/Rar/VM/VMOpType.cs +++ b/src/SharpCompress/Compressors/Rar/VM/VMOpType.cs @@ -7,4 +7,4 @@ namespace SharpCompress.Compressors.Rar.VM VM_OPREGMEM = 2, VM_OPNONE = 3 } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/Rar/VM/VMPreparedCommand.cs b/src/SharpCompress/Compressors/Rar/VM/VMPreparedCommand.cs index fc3238b5..69a459ca 100644 --- a/src/SharpCompress/Compressors/Rar/VM/VMPreparedCommand.cs +++ b/src/SharpCompress/Compressors/Rar/VM/VMPreparedCommand.cs @@ -14,4 +14,4 @@ namespace SharpCompress.Compressors.Rar.VM internal VMPreparedOperand Op2 { get; } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/Rar/VM/VMPreparedOperand.cs b/src/SharpCompress/Compressors/Rar/VM/VMPreparedOperand.cs index b8cb10d9..2f20f306 100644 --- a/src/SharpCompress/Compressors/Rar/VM/VMPreparedOperand.cs +++ b/src/SharpCompress/Compressors/Rar/VM/VMPreparedOperand.cs @@ -7,4 +7,4 @@ namespace SharpCompress.Compressors.Rar.VM internal int Base { get; set; } internal int Offset { get; set; } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/Rar/VM/VMPreparedProgram.cs b/src/SharpCompress/Compressors/Rar/VM/VMPreparedProgram.cs index 94da8a76..de9e7054 100644 --- a/src/SharpCompress/Compressors/Rar/VM/VMPreparedProgram.cs +++ b/src/SharpCompress/Compressors/Rar/VM/VMPreparedProgram.cs @@ -18,4 +18,4 @@ namespace SharpCompress.Compressors.Rar.VM internal int FilteredDataOffset { get; set; } internal int FilteredDataSize { get; set; } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/Rar/VM/VMStandardFilterSignature.cs b/src/SharpCompress/Compressors/Rar/VM/VMStandardFilterSignature.cs index a5812ed0..cc55f167 100644 --- a/src/SharpCompress/Compressors/Rar/VM/VMStandardFilterSignature.cs +++ b/src/SharpCompress/Compressors/Rar/VM/VMStandardFilterSignature.cs @@ -15,4 +15,4 @@ namespace SharpCompress.Compressors.Rar.VM internal VMStandardFilters Type { get; } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/Rar/VM/VMStandardFilters.cs b/src/SharpCompress/Compressors/Rar/VM/VMStandardFilters.cs index 07f74348..5f7c18ea 100644 --- a/src/SharpCompress/Compressors/Rar/VM/VMStandardFilters.cs +++ b/src/SharpCompress/Compressors/Rar/VM/VMStandardFilters.cs @@ -11,4 +11,4 @@ namespace SharpCompress.Compressors.Rar.VM VMSF_DELTA = 6, VMSF_UPCASE = 7 } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/Xz/BinaryUtils.cs b/src/SharpCompress/Compressors/Xz/BinaryUtils.cs index 05f66c46..a0a92171 100644 --- a/src/SharpCompress/Compressors/Xz/BinaryUtils.cs +++ b/src/SharpCompress/Compressors/Xz/BinaryUtils.cs @@ -17,6 +17,7 @@ namespace SharpCompress.Compressors.Xz { return unchecked((uint)ReadLittleEndianInt32(reader)); } + public static int ReadLittleEndianInt32(this Stream stream) { Span bytes = stackalloc byte[4]; diff --git a/src/SharpCompress/Compressors/Xz/CheckType.cs b/src/SharpCompress/Compressors/Xz/CheckType.cs index 19c8019a..4176ac4b 100644 --- a/src/SharpCompress/Compressors/Xz/CheckType.cs +++ b/src/SharpCompress/Compressors/Xz/CheckType.cs @@ -7,4 +7,4 @@ namespace SharpCompress.Compressors.Xz CRC64 = 0x04, SHA256 = 0x0A } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/Xz/Crc64.cs b/src/SharpCompress/Compressors/Xz/Crc64.cs index 1bea4a23..6ea99940 100644 --- a/src/SharpCompress/Compressors/Xz/Crc64.cs +++ b/src/SharpCompress/Compressors/Xz/Crc64.cs @@ -64,5 +64,4 @@ namespace SharpCompress.Compressors.Xz return createTable; } } - } diff --git a/src/SharpCompress/Compressors/Xz/Filters/ArmFilter.cs b/src/SharpCompress/Compressors/Xz/Filters/ArmFilter.cs index dac51743..cefc1137 100644 --- a/src/SharpCompress/Compressors/Xz/Filters/ArmFilter.cs +++ b/src/SharpCompress/Compressors/Xz/Filters/ArmFilter.cs @@ -47,10 +47,7 @@ namespace SharpCompress.Compressors.Xz.Filters } } - public override void ValidateFilter() - { - - } + public override void ValidateFilter() { } public override int Read(byte[] buffer, int offset, int count) { diff --git a/src/SharpCompress/Compressors/Xz/Filters/ArmThumbFilter.cs b/src/SharpCompress/Compressors/Xz/Filters/ArmThumbFilter.cs index 2d6a87cd..3a70f6f7 100644 --- a/src/SharpCompress/Compressors/Xz/Filters/ArmThumbFilter.cs +++ b/src/SharpCompress/Compressors/Xz/Filters/ArmThumbFilter.cs @@ -28,7 +28,6 @@ namespace SharpCompress.Compressors.Xz.Filters public override void Init(byte[] properties) { - if (properties.Length != 0 && properties.Length != 4) { throw new InvalidDataException("ARM Thumb properties unexpected length"); @@ -48,10 +47,7 @@ namespace SharpCompress.Compressors.Xz.Filters } } - public override void ValidateFilter() - { - - } + public override void ValidateFilter() { } public override int Read(byte[] buffer, int offset, int count) { diff --git a/src/SharpCompress/Compressors/Xz/Filters/BlockFilter.cs b/src/SharpCompress/Compressors/Xz/Filters/BlockFilter.cs index 3cfdc6d6..79eddaaa 100644 --- a/src/SharpCompress/Compressors/Xz/Filters/BlockFilter.cs +++ b/src/SharpCompress/Compressors/Xz/Filters/BlockFilter.cs @@ -19,15 +19,18 @@ namespace SharpCompress.Compressors.Xz.Filters LZMA2 = 0x21 } - private static readonly Dictionary FilterMap = new Dictionary - { - {FilterTypes.ARCH_x86_FILTER, typeof(X86Filter) }, - {FilterTypes.ARCH_PowerPC_FILTER, typeof(PowerPCFilter) }, - {FilterTypes.ARCH_IA64_FILTER, typeof(IA64Filter) }, - {FilterTypes.ARCH_ARM_FILTER, typeof(ArmFilter) }, - {FilterTypes.ARCH_ARMTHUMB_FILTER, typeof(ArmThumbFilter) }, - {FilterTypes.ARCH_SPARC_FILTER, typeof(SparcFilter) }, - {FilterTypes.LZMA2, typeof(Lzma2Filter) } + private static readonly Dictionary FilterMap = new Dictionary< + FilterTypes, + Type + > + { + { FilterTypes.ARCH_x86_FILTER, typeof(X86Filter) }, + { FilterTypes.ARCH_PowerPC_FILTER, typeof(PowerPCFilter) }, + { FilterTypes.ARCH_IA64_FILTER, typeof(IA64Filter) }, + { FilterTypes.ARCH_ARM_FILTER, typeof(ArmFilter) }, + { FilterTypes.ARCH_ARMTHUMB_FILTER, typeof(ArmThumbFilter) }, + { FilterTypes.ARCH_SPARC_FILTER, typeof(SparcFilter) }, + { FilterTypes.LZMA2, typeof(Lzma2Filter) } }; public abstract bool AllowAsLast { get; } @@ -42,7 +45,9 @@ namespace SharpCompress.Compressors.Xz.Filters var filterType = (FilterTypes)reader.ReadXZInteger(); if (!FilterMap.ContainsKey(filterType)) { - throw new NotImplementedException($"Filter {filterType} has not yet been implemented"); + throw new NotImplementedException( + $"Filter {filterType} has not yet been implemented" + ); } var filter = (BlockFilter)Activator.CreateInstance(FilterMap[filterType])!; diff --git a/src/SharpCompress/Compressors/Xz/Filters/IA64Filter.cs b/src/SharpCompress/Compressors/Xz/Filters/IA64Filter.cs index 5fb8b7d1..7c78ef26 100644 --- a/src/SharpCompress/Compressors/Xz/Filters/IA64Filter.cs +++ b/src/SharpCompress/Compressors/Xz/Filters/IA64Filter.cs @@ -47,10 +47,7 @@ namespace SharpCompress.Compressors.Xz.Filters } } - public override void ValidateFilter() - { - - } + public override void ValidateFilter() { } public override int Read(byte[] buffer, int offset, int count) { @@ -59,6 +56,7 @@ namespace SharpCompress.Compressors.Xz.Filters _ip += (UInt32)bytesRead; return bytesRead; } + public override void SetBaseStream(Stream stream) { BaseStream = stream; diff --git a/src/SharpCompress/Compressors/Xz/Filters/Lzma2Filter.cs b/src/SharpCompress/Compressors/Xz/Filters/Lzma2Filter.cs index 7e35187d..be1f9ff4 100644 --- a/src/SharpCompress/Compressors/Xz/Filters/Lzma2Filter.cs +++ b/src/SharpCompress/Compressors/Xz/Filters/Lzma2Filter.cs @@ -46,9 +46,7 @@ namespace SharpCompress.Compressors.Xz.Filters } } - public override void ValidateFilter() - { - } + public override void ValidateFilter() { } public override void SetBaseStream(Stream stream) { diff --git a/src/SharpCompress/Compressors/Xz/Filters/PowerPCFilter.cs b/src/SharpCompress/Compressors/Xz/Filters/PowerPCFilter.cs index 3dfaed6d..b9566c35 100644 --- a/src/SharpCompress/Compressors/Xz/Filters/PowerPCFilter.cs +++ b/src/SharpCompress/Compressors/Xz/Filters/PowerPCFilter.cs @@ -28,7 +28,6 @@ namespace SharpCompress.Compressors.Xz.Filters public override void Init(byte[] properties) { - if (properties.Length != 0 && properties.Length != 4) { throw new InvalidDataException("PPC properties unexpected length"); diff --git a/src/SharpCompress/Compressors/Xz/Filters/SparcFilter.cs b/src/SharpCompress/Compressors/Xz/Filters/SparcFilter.cs index 4f5e925d..1b7d4edd 100644 --- a/src/SharpCompress/Compressors/Xz/Filters/SparcFilter.cs +++ b/src/SharpCompress/Compressors/Xz/Filters/SparcFilter.cs @@ -26,8 +26,8 @@ namespace SharpCompress.Compressors.Xz.Filters //private UInt32 _offset = 0; - public override void Init(byte[] properties) { - + public override void Init(byte[] properties) + { if (properties.Length != 0 && properties.Length != 4) { throw new InvalidDataException("SPARC properties unexpected length"); @@ -47,18 +47,18 @@ namespace SharpCompress.Compressors.Xz.Filters } } - public override void ValidateFilter() { + public override void ValidateFilter() { } - } - - public override int Read(byte[] buffer, int offset, int count){ + public override int Read(byte[] buffer, int offset, int count) + { int bytesRead = BaseStream.Read(buffer, offset, count); BranchExecFilter.SPARCConverter(buffer, _ip); _ip += (UInt32)bytesRead; return bytesRead; } - public override void SetBaseStream(Stream stream) { + public override void SetBaseStream(Stream stream) + { BaseStream = stream; } } diff --git a/src/SharpCompress/Compressors/Xz/Filters/X86Filter.cs b/src/SharpCompress/Compressors/Xz/Filters/X86Filter.cs index f5fcf924..46d5837a 100644 --- a/src/SharpCompress/Compressors/Xz/Filters/X86Filter.cs +++ b/src/SharpCompress/Compressors/Xz/Filters/X86Filter.cs @@ -49,10 +49,7 @@ namespace SharpCompress.Compressors.Xz.Filters } } - public override void ValidateFilter() - { - - } + public override void ValidateFilter() { } public override int Read(byte[] buffer, int offset, int count) { diff --git a/src/SharpCompress/Compressors/Xz/XZBlock.cs b/src/SharpCompress/Compressors/Xz/XZBlock.cs index dc3a010d..38409ecf 100644 --- a/src/SharpCompress/Compressors/Xz/XZBlock.cs +++ b/src/SharpCompress/Compressors/Xz/XZBlock.cs @@ -27,8 +27,7 @@ namespace SharpCompress.Compressors.Xz private bool _crcChecked; private ulong _bytesRead; - public XZBlock(Stream stream, CheckType checkType, int checkSize) - : base(stream) + public XZBlock(Stream stream, CheckType checkType, int checkSize) : base(stream) { _checkType = checkType; _checkSize = checkSize; @@ -159,7 +158,9 @@ namespace SharpCompress.Compressors.Xz if (reserved != 0) { - throw new InvalidDataException("Reserved bytes used, perhaps an unknown XZ implementation"); + throw new InvalidDataException( + "Reserved bytes used, perhaps an unknown XZ implementation" + ); } bool compressedSizePresent = (blockFlags & 0x40) != 0; @@ -182,8 +183,10 @@ namespace SharpCompress.Compressors.Xz for (int i = 0; i < _numFilters; i++) { var filter = BlockFilter.Read(reader); - if ((i + 1 == _numFilters && !filter.AllowAsLast) - || (i + 1 < _numFilters && !filter.AllowAsNonLast)) + if ( + (i + 1 == _numFilters && !filter.AllowAsLast) + || (i + 1 < _numFilters && !filter.AllowAsNonLast) + ) { throw new InvalidDataException("Block Filters in bad order"); } @@ -198,11 +201,13 @@ namespace SharpCompress.Compressors.Xz } if (nonLastSizeChangers > 2) { - throw new InvalidDataException("More than two non-last block filters cannot change stream size"); + throw new InvalidDataException( + "More than two non-last block filters cannot change stream size" + ); } - int blockHeaderPaddingSize = BlockHeaderSize - - (4 + (int)(reader.BaseStream.Position - baseStreamOffset)); + int blockHeaderPaddingSize = + BlockHeaderSize - (4 + (int)(reader.BaseStream.Position - baseStreamOffset)); byte[] blockHeaderPadding = reader.ReadBytes(blockHeaderPaddingSize); if (!blockHeaderPadding.All(b => b == 0)) { diff --git a/src/SharpCompress/Compressors/Xz/XZFooter.cs b/src/SharpCompress/Compressors/Xz/XZFooter.cs index 52f72619..40850f31 100644 --- a/src/SharpCompress/Compressors/Xz/XZFooter.cs +++ b/src/SharpCompress/Compressors/Xz/XZFooter.cs @@ -22,7 +22,9 @@ namespace SharpCompress.Compressors.Xz public static XZFooter FromStream(Stream stream) { - var footer = new XZFooter(new BinaryReader(NonDisposingStream.Create(stream), Encoding.UTF8)); + var footer = new XZFooter( + new BinaryReader(NonDisposingStream.Create(stream), Encoding.UTF8) + ); footer.Process(); return footer; } diff --git a/src/SharpCompress/Compressors/Xz/XZHeader.cs b/src/SharpCompress/Compressors/Xz/XZHeader.cs index 8934e135..5968cc62 100644 --- a/src/SharpCompress/Compressors/Xz/XZHeader.cs +++ b/src/SharpCompress/Compressors/Xz/XZHeader.cs @@ -21,7 +21,9 @@ namespace SharpCompress.Compressors.Xz public static XZHeader FromStream(Stream stream) { - var header = new XZHeader(new BinaryReader(NonDisposingStream.Create(stream), Encoding.UTF8)); + var header = new XZHeader( + new BinaryReader(NonDisposingStream.Create(stream), Encoding.UTF8) + ); header.Process(); return header; } diff --git a/src/SharpCompress/Compressors/Xz/XZIndex.cs b/src/SharpCompress/Compressors/Xz/XZIndex.cs index 997d53c3..7ad364ce 100644 --- a/src/SharpCompress/Compressors/Xz/XZIndex.cs +++ b/src/SharpCompress/Compressors/Xz/XZIndex.cs @@ -30,7 +30,10 @@ namespace SharpCompress.Compressors.Xz public static XZIndex FromStream(Stream stream, bool indexMarkerAlreadyVerified) { - var index = new XZIndex(new BinaryReader(NonDisposingStream.Create(stream), Encoding.UTF8), indexMarkerAlreadyVerified); + var index = new XZIndex( + new BinaryReader(NonDisposingStream.Create(stream), Encoding.UTF8), + indexMarkerAlreadyVerified + ); index.Process(); return index; } diff --git a/src/SharpCompress/Compressors/Xz/XZIndexMarkerReachedException.cs b/src/SharpCompress/Compressors/Xz/XZIndexMarkerReachedException.cs index 387a2a1e..d5be9a82 100644 --- a/src/SharpCompress/Compressors/Xz/XZIndexMarkerReachedException.cs +++ b/src/SharpCompress/Compressors/Xz/XZIndexMarkerReachedException.cs @@ -2,7 +2,5 @@ namespace SharpCompress.Compressors.Xz { - public class XZIndexMarkerReachedException : Exception - { - } + public class XZIndexMarkerReachedException : Exception { } } diff --git a/src/SharpCompress/Compressors/Xz/XZStream.cs b/src/SharpCompress/Compressors/Xz/XZStream.cs index 49b5e801..41d968f5 100644 --- a/src/SharpCompress/Compressors/Xz/XZStream.cs +++ b/src/SharpCompress/Compressors/Xz/XZStream.cs @@ -33,9 +33,12 @@ namespace SharpCompress.Compressors.Xz case CheckType.SHA256: throw new NotImplementedException(); default: - throw new NotSupportedException("Check Type unknown to this version of decoder."); + throw new NotSupportedException( + "Check Type unknown to this version of decoder." + ); } } + public XZHeader Header { get; private set; } public XZIndex Index { get; private set; } public XZFooter Footer { get; private set; } @@ -44,9 +47,7 @@ namespace SharpCompress.Compressors.Xz private bool _endOfStream; - public XZStream(Stream stream) : base(stream) - { - } + public XZStream(Stream stream) : base(stream) { } public override int Read(byte[] buffer, int offset, int count) { diff --git a/src/SharpCompress/Crypto/Crc32Stream.cs b/src/SharpCompress/Crypto/Crc32Stream.cs index 635c4677..d3349bf5 100644 --- a/src/SharpCompress/Crypto/Crc32Stream.cs +++ b/src/SharpCompress/Crypto/Crc32Stream.cs @@ -18,10 +18,7 @@ namespace SharpCompress.Crypto private readonly Stream stream; - public Crc32Stream(Stream stream) - : this(stream, DefaultPolynomial, DefaultSeed) - { - } + public Crc32Stream(Stream stream) : this(stream, DefaultPolynomial, DefaultSeed) { } public Crc32Stream(Stream stream, uint polynomial, uint seed) { @@ -37,9 +34,11 @@ namespace SharpCompress.Crypto stream.Flush(); } - public override int Read(byte[] buffer, int offset, int count) => throw new NotSupportedException(); + public override int Read(byte[] buffer, int offset, int count) => + throw new NotSupportedException(); - public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException(); + public override long Seek(long offset, SeekOrigin origin) => + throw new NotSupportedException(); public override void SetLength(long value) => throw new NotSupportedException(); @@ -69,7 +68,11 @@ namespace SharpCompress.Crypto public override bool CanSeek => false; public override bool CanWrite => stream.CanWrite; public override long Length => throw new NotSupportedException(); - public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); } + public override long Position + { + get => throw new NotSupportedException(); + set => throw new NotSupportedException(); + } public uint Crc => ~hash; diff --git a/src/SharpCompress/Crypto/CryptoException.cs b/src/SharpCompress/Crypto/CryptoException.cs index 6e8b9f14..f67e6a01 100644 --- a/src/SharpCompress/Crypto/CryptoException.cs +++ b/src/SharpCompress/Crypto/CryptoException.cs @@ -2,24 +2,12 @@ namespace SharpCompress.Crypto { - public class CryptoException - : Exception + public class CryptoException : Exception { - public CryptoException() - { - } + public CryptoException() { } - public CryptoException( - string message) - : base(message) - { - } + public CryptoException(string message) : base(message) { } - public CryptoException( - string message, - Exception exception) - : base(message, exception) - { - } + public CryptoException(string message, Exception exception) : base(message, exception) { } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Crypto/DataLengthException.cs b/src/SharpCompress/Crypto/DataLengthException.cs index b82a9e9c..d1069755 100644 --- a/src/SharpCompress/Crypto/DataLengthException.cs +++ b/src/SharpCompress/Crypto/DataLengthException.cs @@ -2,16 +2,13 @@ namespace SharpCompress.Crypto { - public class DataLengthException - : CryptoException + public class DataLengthException : CryptoException { /** * base constructor. */ - public DataLengthException() - { - } + public DataLengthException() { } /** * create a DataLengthException with the given message. @@ -19,17 +16,9 @@ namespace SharpCompress.Crypto * @param message the message to be carried with the exception. */ - public DataLengthException( - string message) - : base(message) - { - } + public DataLengthException(string message) : base(message) { } - public DataLengthException( - string message, - Exception exception) - : base(message, exception) - { - } + public DataLengthException(string message, Exception exception) : base(message, exception) + { } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Crypto/IBlockCipher.cs b/src/SharpCompress/Crypto/IBlockCipher.cs index 61a37c46..eed5fc48 100644 --- a/src/SharpCompress/Crypto/IBlockCipher.cs +++ b/src/SharpCompress/Crypto/IBlockCipher.cs @@ -31,4 +31,4 @@ namespace SharpCompress.Crypto /// void Reset(); } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Crypto/ICipherParameters.cs b/src/SharpCompress/Crypto/ICipherParameters.cs index d6e4af8b..dbccaa77 100644 --- a/src/SharpCompress/Crypto/ICipherParameters.cs +++ b/src/SharpCompress/Crypto/ICipherParameters.cs @@ -1,6 +1,4 @@ namespace SharpCompress.Crypto { - public interface ICipherParameters - { - } -} \ No newline at end of file + public interface ICipherParameters { } +} diff --git a/src/SharpCompress/Crypto/KeyParameter.cs b/src/SharpCompress/Crypto/KeyParameter.cs index 7bf2dad8..3fb36f46 100644 --- a/src/SharpCompress/Crypto/KeyParameter.cs +++ b/src/SharpCompress/Crypto/KeyParameter.cs @@ -2,13 +2,11 @@ namespace SharpCompress.Crypto { - public class KeyParameter - : ICipherParameters + public class KeyParameter : ICipherParameters { private readonly byte[] key; - public KeyParameter( - byte[] key) + public KeyParameter(byte[] key) { if (key is null) { @@ -18,10 +16,7 @@ namespace SharpCompress.Crypto this.key = (byte[])key.Clone(); } - public KeyParameter( - byte[] key, - int keyOff, - int keyLen) + public KeyParameter(byte[] key, int keyOff, int keyLen) { if (key is null) { @@ -45,4 +40,4 @@ namespace SharpCompress.Crypto return (byte[])key.Clone(); } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Crypto/RijndaelEngine.cs b/src/SharpCompress/Crypto/RijndaelEngine.cs index b1adaa76..6b91306b 100644 --- a/src/SharpCompress/Crypto/RijndaelEngine.cs +++ b/src/SharpCompress/Crypto/RijndaelEngine.cs @@ -2,147 +2,1362 @@ namespace SharpCompress.Crypto { - public sealed class RijndaelEngine - : IBlockCipher + public sealed class RijndaelEngine : IBlockCipher { private const int MAXROUNDS = 14; private const int MAXKC = (256 / 4); - private static ReadOnlySpan Logtable => new byte[] - { - 0, 0, 25, 1, 50, 2, 26, 198, - 75, 199, 27, 104, 51, 238, 223, 3, - 100, 4, 224, 14, 52, 141, 129, 239, - 76, 113, 8, 200, 248, 105, 28, 193, - 125, 194, 29, 181, 249, 185, 39, 106, - 77, 228, 166, 114, 154, 201, 9, 120, - 101, 47, 138, 5, 33, 15, 225, 36, - 18, 240, 130, 69, 53, 147, 218, 142, - 150, 143, 219, 189, 54, 208, 206, 148, - 19, 92, 210, 241, 64, 70, 131, 56, - 102, 221, 253, 48, 191, 6, 139, 98, - 179, 37, 226, 152, 34, 136, 145, 16, - 126, 110, 72, 195, 163, 182, 30, 66, - 58, 107, 40, 84, 250, 133, 61, 186, - 43, 121, 10, 21, 155, 159, 94, 202, - 78, 212, 172, 229, 243, 115, 167, 87, - 175, 88, 168, 80, 244, 234, 214, 116, - 79, 174, 233, 213, 231, 230, 173, 232, - 44, 215, 117, 122, 235, 22, 11, 245, - 89, 203, 95, 176, 156, 169, 81, 160, - 127, 12, 246, 111, 23, 196, 73, 236, - 216, 67, 31, 45, 164, 118, 123, 183, - 204, 187, 62, 90, 251, 96, 177, 134, - 59, 82, 161, 108, 170, 85, 41, 157, - 151, 178, 135, 144, 97, 190, 220, 252, - 188, 149, 207, 205, 55, 63, 91, 209, - 83, 57, 132, 60, 65, 162, 109, 71, - 20, 42, 158, 93, 86, 242, 211, 171, - 68, 17, 146, 217, 35, 32, 46, 137, - 180, 124, 184, 38, 119, 153, 227, 165, - 103, 74, 237, 222, 197, 49, 254, 24, - 13, 99, 140, 128, 192, 247, 112, 7 - }; + private static ReadOnlySpan Logtable => + new byte[] + { + 0, + 0, + 25, + 1, + 50, + 2, + 26, + 198, + 75, + 199, + 27, + 104, + 51, + 238, + 223, + 3, + 100, + 4, + 224, + 14, + 52, + 141, + 129, + 239, + 76, + 113, + 8, + 200, + 248, + 105, + 28, + 193, + 125, + 194, + 29, + 181, + 249, + 185, + 39, + 106, + 77, + 228, + 166, + 114, + 154, + 201, + 9, + 120, + 101, + 47, + 138, + 5, + 33, + 15, + 225, + 36, + 18, + 240, + 130, + 69, + 53, + 147, + 218, + 142, + 150, + 143, + 219, + 189, + 54, + 208, + 206, + 148, + 19, + 92, + 210, + 241, + 64, + 70, + 131, + 56, + 102, + 221, + 253, + 48, + 191, + 6, + 139, + 98, + 179, + 37, + 226, + 152, + 34, + 136, + 145, + 16, + 126, + 110, + 72, + 195, + 163, + 182, + 30, + 66, + 58, + 107, + 40, + 84, + 250, + 133, + 61, + 186, + 43, + 121, + 10, + 21, + 155, + 159, + 94, + 202, + 78, + 212, + 172, + 229, + 243, + 115, + 167, + 87, + 175, + 88, + 168, + 80, + 244, + 234, + 214, + 116, + 79, + 174, + 233, + 213, + 231, + 230, + 173, + 232, + 44, + 215, + 117, + 122, + 235, + 22, + 11, + 245, + 89, + 203, + 95, + 176, + 156, + 169, + 81, + 160, + 127, + 12, + 246, + 111, + 23, + 196, + 73, + 236, + 216, + 67, + 31, + 45, + 164, + 118, + 123, + 183, + 204, + 187, + 62, + 90, + 251, + 96, + 177, + 134, + 59, + 82, + 161, + 108, + 170, + 85, + 41, + 157, + 151, + 178, + 135, + 144, + 97, + 190, + 220, + 252, + 188, + 149, + 207, + 205, + 55, + 63, + 91, + 209, + 83, + 57, + 132, + 60, + 65, + 162, + 109, + 71, + 20, + 42, + 158, + 93, + 86, + 242, + 211, + 171, + 68, + 17, + 146, + 217, + 35, + 32, + 46, + 137, + 180, + 124, + 184, + 38, + 119, + 153, + 227, + 165, + 103, + 74, + 237, + 222, + 197, + 49, + 254, + 24, + 13, + 99, + 140, + 128, + 192, + 247, + 112, + 7 + }; - private static ReadOnlySpan Alogtable => new byte[] - { - 0, 3, 5, 15, 17, 51, 85, 255, 26, 46, 114, 150, 161, 248, 19, 53, - 95, 225, 56, 72, 216, 115, 149, 164, 247, 2, 6, 10, 30, 34, 102, 170, - 229, 52, 92, 228, 55, 89, 235, 38, 106, 190, 217, 112, 144, 171, 230, 49, - 83, 245, 4, 12, 20, 60, 68, 204, 79, 209, 104, 184, 211, 110, 178, 205, - 76, 212, 103, 169, 224, 59, 77, 215, 98, 166, 241, 8, 24, 40, 120, 136, - 131, 158, 185, 208, 107, 189, 220, 127, 129, 152, 179, 206, 73, 219, 118, 154, - 181, 196, 87, 249, 16, 48, 80, 240, 11, 29, 39, 105, 187, 214, 97, 163, - 254, 25, 43, 125, 135, 146, 173, 236, 47, 113, 147, 174, 233, 32, 96, 160, - 251, 22, 58, 78, 210, 109, 183, 194, 93, 231, 50, 86, 250, 21, 63, 65, - 195, 94, 226, 61, 71, 201, 64, 192, 91, 237, 44, 116, 156, 191, 218, 117, - 159, 186, 213, 100, 172, 239, 42, 126, 130, 157, 188, 223, 122, 142, 137, 128, - 155, 182, 193, 88, 232, 35, 101, 175, 234, 37, 111, 177, 200, 67, 197, 84, - 252, 31, 33, 99, 165, 244, 7, 9, 27, 45, 119, 153, 176, 203, 70, 202, - 69, 207, 74, 222, 121, 139, 134, 145, 168, 227, 62, 66, 198, 81, 243, 14, - 18, 54, 90, 238, 41, 123, 141, 140, 143, 138, 133, 148, 167, 242, 13, 23, - 57, 75, 221, 124, 132, 151, 162, 253, 28, 36, 108, 180, 199, 82, 246, 1, - 3, 5, 15, 17, 51, 85, 255, 26, 46, 114, 150, 161, 248, 19, 53, - 95, 225, 56, 72, 216, 115, 149, 164, 247, 2, 6, 10, 30, 34, 102, 170, - 229, 52, 92, 228, 55, 89, 235, 38, 106, 190, 217, 112, 144, 171, 230, 49, - 83, 245, 4, 12, 20, 60, 68, 204, 79, 209, 104, 184, 211, 110, 178, 205, - 76, 212, 103, 169, 224, 59, 77, 215, 98, 166, 241, 8, 24, 40, 120, 136, - 131, 158, 185, 208, 107, 189, 220, 127, 129, 152, 179, 206, 73, 219, 118, 154, - 181, 196, 87, 249, 16, 48, 80, 240, 11, 29, 39, 105, 187, 214, 97, 163, - 254, 25, 43, 125, 135, 146, 173, 236, 47, 113, 147, 174, 233, 32, 96, 160, - 251, 22, 58, 78, 210, 109, 183, 194, 93, 231, 50, 86, 250, 21, 63, 65, - 195, 94, 226, 61, 71, 201, 64, 192, 91, 237, 44, 116, 156, 191, 218, 117, - 159, 186, 213, 100, 172, 239, 42, 126, 130, 157, 188, 223, 122, 142, 137, 128, - 155, 182, 193, 88, 232, 35, 101, 175, 234, 37, 111, 177, 200, 67, 197, 84, - 252, 31, 33, 99, 165, 244, 7, 9, 27, 45, 119, 153, 176, 203, 70, 202, - 69, 207, 74, 222, 121, 139, 134, 145, 168, 227, 62, 66, 198, 81, 243, 14, - 18, 54, 90, 238, 41, 123, 141, 140, 143, 138, 133, 148, 167, 242, 13, 23, - 57, 75, 221, 124, 132, 151, 162, 253, 28, 36, 108, 180, 199, 82, 246, 1 - }; + private static ReadOnlySpan Alogtable => + new byte[] + { + 0, + 3, + 5, + 15, + 17, + 51, + 85, + 255, + 26, + 46, + 114, + 150, + 161, + 248, + 19, + 53, + 95, + 225, + 56, + 72, + 216, + 115, + 149, + 164, + 247, + 2, + 6, + 10, + 30, + 34, + 102, + 170, + 229, + 52, + 92, + 228, + 55, + 89, + 235, + 38, + 106, + 190, + 217, + 112, + 144, + 171, + 230, + 49, + 83, + 245, + 4, + 12, + 20, + 60, + 68, + 204, + 79, + 209, + 104, + 184, + 211, + 110, + 178, + 205, + 76, + 212, + 103, + 169, + 224, + 59, + 77, + 215, + 98, + 166, + 241, + 8, + 24, + 40, + 120, + 136, + 131, + 158, + 185, + 208, + 107, + 189, + 220, + 127, + 129, + 152, + 179, + 206, + 73, + 219, + 118, + 154, + 181, + 196, + 87, + 249, + 16, + 48, + 80, + 240, + 11, + 29, + 39, + 105, + 187, + 214, + 97, + 163, + 254, + 25, + 43, + 125, + 135, + 146, + 173, + 236, + 47, + 113, + 147, + 174, + 233, + 32, + 96, + 160, + 251, + 22, + 58, + 78, + 210, + 109, + 183, + 194, + 93, + 231, + 50, + 86, + 250, + 21, + 63, + 65, + 195, + 94, + 226, + 61, + 71, + 201, + 64, + 192, + 91, + 237, + 44, + 116, + 156, + 191, + 218, + 117, + 159, + 186, + 213, + 100, + 172, + 239, + 42, + 126, + 130, + 157, + 188, + 223, + 122, + 142, + 137, + 128, + 155, + 182, + 193, + 88, + 232, + 35, + 101, + 175, + 234, + 37, + 111, + 177, + 200, + 67, + 197, + 84, + 252, + 31, + 33, + 99, + 165, + 244, + 7, + 9, + 27, + 45, + 119, + 153, + 176, + 203, + 70, + 202, + 69, + 207, + 74, + 222, + 121, + 139, + 134, + 145, + 168, + 227, + 62, + 66, + 198, + 81, + 243, + 14, + 18, + 54, + 90, + 238, + 41, + 123, + 141, + 140, + 143, + 138, + 133, + 148, + 167, + 242, + 13, + 23, + 57, + 75, + 221, + 124, + 132, + 151, + 162, + 253, + 28, + 36, + 108, + 180, + 199, + 82, + 246, + 1, + 3, + 5, + 15, + 17, + 51, + 85, + 255, + 26, + 46, + 114, + 150, + 161, + 248, + 19, + 53, + 95, + 225, + 56, + 72, + 216, + 115, + 149, + 164, + 247, + 2, + 6, + 10, + 30, + 34, + 102, + 170, + 229, + 52, + 92, + 228, + 55, + 89, + 235, + 38, + 106, + 190, + 217, + 112, + 144, + 171, + 230, + 49, + 83, + 245, + 4, + 12, + 20, + 60, + 68, + 204, + 79, + 209, + 104, + 184, + 211, + 110, + 178, + 205, + 76, + 212, + 103, + 169, + 224, + 59, + 77, + 215, + 98, + 166, + 241, + 8, + 24, + 40, + 120, + 136, + 131, + 158, + 185, + 208, + 107, + 189, + 220, + 127, + 129, + 152, + 179, + 206, + 73, + 219, + 118, + 154, + 181, + 196, + 87, + 249, + 16, + 48, + 80, + 240, + 11, + 29, + 39, + 105, + 187, + 214, + 97, + 163, + 254, + 25, + 43, + 125, + 135, + 146, + 173, + 236, + 47, + 113, + 147, + 174, + 233, + 32, + 96, + 160, + 251, + 22, + 58, + 78, + 210, + 109, + 183, + 194, + 93, + 231, + 50, + 86, + 250, + 21, + 63, + 65, + 195, + 94, + 226, + 61, + 71, + 201, + 64, + 192, + 91, + 237, + 44, + 116, + 156, + 191, + 218, + 117, + 159, + 186, + 213, + 100, + 172, + 239, + 42, + 126, + 130, + 157, + 188, + 223, + 122, + 142, + 137, + 128, + 155, + 182, + 193, + 88, + 232, + 35, + 101, + 175, + 234, + 37, + 111, + 177, + 200, + 67, + 197, + 84, + 252, + 31, + 33, + 99, + 165, + 244, + 7, + 9, + 27, + 45, + 119, + 153, + 176, + 203, + 70, + 202, + 69, + 207, + 74, + 222, + 121, + 139, + 134, + 145, + 168, + 227, + 62, + 66, + 198, + 81, + 243, + 14, + 18, + 54, + 90, + 238, + 41, + 123, + 141, + 140, + 143, + 138, + 133, + 148, + 167, + 242, + 13, + 23, + 57, + 75, + 221, + 124, + 132, + 151, + 162, + 253, + 28, + 36, + 108, + 180, + 199, + 82, + 246, + 1 + }; - private static ReadOnlySpan S => new byte[] - { - 99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, 118, - 202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164, 114, 192, - 183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113, 216, 49, 21, - 4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226, 235, 39, 178, 117, - 9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214, 179, 41, 227, 47, 132, - 83, 209, 0, 237, 32, 252, 177, 91, 106, 203, 190, 57, 74, 76, 88, 207, - 208, 239, 170, 251, 67, 77, 51, 133, 69, 249, 2, 127, 80, 60, 159, 168, - 81, 163, 64, 143, 146, 157, 56, 245, 188, 182, 218, 33, 16, 255, 243, 210, - 205, 12, 19, 236, 95, 151, 68, 23, 196, 167, 126, 61, 100, 93, 25, 115, - 96, 129, 79, 220, 34, 42, 144, 136, 70, 238, 184, 20, 222, 94, 11, 219, - 224, 50, 58, 10, 73, 6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121, - 231, 200, 55, 109, 141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174, 8, - 186, 120, 37, 46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138, - 112, 62, 181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158, - 225, 248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85, 40, 223, - 140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15, 176, 84, 187, 22 - }; + private static ReadOnlySpan S => + new byte[] + { + 99, + 124, + 119, + 123, + 242, + 107, + 111, + 197, + 48, + 1, + 103, + 43, + 254, + 215, + 171, + 118, + 202, + 130, + 201, + 125, + 250, + 89, + 71, + 240, + 173, + 212, + 162, + 175, + 156, + 164, + 114, + 192, + 183, + 253, + 147, + 38, + 54, + 63, + 247, + 204, + 52, + 165, + 229, + 241, + 113, + 216, + 49, + 21, + 4, + 199, + 35, + 195, + 24, + 150, + 5, + 154, + 7, + 18, + 128, + 226, + 235, + 39, + 178, + 117, + 9, + 131, + 44, + 26, + 27, + 110, + 90, + 160, + 82, + 59, + 214, + 179, + 41, + 227, + 47, + 132, + 83, + 209, + 0, + 237, + 32, + 252, + 177, + 91, + 106, + 203, + 190, + 57, + 74, + 76, + 88, + 207, + 208, + 239, + 170, + 251, + 67, + 77, + 51, + 133, + 69, + 249, + 2, + 127, + 80, + 60, + 159, + 168, + 81, + 163, + 64, + 143, + 146, + 157, + 56, + 245, + 188, + 182, + 218, + 33, + 16, + 255, + 243, + 210, + 205, + 12, + 19, + 236, + 95, + 151, + 68, + 23, + 196, + 167, + 126, + 61, + 100, + 93, + 25, + 115, + 96, + 129, + 79, + 220, + 34, + 42, + 144, + 136, + 70, + 238, + 184, + 20, + 222, + 94, + 11, + 219, + 224, + 50, + 58, + 10, + 73, + 6, + 36, + 92, + 194, + 211, + 172, + 98, + 145, + 149, + 228, + 121, + 231, + 200, + 55, + 109, + 141, + 213, + 78, + 169, + 108, + 86, + 244, + 234, + 101, + 122, + 174, + 8, + 186, + 120, + 37, + 46, + 28, + 166, + 180, + 198, + 232, + 221, + 116, + 31, + 75, + 189, + 139, + 138, + 112, + 62, + 181, + 102, + 72, + 3, + 246, + 14, + 97, + 53, + 87, + 185, + 134, + 193, + 29, + 158, + 225, + 248, + 152, + 17, + 105, + 217, + 142, + 148, + 155, + 30, + 135, + 233, + 206, + 85, + 40, + 223, + 140, + 161, + 137, + 13, + 191, + 230, + 66, + 104, + 65, + 153, + 45, + 15, + 176, + 84, + 187, + 22 + }; - private static ReadOnlySpan Si => new byte[] - { - 82, 9, 106, 213, 48, 54, 165, 56, 191, 64, 163, 158, 129, 243, 215, 251, - 124, 227, 57, 130, 155, 47, 255, 135, 52, 142, 67, 68, 196, 222, 233, 203, - 84, 123, 148, 50, 166, 194, 35, 61, 238, 76, 149, 11, 66, 250, 195, 78, - 8, 46, 161, 102, 40, 217, 36, 178, 118, 91, 162, 73, 109, 139, 209, 37, - 114, 248, 246, 100, 134, 104, 152, 22, 212, 164, 92, 204, 93, 101, 182, 146, - 108, 112, 72, 80, 253, 237, 185, 218, 94, 21, 70, 87, 167, 141, 157, 132, - 144, 216, 171, 0, 140, 188, 211, 10, 247, 228, 88, 5, 184, 179, 69, 6, - 208, 44, 30, 143, 202, 63, 15, 2, 193, 175, 189, 3, 1, 19, 138, 107, - 58, 145, 17, 65, 79, 103, 220, 234, 151, 242, 207, 206, 240, 180, 230, 115, - 150, 172, 116, 34, 231, 173, 53, 133, 226, 249, 55, 232, 28, 117, 223, 110, - 71, 241, 26, 113, 29, 41, 197, 137, 111, 183, 98, 14, 170, 24, 190, 27, - 252, 86, 62, 75, 198, 210, 121, 32, 154, 219, 192, 254, 120, 205, 90, 244, - 31, 221, 168, 51, 136, 7, 199, 49, 177, 18, 16, 89, 39, 128, 236, 95, - 96, 81, 127, 169, 25, 181, 74, 13, 45, 229, 122, 159, 147, 201, 156, 239, - 160, 224, 59, 77, 174, 42, 245, 176, 200, 235, 187, 60, 131, 83, 153, 97, - 23, 43, 4, 126, 186, 119, 214, 38, 225, 105, 20, 99, 85, 33, 12, 125 - }; + private static ReadOnlySpan Si => + new byte[] + { + 82, + 9, + 106, + 213, + 48, + 54, + 165, + 56, + 191, + 64, + 163, + 158, + 129, + 243, + 215, + 251, + 124, + 227, + 57, + 130, + 155, + 47, + 255, + 135, + 52, + 142, + 67, + 68, + 196, + 222, + 233, + 203, + 84, + 123, + 148, + 50, + 166, + 194, + 35, + 61, + 238, + 76, + 149, + 11, + 66, + 250, + 195, + 78, + 8, + 46, + 161, + 102, + 40, + 217, + 36, + 178, + 118, + 91, + 162, + 73, + 109, + 139, + 209, + 37, + 114, + 248, + 246, + 100, + 134, + 104, + 152, + 22, + 212, + 164, + 92, + 204, + 93, + 101, + 182, + 146, + 108, + 112, + 72, + 80, + 253, + 237, + 185, + 218, + 94, + 21, + 70, + 87, + 167, + 141, + 157, + 132, + 144, + 216, + 171, + 0, + 140, + 188, + 211, + 10, + 247, + 228, + 88, + 5, + 184, + 179, + 69, + 6, + 208, + 44, + 30, + 143, + 202, + 63, + 15, + 2, + 193, + 175, + 189, + 3, + 1, + 19, + 138, + 107, + 58, + 145, + 17, + 65, + 79, + 103, + 220, + 234, + 151, + 242, + 207, + 206, + 240, + 180, + 230, + 115, + 150, + 172, + 116, + 34, + 231, + 173, + 53, + 133, + 226, + 249, + 55, + 232, + 28, + 117, + 223, + 110, + 71, + 241, + 26, + 113, + 29, + 41, + 197, + 137, + 111, + 183, + 98, + 14, + 170, + 24, + 190, + 27, + 252, + 86, + 62, + 75, + 198, + 210, + 121, + 32, + 154, + 219, + 192, + 254, + 120, + 205, + 90, + 244, + 31, + 221, + 168, + 51, + 136, + 7, + 199, + 49, + 177, + 18, + 16, + 89, + 39, + 128, + 236, + 95, + 96, + 81, + 127, + 169, + 25, + 181, + 74, + 13, + 45, + 229, + 122, + 159, + 147, + 201, + 156, + 239, + 160, + 224, + 59, + 77, + 174, + 42, + 245, + 176, + 200, + 235, + 187, + 60, + 131, + 83, + 153, + 97, + 23, + 43, + 4, + 126, + 186, + 119, + 214, + 38, + 225, + 105, + 20, + 99, + 85, + 33, + 12, + 125 + }; - private static ReadOnlySpan rcon => new byte[] - { - 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, - 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 - }; + private static ReadOnlySpan rcon => + new byte[] + { + 0x01, + 0x02, + 0x04, + 0x08, + 0x10, + 0x20, + 0x40, + 0x80, + 0x1b, + 0x36, + 0x6c, + 0xd8, + 0xab, + 0x4d, + 0x9a, + 0x2f, + 0x5e, + 0xbc, + 0x63, + 0xc6, + 0x97, + 0x35, + 0x6a, + 0xd4, + 0xb3, + 0x7d, + 0xfa, + 0xef, + 0xc5, + 0x91 + }; private static readonly byte[][] shifts0 = { - new byte[] {0, 8, 16, 24}, - new byte[] {0, 8, 16, 24}, - new byte[] {0, 8, 16, 24}, - new byte[] {0, 8, 16, 32}, - new byte[] {0, 8, 24, 32} + new byte[] { 0, 8, 16, 24 }, + new byte[] { 0, 8, 16, 24 }, + new byte[] { 0, 8, 16, 24 }, + new byte[] { 0, 8, 16, 32 }, + new byte[] { 0, 8, 24, 32 } }; private static readonly byte[][] shifts1 = { - new byte[] {0, 24, 16, 8}, - new byte[] {0, 32, 24, 16}, - new byte[] {0, 40, 32, 24}, - new byte[] {0, 48, 40, 24}, - new byte[] {0, 56, 40, 32} + new byte[] { 0, 24, 16, 8 }, + new byte[] { 0, 32, 24, 16 }, + new byte[] { 0, 40, 32, 24 }, + new byte[] { 0, 48, 40, 24 }, + new byte[] { 0, 56, 40, 32 } }; /** @@ -150,8 +1365,7 @@ namespace SharpCompress.Crypto * needed for MixColumn and InvMixColumn */ - private byte Mul0x2( - int b) + private byte Mul0x2(int b) { if (b != 0) { @@ -160,8 +1374,7 @@ namespace SharpCompress.Crypto return 0; } - private byte Mul0x3( - int b) + private byte Mul0x3(int b) { if (b != 0) { @@ -170,8 +1383,7 @@ namespace SharpCompress.Crypto return 0; } - private byte Mul0x9( - int b) + private byte Mul0x9(int b) { if (b >= 0) { @@ -180,8 +1392,7 @@ namespace SharpCompress.Crypto return 0; } - private byte Mul0xb( - int b) + private byte Mul0xb(int b) { if (b >= 0) { @@ -190,8 +1401,7 @@ namespace SharpCompress.Crypto return 0; } - private byte Mul0xd( - int b) + private byte Mul0xd(int b) { if (b >= 0) { @@ -200,8 +1410,7 @@ namespace SharpCompress.Crypto return 0; } - private byte Mul0xe( - int b) + private byte Mul0xe(int b) { if (b >= 0) { @@ -222,9 +1431,7 @@ namespace SharpCompress.Crypto A3 ^= rk[3]; } - private long Shift( - long r, - int shift) + private long Shift(long r, int shift) { //return (((long)((ulong) r >> shift) | (r << (BC - shift)))) & BC_MASK; @@ -282,7 +1489,10 @@ namespace SharpCompress.Crypto private void MixColumn() { - long r0, r1, r2, r3; + long r0, + r1, + r2, + r3; r0 = r1 = r2 = r3 = 0; @@ -315,7 +1525,10 @@ namespace SharpCompress.Crypto private void InvMixColumn() { - long r0, r1, r2, r3; + long r0, + r1, + r2, + r3; r0 = r1 = r2 = r3 = 0; for (int j = 0; j < BC; j += 8) @@ -353,10 +1566,10 @@ namespace SharpCompress.Crypto * The number of calculations depends on keyBits and blockBits */ - private long[][] GenerateWorkingKey( - byte[] key) + private long[][] GenerateWorkingKey(byte[] key) { - int t, rconpointer = 0; + int t, + rconpointer = 0; int keyBits = key.Length * 8; byte[,] tk = new byte[4, MAXKC]; @@ -472,7 +1685,10 @@ namespace SharpCompress.Crypto private int ROUNDS; private readonly int blockBits; private long[][]? workingKey; - private long A0, A1, A2, A3; + private long A0, + A1, + A2, + A3; private bool forEncryption; private readonly byte[] shifts0SC; private readonly byte[] shifts1SC; @@ -481,10 +1697,7 @@ namespace SharpCompress.Crypto * default constructor - 128 bit block size. */ - public RijndaelEngine() - : this(128) - { - } + public RijndaelEngine() : this(128) { } /** * basic constructor - set the cipher up for a given blocksize @@ -492,8 +1705,7 @@ namespace SharpCompress.Crypto * @param blocksize the blocksize in bits, must be 128, 192, or 256. */ - public RijndaelEngine( - int blockBits) + public RijndaelEngine(int blockBits) { switch (blockBits) { @@ -543,9 +1755,7 @@ namespace SharpCompress.Crypto * inappropriate. */ - public void Init( - bool forEncryption, - ICipherParameters parameters) + public void Init(bool forEncryption, ICipherParameters parameters) { var parameter = parameters as KeyParameter; if (parameter != null) @@ -555,7 +1765,9 @@ namespace SharpCompress.Crypto return; } - throw new ArgumentException("invalid parameter passed to Rijndael init - " + parameters.GetType()); + throw new ArgumentException( + "invalid parameter passed to Rijndael init - " + parameters.GetType() + ); } public string AlgorithmName => "Rijndael"; @@ -600,9 +1812,7 @@ namespace SharpCompress.Crypto return BC / 2; } - public void Reset() - { - } + public void Reset() { } private void UnPackBlock(ReadOnlySpan bytes) { @@ -700,4 +1910,4 @@ namespace SharpCompress.Crypto KeyAddition(rk[0]); } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Factories/Factory.cs b/src/SharpCompress/Factories/Factory.cs index 9f5cb001..ba0bae88 100644 --- a/src/SharpCompress/Factories/Factory.cs +++ b/src/SharpCompress/Factories/Factory.cs @@ -29,7 +29,7 @@ namespace SharpCompress.Factories /// /// Gets the collection of registered . /// - public static IEnumerable Factories => _factories; + public static IEnumerable Factories => _factories; /// /// Registers an archive factory. @@ -71,7 +71,11 @@ namespace SharpCompress.Factories /// /// /// - internal virtual bool TryOpenReader(RewindableStream rewindableStream, ReaderOptions options, out IReader? reader) + internal virtual bool TryOpenReader( + RewindableStream rewindableStream, + ReaderOptions options, + out IReader? reader + ) { reader = null; @@ -85,8 +89,8 @@ namespace SharpCompress.Factories return true; } } - + return false; - } + } } } diff --git a/src/SharpCompress/Factories/GZipFactory.cs b/src/SharpCompress/Factories/GZipFactory.cs index fe6f4260..1c473e55 100644 --- a/src/SharpCompress/Factories/GZipFactory.cs +++ b/src/SharpCompress/Factories/GZipFactory.cs @@ -20,12 +20,13 @@ namespace SharpCompress.Factories /// /// Represents the foundation factory of GZip archive. /// - public class GZipFactory : Factory, - IArchiveFactory, - IMultiArchiveFactory, - IReaderFactory, - IWriterFactory, - IWriteableArchiveFactory + public class GZipFactory + : Factory, + IArchiveFactory, + IMultiArchiveFactory, + IReaderFactory, + IWriterFactory, + IWriteableArchiveFactory { #region IFactory @@ -65,7 +66,7 @@ namespace SharpCompress.Factories #endregion - #region IMultiArchiveFactory + #region IMultiArchiveFactory /// public IArchive Open(IReadOnlyList streams, ReaderOptions? readerOptions = null) @@ -84,7 +85,11 @@ namespace SharpCompress.Factories #region IReaderFactory /// - internal override bool TryOpenReader(RewindableStream rewindableStream, ReaderOptions options, out IReader? reader) + internal override bool TryOpenReader( + RewindableStream rewindableStream, + ReaderOptions options, + out IReader? reader + ) { reader = null; @@ -104,7 +109,7 @@ namespace SharpCompress.Factories reader = OpenReader(rewindableStream, options); return true; } - + return false; } @@ -123,7 +128,9 @@ namespace SharpCompress.Factories { if (writerOptions.CompressionType != CompressionType.GZip) { - throw new InvalidFormatException("GZip archives only support GZip compression type."); + throw new InvalidFormatException( + "GZip archives only support GZip compression type." + ); } return new GZipWriter(stream, new GZipWriterOptions(writerOptions)); } diff --git a/src/SharpCompress/Factories/IFactory.cs b/src/SharpCompress/Factories/IFactory.cs index 82e27f11..39c2c384 100644 --- a/src/SharpCompress/Factories/IFactory.cs +++ b/src/SharpCompress/Factories/IFactory.cs @@ -32,7 +32,7 @@ namespace SharpCompress.Factories /// returns the extensions typically used by this archive type. /// /// - IEnumerable GetSupportedExtensions(); + IEnumerable GetSupportedExtensions(); /// /// Returns true if the stream represents an archive of the format defined by this type. @@ -52,4 +52,3 @@ namespace SharpCompress.Factories FileInfo? GetFilePart(int index, FileInfo part1); } } - diff --git a/src/SharpCompress/Factories/RarFactory.cs b/src/SharpCompress/Factories/RarFactory.cs index 7d6c16ba..f9ffdb8c 100644 --- a/src/SharpCompress/Factories/RarFactory.cs +++ b/src/SharpCompress/Factories/RarFactory.cs @@ -14,10 +14,7 @@ namespace SharpCompress.Factories /// /// Represents the foundation factory of RAR archive. /// - public class RarFactory : Factory, - IArchiveFactory, - IMultiArchiveFactory, - IReaderFactory + public class RarFactory : Factory, IArchiveFactory, IMultiArchiveFactory, IReaderFactory { #region IArchive @@ -48,7 +45,7 @@ namespace SharpCompress.Factories #endregion - #region IArchiveFactory + #region IArchiveFactory /// public IArchive Open(Stream stream, ReaderOptions? readerOptions = null) @@ -80,7 +77,7 @@ namespace SharpCompress.Factories #endregion - #region IReaderFactory + #region IReaderFactory /// public IReader OpenReader(Stream stream, ReaderOptions? options) diff --git a/src/SharpCompress/Factories/SevenZipFactory.cs b/src/SharpCompress/Factories/SevenZipFactory.cs index c7d4dd8b..8bdbb8d0 100644 --- a/src/SharpCompress/Factories/SevenZipFactory.cs +++ b/src/SharpCompress/Factories/SevenZipFactory.cs @@ -14,9 +14,7 @@ namespace SharpCompress.Factories /// /// Represents the foundation factory of 7Zip archive. /// - public class SevenZipFactory : Factory, - IArchiveFactory, - IMultiArchiveFactory + public class SevenZipFactory : Factory, IArchiveFactory, IMultiArchiveFactory { #region IFactory @@ -40,7 +38,7 @@ namespace SharpCompress.Factories #endregion - #region IArchiveFactory + #region IArchiveFactory /// public IArchive Open(Stream stream, ReaderOptions? readerOptions = null) @@ -68,18 +66,22 @@ namespace SharpCompress.Factories public IArchive Open(IReadOnlyList fileInfos, ReaderOptions? readerOptions = null) { return SevenZipArchive.Open(fileInfos, readerOptions); - } + } #endregion #region reader - internal override bool TryOpenReader(RewindableStream rewindableStream, ReaderOptions options, out IReader? reader) + internal override bool TryOpenReader( + RewindableStream rewindableStream, + ReaderOptions options, + out IReader? reader + ) { reader = null; return false; } - + #endregion } } diff --git a/src/SharpCompress/Factories/TarFactory.cs b/src/SharpCompress/Factories/TarFactory.cs index 4214ca93..b2322d56 100644 --- a/src/SharpCompress/Factories/TarFactory.cs +++ b/src/SharpCompress/Factories/TarFactory.cs @@ -22,12 +22,13 @@ namespace SharpCompress.Factories /// /// Represents the foundation factory of TAR archive. /// - public class TarFactory : Factory, - IArchiveFactory, - IMultiArchiveFactory, - IReaderFactory, - IWriterFactory, - IWriteableArchiveFactory + public class TarFactory + : Factory, + IArchiveFactory, + IMultiArchiveFactory, + IReaderFactory, + IWriterFactory, + IWriteableArchiveFactory { #region IFactory @@ -111,7 +112,11 @@ namespace SharpCompress.Factories #region IReaderFactory /// - internal override bool TryOpenReader(RewindableStream rewindableStream, ReaderOptions options, out IReader? reader) + internal override bool TryOpenReader( + RewindableStream rewindableStream, + ReaderOptions options, + out IReader? reader + ) { reader = null; @@ -127,7 +132,11 @@ namespace SharpCompress.Factories if (BZip2Stream.IsBZip2(rewindableStream)) { rewindableStream.Rewind(false); - var testStream = new BZip2Stream(NonDisposingStream.Create(rewindableStream), CompressionMode.Decompress, false); + var testStream = new BZip2Stream( + NonDisposingStream.Create(rewindableStream), + CompressionMode.Decompress, + false + ); if (TarArchive.IsTarFile(testStream)) { rewindableStream.Rewind(true); @@ -140,7 +149,10 @@ namespace SharpCompress.Factories if (LZipStream.IsLZipFile(rewindableStream)) { rewindableStream.Rewind(false); - var testStream = new LZipStream(NonDisposingStream.Create(rewindableStream), CompressionMode.Decompress); + var testStream = new LZipStream( + NonDisposingStream.Create(rewindableStream), + CompressionMode.Decompress + ); if (TarArchive.IsTarFile(testStream)) { rewindableStream.Rewind(true); @@ -161,7 +173,7 @@ namespace SharpCompress.Factories return true; } } - + return false; } @@ -192,6 +204,5 @@ namespace SharpCompress.Factories } #endregion - } } diff --git a/src/SharpCompress/Factories/ZipFactory.cs b/src/SharpCompress/Factories/ZipFactory.cs index a3e6e757..66b274cb 100644 --- a/src/SharpCompress/Factories/ZipFactory.cs +++ b/src/SharpCompress/Factories/ZipFactory.cs @@ -18,12 +18,13 @@ namespace SharpCompress.Factories /// /// Represents the foundation factory of ZIP archive. /// - public class ZipFactory : Factory, - IArchiveFactory, - IMultiArchiveFactory, - IReaderFactory, - IWriterFactory, - IWriteableArchiveFactory + public class ZipFactory + : Factory, + IArchiveFactory, + IMultiArchiveFactory, + IReaderFactory, + IWriterFactory, + IWriteableArchiveFactory { #region IFactory @@ -44,9 +45,7 @@ namespace SharpCompress.Factories /// public override bool IsArchive(Stream stream, string? password = null) { - var startPosition = stream.CanSeek - ? stream.Position - : -1; + var startPosition = stream.CanSeek ? stream.Position : -1; // probe for single volume zip @@ -91,7 +90,7 @@ namespace SharpCompress.Factories #endregion - #region IMultiArchiveFactory + #region IMultiArchiveFactory /// public IArchive Open(IReadOnlyList streams, ReaderOptions? readerOptions = null) @@ -107,7 +106,7 @@ namespace SharpCompress.Factories #endregion - #region IReaderFactory + #region IReaderFactory /// public IReader OpenReader(Stream stream, ReaderOptions? options) diff --git a/src/SharpCompress/IO/BufferedSubStream.cs b/src/SharpCompress/IO/BufferedSubStream.cs index 9b6ae6cd..94d70b17 100644 --- a/src/SharpCompress/IO/BufferedSubStream.cs +++ b/src/SharpCompress/IO/BufferedSubStream.cs @@ -10,7 +10,8 @@ namespace SharpCompress.IO private int cacheLength; private readonly byte[] cache; - public BufferedSubStream(Stream stream, long origin, long bytesToRead) : base(stream, throwOnDispose: false) + public BufferedSubStream(Stream stream, long origin, long bytesToRead) + : base(stream, throwOnDispose: false) { position = origin; BytesLeftToRead = bytesToRead; @@ -32,7 +33,11 @@ namespace SharpCompress.IO public override long Length => BytesLeftToRead; - public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); } + public override long Position + { + get => throw new NotSupportedException(); + set => throw new NotSupportedException(); + } public override int Read(byte[] buffer, int offset, int count) { @@ -80,4 +85,4 @@ namespace SharpCompress.IO throw new NotSupportedException(); } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/IO/CountingWritableSubStream.cs b/src/SharpCompress/IO/CountingWritableSubStream.cs index b94303bf..a5aa4465 100644 --- a/src/SharpCompress/IO/CountingWritableSubStream.cs +++ b/src/SharpCompress/IO/CountingWritableSubStream.cs @@ -5,9 +5,7 @@ namespace SharpCompress.IO { internal class CountingWritableSubStream : NonDisposingStream { - internal CountingWritableSubStream(Stream stream) : base(stream, throwOnDispose: false) - { - } + internal CountingWritableSubStream(Stream stream) : base(stream, throwOnDispose: false) { } public ulong Count { get; private set; } @@ -24,7 +22,11 @@ namespace SharpCompress.IO public override long Length => throw new NotSupportedException(); - public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); } + public override long Position + { + get => throw new NotSupportedException(); + set => throw new NotSupportedException(); + } public override int Read(byte[] buffer, int offset, int count) { @@ -53,4 +55,4 @@ namespace SharpCompress.IO ++Count; } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/IO/ListeningStream.cs b/src/SharpCompress/IO/ListeningStream.cs index 1bab99d2..d914bec4 100644 --- a/src/SharpCompress/IO/ListeningStream.cs +++ b/src/SharpCompress/IO/ListeningStream.cs @@ -38,13 +38,20 @@ namespace SharpCompress.IO public override long Length => Stream.Length; - public override long Position { get => Stream.Position; set => Stream.Position = value; } + public override long Position + { + get => Stream.Position; + set => Stream.Position = value; + } public override int Read(byte[] buffer, int offset, int count) { int read = Stream.Read(buffer, offset, count); currentEntryTotalReadBytes += read; - listener.FireCompressedBytesRead(currentEntryTotalReadBytes, currentEntryTotalReadBytes); + listener.FireCompressedBytesRead( + currentEntryTotalReadBytes, + currentEntryTotalReadBytes + ); return read; } @@ -57,7 +64,10 @@ namespace SharpCompress.IO } ++currentEntryTotalReadBytes; - listener.FireCompressedBytesRead(currentEntryTotalReadBytes, currentEntryTotalReadBytes); + listener.FireCompressedBytesRead( + currentEntryTotalReadBytes, + currentEntryTotalReadBytes + ); return value; } @@ -76,4 +86,4 @@ namespace SharpCompress.IO Stream.Write(buffer, offset, count); } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/IO/MarkingBinaryReader.cs b/src/SharpCompress/IO/MarkingBinaryReader.cs index 5b3e7ffe..01847518 100644 --- a/src/SharpCompress/IO/MarkingBinaryReader.cs +++ b/src/SharpCompress/IO/MarkingBinaryReader.cs @@ -6,10 +6,7 @@ namespace SharpCompress.IO { internal class MarkingBinaryReader : BinaryReader { - public MarkingBinaryReader(Stream stream) - : base(stream) - { - } + public MarkingBinaryReader(Stream stream) : base(stream) { } public virtual long CurrentReadByteCount { get; protected set; } @@ -59,7 +56,13 @@ namespace SharpCompress.IO var bytes = base.ReadBytes(count); if (bytes.Length != count) { - throw new EndOfStreamException(string.Format("Could not read the requested amount of bytes. End of stream reached. Requested: {0} Read: {1}", count, bytes.Length)); + throw new EndOfStreamException( + string.Format( + "Could not read the requested amount of bytes. End of stream reached. Requested: {0} Read: {1}", + count, + bytes.Length + ) + ); } return bytes; } diff --git a/src/SharpCompress/IO/NonDisposingStream.cs b/src/SharpCompress/IO/NonDisposingStream.cs index 12b9a6cf..a3b74469 100644 --- a/src/SharpCompress/IO/NonDisposingStream.cs +++ b/src/SharpCompress/IO/NonDisposingStream.cs @@ -7,7 +7,10 @@ namespace SharpCompress.IO { public static NonDisposingStream Create(Stream stream, bool throwOnDispose = false) { - if (stream is NonDisposingStream nonDisposingStream && nonDisposingStream.ThrowOnDispose == throwOnDispose) + if ( + stream is NonDisposingStream nonDisposingStream + && nonDisposingStream.ThrowOnDispose == throwOnDispose + ) { return nonDisposingStream; } @@ -26,7 +29,9 @@ namespace SharpCompress.IO { if (ThrowOnDispose) { - throw new InvalidOperationException($"Attempt to dispose of a {nameof(NonDisposingStream)} when {nameof(ThrowOnDispose)} is {ThrowOnDispose}"); + throw new InvalidOperationException( + $"Attempt to dispose of a {nameof(NonDisposingStream)} when {nameof(ThrowOnDispose)} is {ThrowOnDispose}" + ); } } @@ -45,7 +50,11 @@ namespace SharpCompress.IO public override long Length => Stream.Length; - public override long Position { get => Stream.Position; set => Stream.Position = value; } + public override long Position + { + get => Stream.Position; + set => Stream.Position = value; + } public override int Read(byte[] buffer, int offset, int count) { diff --git a/src/SharpCompress/IO/ReadOnlySubStream.cs b/src/SharpCompress/IO/ReadOnlySubStream.cs index 4ba326dd..f098db4c 100644 --- a/src/SharpCompress/IO/ReadOnlySubStream.cs +++ b/src/SharpCompress/IO/ReadOnlySubStream.cs @@ -5,10 +5,8 @@ namespace SharpCompress.IO { internal class ReadOnlySubStream : NonDisposingStream { - public ReadOnlySubStream(Stream stream, long bytesToRead) - : this(stream, null, bytesToRead) - { - } + public ReadOnlySubStream(Stream stream, long bytesToRead) : this(stream, null, bytesToRead) + { } public ReadOnlySubStream(Stream stream, long? origin, long bytesToRead) : base(stream, throwOnDispose: false) @@ -35,7 +33,11 @@ namespace SharpCompress.IO public override long Length => throw new NotSupportedException(); - public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); } + public override long Position + { + get => throw new NotSupportedException(); + set => throw new NotSupportedException(); + } public override int Read(byte[] buffer, int offset, int count) { @@ -69,7 +71,7 @@ namespace SharpCompress.IO public override int Read(Span buffer) { var slice_len = BytesLeftToRead < buffer.Length ? BytesLeftToRead : buffer.Length; - var read = Stream.Read(buffer.Slice(0,(int)slice_len)); + var read = Stream.Read(buffer.Slice(0, (int)slice_len)); if (read > 0) { BytesLeftToRead -= read; diff --git a/src/SharpCompress/IO/RewindableStream.cs b/src/SharpCompress/IO/RewindableStream.cs index c30efeb0..281f08ea 100644 --- a/src/SharpCompress/IO/RewindableStream.cs +++ b/src/SharpCompress/IO/RewindableStream.cs @@ -46,7 +46,6 @@ namespace SharpCompress.IO } else { - bufferStream.TransferTo(buffer); //create new memorystream to allow proper resizing as memorystream could be a user provided buffer //https://github.com/adamhathcock/sharpcompress/issues/306 diff --git a/src/SharpCompress/IO/SourceStream.cs b/src/SharpCompress/IO/SourceStream.cs index e23f7eb7..35fba988 100644 --- a/src/SharpCompress/IO/SourceStream.cs +++ b/src/SharpCompress/IO/SourceStream.cs @@ -17,15 +17,19 @@ namespace SharpCompress.IO private Func _getStreamPart; private int _stream; - public SourceStream(FileInfo file, Func getPart, ReaderOptions options) : this(null, null, file, getPart, options) - { - } + public SourceStream(FileInfo file, Func getPart, ReaderOptions options) + : this(null, null, file, getPart, options) { } - public SourceStream(Stream stream, Func getPart, ReaderOptions options) : this(stream, getPart, null, null, options) - { - } + public SourceStream(Stream stream, Func getPart, ReaderOptions options) + : this(stream, getPart, null, null, options) { } - private SourceStream(Stream? stream, Func? getStreamPart, FileInfo? file, Func? getFilePart, ReaderOptions options) + private SourceStream( + Stream? stream, + Func? getStreamPart, + FileInfo? file, + Func? getFilePart, + ReaderOptions options + ) { this.ReaderOptions = options; _files = new List(); @@ -54,9 +58,7 @@ namespace SharpCompress.IO public void LoadAllParts() { - for (int i = 1; SetStream(i); i++) - { - } + for (int i = 1; SetStream(i); i++) { } SetStream(0); } @@ -69,6 +71,7 @@ namespace SharpCompress.IO public IEnumerable Streams => _streams; private Stream Current => _streams[_stream]; + public bool LoadStream(int index) //ensure all parts to id are loaded { while (_streams.Count <= index) @@ -101,6 +104,7 @@ namespace SharpCompress.IO } return true; } + public bool SetStream(int idx) //allow caller to switch part in multipart { if (LoadStream(idx)) @@ -137,7 +141,11 @@ namespace SharpCompress.IO while (count != 0 && r != 0) { - r = Current.Read(buffer, offset, (int)Math.Min(count, Current.Length - Current.Position)); + r = Current.Read( + buffer, + offset, + (int)Math.Min(count, Current.Length - Current.Position) + ); count -= r; offset += r; @@ -146,7 +154,7 @@ namespace SharpCompress.IO var length = Current.Length; // Load next file if present - if (!SetStream(_stream + 1)) + if (!SetStream(_stream + 1)) { break; } @@ -166,9 +174,15 @@ namespace SharpCompress.IO long pos = this.Position; switch (origin) { - case SeekOrigin.Begin: pos = offset; break; - case SeekOrigin.Current: pos += offset; break; - case SeekOrigin.End: pos = Length + offset; break; + case SeekOrigin.Begin: + pos = offset; + break; + case SeekOrigin.Current: + pos += offset; + break; + case SeekOrigin.End: + pos = Length + offset; + break; } _prevSize = 0; diff --git a/src/SharpCompress/Lazy.cs b/src/SharpCompress/Lazy.cs index eab72849..3ddd47d2 100644 --- a/src/SharpCompress/Lazy.cs +++ b/src/SharpCompress/Lazy.cs @@ -28,4 +28,4 @@ namespace SharpCompress } } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Polyfills/StringExtensions.cs b/src/SharpCompress/Polyfills/StringExtensions.cs index e58aff4d..c6283707 100644 --- a/src/SharpCompress/Polyfills/StringExtensions.cs +++ b/src/SharpCompress/Polyfills/StringExtensions.cs @@ -16,4 +16,4 @@ namespace SharpCompress } } -#endif \ No newline at end of file +#endif diff --git a/src/SharpCompress/Readers/AbstractReader.cs b/src/SharpCompress/Readers/AbstractReader.cs index 619d834e..f8d91ca1 100644 --- a/src/SharpCompress/Readers/AbstractReader.cs +++ b/src/SharpCompress/Readers/AbstractReader.cs @@ -99,9 +99,11 @@ namespace SharpCompress.Readers entriesForCurrentReadStream?.Dispose(); if ((stream is null) || (!stream.CanRead)) { - throw new MultipartStreamRequiredException("File is split into multiple archives: '" - + Entry.Key + - "'. A new readable stream is required. Use Cancel if it was intended."); + throw new MultipartStreamRequiredException( + "File is split into multiple archives: '" + + Entry.Key + + "'. A new readable stream is required. Use Cancel if it was intended." + ); } entriesForCurrentReadStream = GetEntries(stream).GetEnumerator(); return entriesForCurrentReadStream.MoveNext(); @@ -133,9 +135,7 @@ namespace SharpCompress.Readers { var part = Entry.Parts.First(); - if (ArchiveType != ArchiveType.Rar - && !Entry.IsSolid - && Entry.CompressedSize > 0) + if (ArchiveType != ArchiveType.Rar && !Entry.IsSolid && Entry.CompressedSize > 0) { //not solid and has a known compressed size then we can skip raw bytes. var rawStream = part.GetRawStream(); @@ -159,7 +159,9 @@ namespace SharpCompress.Readers { if (wroteCurrentEntry) { - throw new ArgumentException("WriteEntryTo or OpenEntryStream can only be called once."); + throw new ArgumentException( + "WriteEntryTo or OpenEntryStream can only be called once." + ); } if (writableStream is null) @@ -168,7 +170,9 @@ namespace SharpCompress.Readers } if (!writableStream.CanWrite) { - throw new ArgumentException("A writable Stream was required. Use Cancel if that was intended."); + throw new ArgumentException( + "A writable Stream was required. Use Cancel if that was intended." + ); } Write(writableStream); @@ -188,7 +192,9 @@ namespace SharpCompress.Readers { if (wroteCurrentEntry) { - throw new ArgumentException("WriteEntryTo or OpenEntryStream can only be called once."); + throw new ArgumentException( + "WriteEntryTo or OpenEntryStream can only be called once." + ); } var stream = GetEntryStream(); wroteCurrentEntry = true; @@ -212,26 +218,49 @@ namespace SharpCompress.Readers IEntry IReader.Entry => Entry; - void IExtractionListener.FireCompressedBytesRead(long currentPartCompressedBytes, long compressedReadBytes) + void IExtractionListener.FireCompressedBytesRead( + long currentPartCompressedBytes, + long compressedReadBytes + ) { - CompressedBytesRead?.Invoke(this, new CompressedBytesReadEventArgs( - currentFilePartCompressedBytesRead: currentPartCompressedBytes, - compressedBytesRead: compressedReadBytes - )); + CompressedBytesRead?.Invoke( + this, + new CompressedBytesReadEventArgs( + currentFilePartCompressedBytesRead: currentPartCompressedBytes, + compressedBytesRead: compressedReadBytes + ) + ); } - void IExtractionListener.FireFilePartExtractionBegin(string name, long size, long compressedSize) + void IExtractionListener.FireFilePartExtractionBegin( + string name, + long size, + long compressedSize + ) { - FilePartExtractionBegin?.Invoke(this, new FilePartExtractionBeginEventArgs( - compressedSize: compressedSize, - size: size, - name: name - )); + FilePartExtractionBegin?.Invoke( + this, + new FilePartExtractionBeginEventArgs( + compressedSize: compressedSize, + size: size, + name: name + ) + ); } - void IReaderExtractionListener.FireEntryExtractionProgress(Entry entry, long bytesTransferred, int iterations) + void IReaderExtractionListener.FireEntryExtractionProgress( + Entry entry, + long bytesTransferred, + int iterations + ) { - EntryExtractionProgress?.Invoke(this, new ReaderExtractionEventArgs(entry, new ReaderProgress(entry, bytesTransferred, iterations))); + EntryExtractionProgress?.Invoke( + this, + new ReaderExtractionEventArgs( + entry, + new ReaderProgress(entry, bytesTransferred, iterations) + ) + ); } } } diff --git a/src/SharpCompress/Readers/GZip/GZipReader.cs b/src/SharpCompress/Readers/GZip/GZipReader.cs index f4b889d0..d9a823f0 100644 --- a/src/SharpCompress/Readers/GZip/GZipReader.cs +++ b/src/SharpCompress/Readers/GZip/GZipReader.cs @@ -7,8 +7,7 @@ namespace SharpCompress.Readers.GZip { public class GZipReader : AbstractReader { - internal GZipReader(Stream stream, ReaderOptions options) - : base(options, ArchiveType.GZip) + internal GZipReader(Stream stream, ReaderOptions options) : base(options, ArchiveType.GZip) { Volume = new GZipVolume(stream, options); } diff --git a/src/SharpCompress/Readers/IReader.cs b/src/SharpCompress/Readers/IReader.cs index db11164d..a4beaa80 100644 --- a/src/SharpCompress/Readers/IReader.cs +++ b/src/SharpCompress/Readers/IReader.cs @@ -36,4 +36,4 @@ namespace SharpCompress.Readers /// EntryStream OpenEntryStream(); } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Readers/IReaderExtensions.cs b/src/SharpCompress/Readers/IReaderExtensions.cs index 502fc8ad..29f11ef1 100644 --- a/src/SharpCompress/Readers/IReaderExtensions.cs +++ b/src/SharpCompress/Readers/IReaderExtensions.cs @@ -24,8 +24,11 @@ namespace SharpCompress.Readers /// /// Extract all remaining unread entries to specific directory, retaining filename /// - public static void WriteAllToDirectory(this IReader reader, string destinationDirectory, - ExtractionOptions? options = null) + public static void WriteAllToDirectory( + this IReader reader, + string destinationDirectory, + ExtractionOptions? options = null + ) { while (reader.MoveToNextEntry()) { @@ -36,28 +39,41 @@ namespace SharpCompress.Readers /// /// Extract to specific directory, retaining filename /// - public static void WriteEntryToDirectory(this IReader reader, string destinationDirectory, - ExtractionOptions? options = null) + public static void WriteEntryToDirectory( + this IReader reader, + string destinationDirectory, + ExtractionOptions? options = null + ) { - ExtractionMethods.WriteEntryToDirectory(reader.Entry, destinationDirectory, options, - reader.WriteEntryToFile); + ExtractionMethods.WriteEntryToDirectory( + reader.Entry, + destinationDirectory, + options, + reader.WriteEntryToFile + ); } /// /// Extract to specific file /// - public static void WriteEntryToFile(this IReader reader, - string destinationFileName, - ExtractionOptions? options = null) + public static void WriteEntryToFile( + this IReader reader, + string destinationFileName, + ExtractionOptions? options = null + ) { - ExtractionMethods.WriteEntryToFile(reader.Entry, destinationFileName, options, - (x, fm) => - { - using (FileStream fs = File.Open(destinationFileName, fm)) - { - reader.WriteEntryTo(fs); - } - }); + ExtractionMethods.WriteEntryToFile( + reader.Entry, + destinationFileName, + options, + (x, fm) => + { + using (FileStream fs = File.Open(destinationFileName, fm)) + { + reader.WriteEntryTo(fs); + } + } + ); } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Readers/IReaderFactory.cs b/src/SharpCompress/Readers/IReaderFactory.cs index 1f6f7408..4587cca6 100644 --- a/src/SharpCompress/Readers/IReaderFactory.cs +++ b/src/SharpCompress/Readers/IReaderFactory.cs @@ -20,4 +20,3 @@ namespace SharpCompress.Readers IReader OpenReader(Stream stream, ReaderOptions? options); } } - diff --git a/src/SharpCompress/Readers/Rar/MultiVolumeRarReader.cs b/src/SharpCompress/Readers/Rar/MultiVolumeRarReader.cs index 6de11a24..4e857626 100644 --- a/src/SharpCompress/Readers/Rar/MultiVolumeRarReader.cs +++ b/src/SharpCompress/Readers/Rar/MultiVolumeRarReader.cs @@ -20,9 +20,7 @@ namespace SharpCompress.Readers.Rar this.streams = streams.GetEnumerator(); } - internal override void ValidateArchive(RarVolume archive) - { - } + internal override void ValidateArchive(RarVolume archive) { } protected override Stream RequestInitialStream() { @@ -30,7 +28,9 @@ namespace SharpCompress.Readers.Rar { return streams.Current; } - throw new MultiVolumeExtractionException("No stream provided when requested by MultiVolumeRarReader"); + throw new MultiVolumeExtractionException( + "No stream provided when requested by MultiVolumeRarReader" + ); } internal override bool NextEntryForCurrentStream() @@ -57,8 +57,11 @@ namespace SharpCompress.Readers.Rar private Stream tempStream; private bool isFirst = true; - internal MultiVolumeStreamEnumerator(MultiVolumeRarReader r, IEnumerator nextReadableStreams, - Stream tempStream) + internal MultiVolumeStreamEnumerator( + MultiVolumeRarReader r, + IEnumerator nextReadableStreams, + Stream tempStream + ) { reader = r; this.nextReadableStreams = nextReadableStreams; @@ -77,9 +80,7 @@ namespace SharpCompress.Readers.Rar public FilePart Current { get; private set; } - public void Dispose() - { - } + public void Dispose() { } object IEnumerator.Current => Current; @@ -103,7 +104,9 @@ namespace SharpCompress.Readers.Rar } else if (!nextReadableStreams.MoveNext()) { - throw new MultiVolumeExtractionException("No stream provided when requested by MultiVolumeRarReader"); + throw new MultiVolumeExtractionException( + "No stream provided when requested by MultiVolumeRarReader" + ); } else { @@ -114,9 +117,7 @@ namespace SharpCompress.Readers.Rar return true; } - public void Reset() - { - } + public void Reset() { } } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Readers/Rar/NonSeekableStreamFilePart.cs b/src/SharpCompress/Readers/Rar/NonSeekableStreamFilePart.cs index 76c9f201..5c545540 100644 --- a/src/SharpCompress/Readers/Rar/NonSeekableStreamFilePart.cs +++ b/src/SharpCompress/Readers/Rar/NonSeekableStreamFilePart.cs @@ -7,15 +7,14 @@ namespace SharpCompress.Readers.Rar internal class NonSeekableStreamFilePart : RarFilePart { internal NonSeekableStreamFilePart(MarkHeader mh, FileHeader fh, int index = 0) - : base(mh, fh, index) - { - } + : base(mh, fh, index) { } internal override Stream GetCompressedStream() { return FileHeader.PackedStream; } - internal override string FilePartName => "Unknown Stream - File Entry: " + FileHeader.FileName; + internal override string FilePartName => + "Unknown Stream - File Entry: " + FileHeader.FileName; } } diff --git a/src/SharpCompress/Readers/Rar/RarReader.cs b/src/SharpCompress/Readers/Rar/RarReader.cs index c51534bc..32bf4124 100644 --- a/src/SharpCompress/Readers/Rar/RarReader.cs +++ b/src/SharpCompress/Readers/Rar/RarReader.cs @@ -13,13 +13,12 @@ namespace SharpCompress.Readers.Rar public abstract class RarReader : AbstractReader { private RarVolume? volume; - internal Lazy UnpackV2017 { get; } = new Lazy(() => new SharpCompress.Compressors.Rar.UnpackV2017.Unpack()); - internal Lazy UnpackV1 { get; } = new Lazy(() => new SharpCompress.Compressors.Rar.UnpackV1.Unpack()); + internal Lazy UnpackV2017 { get; } = + new Lazy(() => new SharpCompress.Compressors.Rar.UnpackV2017.Unpack()); + internal Lazy UnpackV1 { get; } = + new Lazy(() => new SharpCompress.Compressors.Rar.UnpackV1.Unpack()); - internal RarReader(ReaderOptions options) - : base(options, ArchiveType.Rar) - { - } + internal RarReader(ReaderOptions options) : base(options, ArchiveType.Rar) { } internal abstract void ValidateArchive(RarVolume archive); @@ -66,10 +65,15 @@ namespace SharpCompress.Readers.Rar protected override EntryStream GetEntryStream() { - var stream = new MultiVolumeReadOnlyStream(CreateFilePartEnumerableForCurrentEntry().Cast(), this); + var stream = new MultiVolumeReadOnlyStream( + CreateFilePartEnumerableForCurrentEntry().Cast(), + this + ); if (Entry.IsRarV3) { - return CreateEntryStream(new RarCrcStream(UnpackV1.Value, Entry.FileHeader, stream)); + return CreateEntryStream( + new RarCrcStream(UnpackV1.Value, Entry.FileHeader, stream) + ); } return CreateEntryStream(new RarCrcStream(UnpackV2017.Value, Entry.FileHeader, stream)); } diff --git a/src/SharpCompress/Readers/Rar/RarReaderEntry.cs b/src/SharpCompress/Readers/Rar/RarReaderEntry.cs index 2e29d615..7a67392e 100644 --- a/src/SharpCompress/Readers/Rar/RarReaderEntry.cs +++ b/src/SharpCompress/Readers/Rar/RarReaderEntry.cs @@ -31,4 +31,4 @@ namespace SharpCompress.Readers.Rar /// public override long Size => Part.FileHeader.UncompressedSize; } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Readers/Rar/RarReaderVolume.cs b/src/SharpCompress/Readers/Rar/RarReaderVolume.cs index fa3bbdf1..61e73ecb 100644 --- a/src/SharpCompress/Readers/Rar/RarReaderVolume.cs +++ b/src/SharpCompress/Readers/Rar/RarReaderVolume.cs @@ -9,9 +9,7 @@ namespace SharpCompress.Readers.Rar public class RarReaderVolume : RarVolume { internal RarReaderVolume(Stream stream, ReaderOptions options, int index = 0) - : base(StreamingMode.Streaming, stream, options, index) - { - } + : base(StreamingMode.Streaming, stream, options, index) { } internal override RarFilePart CreateFilePart(MarkHeader markHeader, FileHeader fileHeader) { diff --git a/src/SharpCompress/Readers/Rar/SingleVolumeRarReader.cs b/src/SharpCompress/Readers/Rar/SingleVolumeRarReader.cs index 4d3cf411..45bf884b 100644 --- a/src/SharpCompress/Readers/Rar/SingleVolumeRarReader.cs +++ b/src/SharpCompress/Readers/Rar/SingleVolumeRarReader.cs @@ -8,8 +8,7 @@ namespace SharpCompress.Readers.Rar { private readonly Stream stream; - internal SingleVolumeRarReader(Stream stream, ReaderOptions options) - : base(options) + internal SingleVolumeRarReader(Stream stream, ReaderOptions options) : base(options) { this.stream = stream; } @@ -18,7 +17,8 @@ namespace SharpCompress.Readers.Rar { if (archive.IsMultiVolume) { - var msg = "Streamed archive is a Multi-volume archive. Use different RarReader method to extract."; + var msg = + "Streamed archive is a Multi-volume archive. Use different RarReader method to extract."; throw new MultiVolumeExtractionException(msg); } } @@ -28,4 +28,4 @@ namespace SharpCompress.Readers.Rar return stream; } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Readers/ReaderFactory.cs b/src/SharpCompress/Readers/ReaderFactory.cs index 5f75ed0d..d7e58f68 100644 --- a/src/SharpCompress/Readers/ReaderFactory.cs +++ b/src/SharpCompress/Readers/ReaderFactory.cs @@ -18,20 +18,23 @@ namespace SharpCompress.Readers public static IReader Open(Stream stream, ReaderOptions? options = null) { stream.CheckNotNull(nameof(stream)); - options = options ?? new ReaderOptions() - { - LeaveStreamOpen = false - }; + options = options ?? new ReaderOptions() { LeaveStreamOpen = false }; RewindableStream rewindableStream = new RewindableStream(stream); rewindableStream.StartRecording(); - foreach(var factory in Factories.Factory.Factories.OfType()) + foreach (var factory in Factories.Factory.Factories.OfType()) { - if (factory.TryOpenReader(rewindableStream, options, out var reader) && reader != null) return reader; - } + if ( + factory.TryOpenReader(rewindableStream, options, out var reader) + && reader != null + ) + return reader; + } - throw new InvalidOperationException("Cannot determine compressed stream type. Supported Reader Formats: Zip, GZip, BZip2, Tar, Rar, LZip, XZ"); + throw new InvalidOperationException( + "Cannot determine compressed stream type. Supported Reader Formats: Zip, GZip, BZip2, Tar, Rar, LZip, XZ" + ); } } } diff --git a/src/SharpCompress/Readers/ReaderOptions.cs b/src/SharpCompress/Readers/ReaderOptions.cs index 110b0c33..3891781d 100644 --- a/src/SharpCompress/Readers/ReaderOptions.cs +++ b/src/SharpCompress/Readers/ReaderOptions.cs @@ -13,4 +13,4 @@ namespace SharpCompress.Readers public bool DisableCheckIncomplete { get; set; } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Readers/ReaderProgress.cs b/src/SharpCompress/Readers/ReaderProgress.cs index 7b6f099d..794929dd 100644 --- a/src/SharpCompress/Readers/ReaderProgress.cs +++ b/src/SharpCompress/Readers/ReaderProgress.cs @@ -1,6 +1,4 @@ - - -using System; +using System; using SharpCompress.Common; namespace SharpCompress.Readers diff --git a/src/SharpCompress/Readers/Tar/TarReader.cs b/src/SharpCompress/Readers/Tar/TarReader.cs index a2b7ecc7..707c2e58 100644 --- a/src/SharpCompress/Readers/Tar/TarReader.cs +++ b/src/SharpCompress/Readers/Tar/TarReader.cs @@ -33,29 +33,29 @@ namespace SharpCompress.Readers.Tar switch (compressionType) { case CompressionType.BZip2: - { - return new BZip2Stream(stream, CompressionMode.Decompress, false); - } + { + return new BZip2Stream(stream, CompressionMode.Decompress, false); + } case CompressionType.GZip: - { - return new GZipStream(stream, CompressionMode.Decompress); - } + { + return new GZipStream(stream, CompressionMode.Decompress); + } case CompressionType.LZip: - { - return new LZipStream(stream, CompressionMode.Decompress); - } + { + return new LZipStream(stream, CompressionMode.Decompress); + } case CompressionType.Xz: - { - return new XZStream(stream); - } + { + return new XZStream(stream); + } case CompressionType.None: - { - return stream; - } + { + return stream; + } default: - { - throw new NotSupportedException("Invalid compression type: " + compressionType); - } + { + throw new NotSupportedException("Invalid compression type: " + compressionType); + } } } @@ -76,7 +76,10 @@ namespace SharpCompress.Readers.Tar if (GZipArchive.IsGZipFile(rewindableStream)) { rewindableStream.Rewind(false); - GZipStream testStream = new GZipStream(rewindableStream, CompressionMode.Decompress); + GZipStream testStream = new GZipStream( + rewindableStream, + CompressionMode.Decompress + ); if (TarArchive.IsTarFile(testStream)) { rewindableStream.Rewind(true); @@ -89,7 +92,11 @@ namespace SharpCompress.Readers.Tar if (BZip2Stream.IsBZip2(rewindableStream)) { rewindableStream.Rewind(false); - BZip2Stream testStream = new BZip2Stream(rewindableStream, CompressionMode.Decompress, false); + BZip2Stream testStream = new BZip2Stream( + rewindableStream, + CompressionMode.Decompress, + false + ); if (TarArchive.IsTarFile(testStream)) { rewindableStream.Rewind(true); @@ -102,7 +109,10 @@ namespace SharpCompress.Readers.Tar if (LZipStream.IsLZipFile(rewindableStream)) { rewindableStream.Rewind(false); - LZipStream testStream = new LZipStream(rewindableStream, CompressionMode.Decompress); + LZipStream testStream = new LZipStream( + rewindableStream, + CompressionMode.Decompress + ); if (TarArchive.IsTarFile(testStream)) { rewindableStream.Rewind(true); @@ -118,7 +128,12 @@ namespace SharpCompress.Readers.Tar protected override IEnumerable GetEntries(Stream stream) { - return TarEntry.GetEntries(StreamingMode.Streaming, stream, compressionType, Options.ArchiveEncoding); + return TarEntry.GetEntries( + StreamingMode.Streaming, + stream, + compressionType, + Options.ArchiveEncoding + ); } } } diff --git a/src/SharpCompress/Readers/Zip/ZipReader.cs b/src/SharpCompress/Readers/Zip/ZipReader.cs index 54a759b2..111b3860 100644 --- a/src/SharpCompress/Readers/Zip/ZipReader.cs +++ b/src/SharpCompress/Readers/Zip/ZipReader.cs @@ -10,11 +10,13 @@ namespace SharpCompress.Readers.Zip { private readonly StreamingZipHeaderFactory _headerFactory; - private ZipReader(Stream stream, ReaderOptions options) - : base(options, ArchiveType.Zip) + private ZipReader(Stream stream, ReaderOptions options) : base(options, ArchiveType.Zip) { Volume = new ZipVolume(stream, options); - _headerFactory = new StreamingZipHeaderFactory(options.Password, options.ArchiveEncoding); + _headerFactory = new StreamingZipHeaderFactory( + options.Password, + options.ArchiveEncoding + ); } public override ZipVolume Volume { get; } @@ -44,14 +46,17 @@ namespace SharpCompress.Readers.Zip switch (h.ZipHeaderType) { case ZipHeaderType.LocalEntry: + { - yield return new ZipEntry(new StreamingZipFilePart((LocalEntryHeader)h, stream)); + yield return new ZipEntry( + new StreamingZipFilePart((LocalEntryHeader)h, stream) + ); } break; case ZipHeaderType.DirectoryEnd: - { - yield break; - } + { + yield break; + } } } } diff --git a/src/SharpCompress/Utility.cs b/src/SharpCompress/Utility.cs index 3d6f3c58..ff059ae6 100644 --- a/src/SharpCompress/Utility.cs +++ b/src/SharpCompress/Utility.cs @@ -69,7 +69,13 @@ namespace SharpCompress } } - public static void Copy(Array sourceArray, long sourceIndex, Array destinationArray, long destinationIndex, long length) + public static void Copy( + Array sourceArray, + long sourceIndex, + Array destinationArray, + long destinationIndex, + long length + ) { if (sourceIndex > Int32.MaxValue || sourceIndex < Int32.MinValue) { @@ -86,7 +92,13 @@ namespace SharpCompress throw new ArgumentOutOfRangeException(nameof(length)); } - Array.Copy(sourceArray, (int)sourceIndex, destinationArray, (int)destinationIndex, (int)length); + Array.Copy( + sourceArray, + (int)sourceIndex, + destinationArray, + (int)destinationIndex, + (int)length + ); } public static IEnumerable AsEnumerable(this T item) @@ -141,8 +153,7 @@ namespace SharpCompress { break; } - } - while (true); + } while (true); } finally { @@ -155,10 +166,7 @@ namespace SharpCompress byte[] buffer = GetTransferByteArray(); try { - do - { - } - while (source.Read(buffer, 0, buffer.Length) == buffer.Length); + do { } while (source.Read(buffer, 0, buffer.Length) == buffer.Length); } finally { @@ -183,13 +191,12 @@ namespace SharpCompress count++; if (count == array.Length) { - source.Position = source.Position - len + i - array.Length +1; + source.Position = source.Position - len + i - array.Length + 1; return true; } } } - } - while ((len = source.Read(buffer, 0, buffer.Length)) > 0); + } while ((len = source.Read(buffer, 0, buffer.Length)) > 0); } finally { @@ -242,15 +249,18 @@ namespace SharpCompress var localDateTime = dateTime.Value.ToLocalTime(); return (uint)( - (localDateTime.Second / 2) | (localDateTime.Minute << 5) | (localDateTime.Hour << 11) | - (localDateTime.Day << 16) | (localDateTime.Month << 21) | - ((localDateTime.Year - 1980) << 25)); + (localDateTime.Second / 2) + | (localDateTime.Minute << 5) + | (localDateTime.Hour << 11) + | (localDateTime.Day << 16) + | (localDateTime.Month << 21) + | ((localDateTime.Year - 1980) << 25) + ); } public static DateTime DosDateToDateTime(UInt32 iTime) { - return DosDateToDateTime((UInt16)(iTime / 65536), - (UInt16)(iTime % 65536)); + return DosDateToDateTime((UInt16)(iTime / 65536), (UInt16)(iTime % 65536)); } /// @@ -283,7 +293,12 @@ namespace SharpCompress } } - public static long TransferTo(this Stream source, Stream destination, Common.Entry entry, IReaderExtractionListener readerExtractionListener) + public static long TransferTo( + this Stream source, + Stream destination, + Common.Entry entry, + IReaderExtractionListener readerExtractionListener + ) { byte[] array = GetTransferByteArray(); try @@ -357,10 +372,10 @@ namespace SharpCompress /// Return the new UINT32 in the other endianness format public static UInt32 SwapUINT32(UInt32 number) { - return (number >> 24) | - ((number << 8) & 0x00FF0000) | - ((number >> 8) & 0x0000FF00) | - (number << 24); + return (number >> 24) + | ((number << 8) & 0x00FF0000) + | ((number >> 8) & 0x0000FF00) + | (number << 24); } /// diff --git a/src/SharpCompress/Writers/AbstractWriter.cs b/src/SharpCompress/Writers/AbstractWriter.cs index fad9bd1e..0c910f69 100644 --- a/src/SharpCompress/Writers/AbstractWriter.cs +++ b/src/SharpCompress/Writers/AbstractWriter.cs @@ -56,4 +56,4 @@ namespace SharpCompress.Writers } } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Writers/GZip/GZipWriter.cs b/src/SharpCompress/Writers/GZip/GZipWriter.cs index 12e820a2..b7d32ed2 100644 --- a/src/SharpCompress/Writers/GZip/GZipWriter.cs +++ b/src/SharpCompress/Writers/GZip/GZipWriter.cs @@ -18,9 +18,14 @@ namespace SharpCompress.Writers.GZip { destination = NonDisposingStream.Create(destination); } - InitalizeStream(new GZipStream(destination, CompressionMode.Compress, - options?.CompressionLevel ?? CompressionLevel.Default, - WriterOptions.ArchiveEncoding.GetEncoding())); + InitalizeStream( + new GZipStream( + destination, + CompressionMode.Compress, + options?.CompressionLevel ?? CompressionLevel.Default, + WriterOptions.ArchiveEncoding.GetEncoding() + ) + ); } protected override void Dispose(bool isDisposing) diff --git a/src/SharpCompress/Writers/GZip/GZipWriterOptions.cs b/src/SharpCompress/Writers/GZip/GZipWriterOptions.cs index b6966e16..cef2744a 100644 --- a/src/SharpCompress/Writers/GZip/GZipWriterOptions.cs +++ b/src/SharpCompress/Writers/GZip/GZipWriterOptions.cs @@ -5,13 +5,9 @@ namespace SharpCompress.Writers.GZip { public class GZipWriterOptions : WriterOptions { - public GZipWriterOptions() - : base(CompressionType.GZip) - { - } + public GZipWriterOptions() : base(CompressionType.GZip) { } - internal GZipWriterOptions(WriterOptions options) - : base(options.CompressionType) + internal GZipWriterOptions(WriterOptions options) : base(options.CompressionType) { LeaveStreamOpen = options.LeaveStreamOpen; ArchiveEncoding = options.ArchiveEncoding; @@ -25,4 +21,4 @@ namespace SharpCompress.Writers.GZip public CompressionLevel CompressionLevel { get; set; } = CompressionLevel.Default; } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Writers/IWriter.cs b/src/SharpCompress/Writers/IWriter.cs index a15225bf..0c8cb5ab 100644 --- a/src/SharpCompress/Writers/IWriter.cs +++ b/src/SharpCompress/Writers/IWriter.cs @@ -9,4 +9,4 @@ namespace SharpCompress.Writers ArchiveType WriterType { get; } void Write(string filename, Stream source, DateTime? modificationTime); } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Writers/IWriterExtensions.cs b/src/SharpCompress/Writers/IWriterExtensions.cs index 5fc1c82d..9335c46e 100644 --- a/src/SharpCompress/Writers/IWriterExtensions.cs +++ b/src/SharpCompress/Writers/IWriterExtensions.cs @@ -29,16 +29,23 @@ namespace SharpCompress.Writers writer.Write(entryPath, new FileInfo(source)); } - public static void WriteAll(this IWriter writer, string directory, string searchPattern = "*", SearchOption option = SearchOption.TopDirectoryOnly) + public static void WriteAll( + this IWriter writer, + string directory, + string searchPattern = "*", + SearchOption option = SearchOption.TopDirectoryOnly + ) { writer.WriteAll(directory, searchPattern, null, option); } - public static void WriteAll(this IWriter writer, - string directory, - string searchPattern = "*", - Func? fileSearchFunc = null, - SearchOption option = SearchOption.TopDirectoryOnly) + public static void WriteAll( + this IWriter writer, + string directory, + string searchPattern = "*", + Func? fileSearchFunc = null, + SearchOption option = SearchOption.TopDirectoryOnly + ) { if (!Directory.Exists(directory)) { @@ -49,7 +56,11 @@ namespace SharpCompress.Writers { fileSearchFunc = n => true; } - foreach (var file in Directory.EnumerateFiles(directory, searchPattern, option).Where(fileSearchFunc)) + foreach ( + var file in Directory + .EnumerateFiles(directory, searchPattern, option) + .Where(fileSearchFunc) + ) { writer.Write(file.Substring(directory.Length), file); } diff --git a/src/SharpCompress/Writers/Tar/TarWriter.cs b/src/SharpCompress/Writers/Tar/TarWriter.cs index c90e069e..b6b4da5c 100644 --- a/src/SharpCompress/Writers/Tar/TarWriter.cs +++ b/src/SharpCompress/Writers/Tar/TarWriter.cs @@ -32,24 +32,29 @@ namespace SharpCompress.Writers.Tar case CompressionType.None: break; case CompressionType.BZip2: + { destination = new BZip2Stream(destination, CompressionMode.Compress, false); } break; case CompressionType.GZip: + { destination = new GZipStream(destination, CompressionMode.Compress); } break; case CompressionType.LZip: + { destination = new LZipStream(destination, CompressionMode.Compress); } break; default: - { - throw new InvalidFormatException("Tar does not support compression: " + options.CompressionType); - } + { + throw new InvalidFormatException( + "Tar does not support compression: " + options.CompressionType + ); + } } InitalizeStream(destination); } @@ -110,15 +115,15 @@ namespace SharpCompress.Writers.Tar switch (OutputStream) { case BZip2Stream b: - { - b.Finish(); - break; - } + { + b.Finish(); + break; + } case LZipStream l: - { - l.Finish(); - break; - } + { + l.Finish(); + break; + } } } base.Dispose(isDisposing); diff --git a/src/SharpCompress/Writers/Tar/TarWriterOptions.cs b/src/SharpCompress/Writers/Tar/TarWriterOptions.cs index 752d95cb..f3cc26db 100755 --- a/src/SharpCompress/Writers/Tar/TarWriterOptions.cs +++ b/src/SharpCompress/Writers/Tar/TarWriterOptions.cs @@ -20,4 +20,4 @@ namespace SharpCompress.Writers.Tar ArchiveEncoding = options.ArchiveEncoding; } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Writers/WriterFactory.cs b/src/SharpCompress/Writers/WriterFactory.cs index 60aa613c..cd7102c5 100644 --- a/src/SharpCompress/Writers/WriterFactory.cs +++ b/src/SharpCompress/Writers/WriterFactory.cs @@ -8,10 +8,13 @@ namespace SharpCompress.Writers { public static class WriterFactory { - public static IWriter Open(Stream stream, ArchiveType archiveType, WriterOptions writerOptions) + public static IWriter Open( + Stream stream, + ArchiveType archiveType, + WriterOptions writerOptions + ) { - var factory = Factories.Factory - .Factories + var factory = Factories.Factory.Factories .OfType() .FirstOrDefault(item => item.KnownArchiveType == archiveType); diff --git a/src/SharpCompress/Writers/WriterOptions.cs b/src/SharpCompress/Writers/WriterOptions.cs index db1e2ffa..db3b83c7 100644 --- a/src/SharpCompress/Writers/WriterOptions.cs +++ b/src/SharpCompress/Writers/WriterOptions.cs @@ -8,6 +8,7 @@ namespace SharpCompress.Writers { CompressionType = compressionType; } + public CompressionType CompressionType { get; set; } public static implicit operator WriterOptions(CompressionType compressionType) @@ -15,4 +16,4 @@ namespace SharpCompress.Writers return new WriterOptions(compressionType); } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Writers/Zip/ZipCentralDirectoryEntry.cs b/src/SharpCompress/Writers/Zip/ZipCentralDirectoryEntry.cs index d4609ef6..de54e622 100644 --- a/src/SharpCompress/Writers/Zip/ZipCentralDirectoryEntry.cs +++ b/src/SharpCompress/Writers/Zip/ZipCentralDirectoryEntry.cs @@ -14,7 +14,12 @@ namespace SharpCompress.Writers.Zip private readonly string fileName; private readonly ArchiveEncoding archiveEncoding; - public ZipCentralDirectoryEntry(ZipCompressionMethod compression, string fileName, ulong headerOffset, ArchiveEncoding archiveEncoding) + public ZipCentralDirectoryEntry( + ZipCompressionMethod compression, + string fileName, + ulong headerOffset, + ArchiveEncoding archiveEncoding + ) { this.compression = compression; this.fileName = fileName; @@ -45,7 +50,9 @@ namespace SharpCompress.Writers.Zip var extralength = zip64 ? (2 + 2 + 8 + 8 + 8 + 4) : 0; var version = (byte)(zip64 ? 45 : 20); // Version 20 required for deflate/encryption - HeaderFlags flags = Equals(archiveEncoding.GetEncoding(), Encoding.UTF8) ? HeaderFlags.Efs : HeaderFlags.None; + HeaderFlags flags = Equals(archiveEncoding.GetEncoding(), Encoding.UTF8) + ? HeaderFlags.Efs + : HeaderFlags.None; if (!outputStream.CanSeek) { // Cannot use data descriptors with zip64: @@ -143,8 +150,26 @@ namespace SharpCompress.Writers.Zip outputStream.Write(encodedComment, 0, encodedComment.Length); - return (uint)(8 + 2 + 2 + 4 + 4 + 4 + 4 + 2 + 2 + 2 - + 2 + 2 + 2 + 2 + 4 + encodedFilename.Length + extralength + encodedComment.Length); + return (uint)( + 8 + + 2 + + 2 + + 4 + + 4 + + 4 + + 4 + + 2 + + 2 + + 2 + + 2 + + 2 + + 2 + + 2 + + 4 + + encodedFilename.Length + + extralength + + encodedComment.Length + ); } } } diff --git a/src/SharpCompress/Writers/Zip/ZipWriter.cs b/src/SharpCompress/Writers/Zip/ZipWriter.cs index 7ee74e19..fb04e7a4 100644 --- a/src/SharpCompress/Writers/Zip/ZipWriter.cs +++ b/src/SharpCompress/Writers/Zip/ZipWriter.cs @@ -19,7 +19,8 @@ namespace SharpCompress.Writers.Zip { private readonly CompressionType compressionType; private readonly CompressionLevel compressionLevel; - private readonly List entries = new List(); + private readonly List entries = + new List(); private readonly string zipComment; private long streamPosition; private PpmdProperties? ppmdProps; @@ -47,10 +48,7 @@ namespace SharpCompress.Writers.Zip private PpmdProperties PpmdProperties { - get - { - return ppmdProps ??= new PpmdProperties(); - } + get { return ppmdProps ??= new PpmdProperties(); } } protected override void Dispose(bool isDisposing) @@ -72,39 +70,46 @@ namespace SharpCompress.Writers.Zip switch (compressionType) { case CompressionType.None: - { - return ZipCompressionMethod.None; - } + { + return ZipCompressionMethod.None; + } case CompressionType.Deflate: - { - return ZipCompressionMethod.Deflate; - } + { + return ZipCompressionMethod.Deflate; + } case CompressionType.BZip2: - { - return ZipCompressionMethod.BZip2; - } + { + return ZipCompressionMethod.BZip2; + } case CompressionType.LZMA: - { - return ZipCompressionMethod.LZMA; - } + { + return ZipCompressionMethod.LZMA; + } case CompressionType.PPMd: - { - return ZipCompressionMethod.PPMd; - } + { + return ZipCompressionMethod.PPMd; + } default: - throw new InvalidFormatException("Invalid compression method: " + compressionType); + throw new InvalidFormatException( + "Invalid compression method: " + compressionType + ); } } public override void Write(string entryPath, Stream source, DateTime? modificationTime) { - Write(entryPath, source, new ZipWriterEntryOptions() - { - ModificationDateTime = modificationTime - }); + Write( + entryPath, + source, + new ZipWriterEntryOptions() { ModificationDateTime = modificationTime } + ); } - public void Write(string entryPath, Stream source, ZipWriterEntryOptions zipWriterEntryOptions) + public void Write( + string entryPath, + Stream source, + ZipWriterEntryOptions zipWriterEntryOptions + ) { using (Stream output = WriteToStream(entryPath, zipWriterEntryOptions)) { @@ -119,7 +124,12 @@ namespace SharpCompress.Writers.Zip entryPath = NormalizeFilename(entryPath); options.ModificationDateTime ??= DateTime.Now; options.EntryComment ??= string.Empty; - var entry = new ZipCentralDirectoryEntry(compression, entryPath, (ulong)streamPosition, WriterOptions.ArchiveEncoding) + var entry = new ZipCentralDirectoryEntry( + compression, + entryPath, + (ulong)streamPosition, + WriterOptions.ArchiveEncoding + ) { Comment = options.EntryComment, ModificationTime = options.ModificationDateTime @@ -134,8 +144,13 @@ namespace SharpCompress.Writers.Zip var headersize = (uint)WriteHeader(entryPath, options, entry, useZip64); streamPosition += headersize; - return new ZipWritingStream(this, OutputStream, entry, compression, - options.DeflateCompressionLevel ?? compressionLevel); + return new ZipWritingStream( + this, + OutputStream, + entry, + compression, + options.DeflateCompressionLevel ?? compressionLevel + ); } private string NormalizeFilename(string filename) @@ -151,15 +166,24 @@ namespace SharpCompress.Writers.Zip return filename.Trim('/'); } - private int WriteHeader(string filename, ZipWriterEntryOptions zipWriterEntryOptions, ZipCentralDirectoryEntry entry, bool useZip64) + private int WriteHeader( + string filename, + ZipWriterEntryOptions zipWriterEntryOptions, + ZipCentralDirectoryEntry entry, + bool useZip64 + ) { // We err on the side of caution until the zip specification clarifies how to support this if (!OutputStream.CanSeek && useZip64) { - throw new NotSupportedException("Zip64 extensions are not supported on non-seekable streams"); + throw new NotSupportedException( + "Zip64 extensions are not supported on non-seekable streams" + ); } - var explicitZipCompressionInfo = ToZipCompressionMethod(zipWriterEntryOptions.CompressionType ?? compressionType); + var explicitZipCompressionInfo = ToZipCompressionMethod( + zipWriterEntryOptions.CompressionType ?? compressionType + ); byte[] encodedFilename = WriterOptions.ArchiveEncoding.Encode(filename); Span intBuf = stackalloc byte[4]; @@ -180,7 +204,9 @@ namespace SharpCompress.Writers.Zip { OutputStream.Write(stackalloc byte[] { 63, 0 }); //version says we used PPMd or LZMA } - HeaderFlags flags = Equals(WriterOptions.ArchiveEncoding.GetEncoding(), Encoding.UTF8) ? HeaderFlags.Efs : 0; + HeaderFlags flags = Equals(WriterOptions.ArchiveEncoding.GetEncoding(), Encoding.UTF8) + ? HeaderFlags.Efs + : 0; if (!OutputStream.CanSeek) { flags |= HeaderFlags.UsePostDataDescriptor; @@ -195,7 +221,10 @@ namespace SharpCompress.Writers.Zip OutputStream.Write(intBuf.Slice(0, 2)); BinaryPrimitives.WriteUInt16LittleEndian(intBuf, (ushort)explicitZipCompressionInfo); OutputStream.Write(intBuf.Slice(0, 2)); // zipping method - BinaryPrimitives.WriteUInt32LittleEndian(intBuf, zipWriterEntryOptions.ModificationDateTime.DateTimeToDosTime()); + BinaryPrimitives.WriteUInt32LittleEndian( + intBuf, + zipWriterEntryOptions.ModificationDateTime.DateTimeToDosTime() + ); OutputStream.Write(intBuf); // zipping date and time @@ -218,7 +247,9 @@ namespace SharpCompress.Writers.Zip if (extralength != 0) { OutputStream.Write(new byte[extralength], 0, extralength); // reserve space for zip64 data - entry.Zip64HeaderOffset = (ushort)(6 + 2 + 2 + 4 + 12 + 2 + 2 + encodedFilename.Length); + entry.Zip64HeaderOffset = (ushort)( + 6 + 2 + 2 + 4 + 12 + 2 + 2 + encodedFilename.Length + ); } return 6 + 2 + 2 + 4 + 12 + 2 + 2 + encodedFilename.Length + extralength; @@ -237,11 +268,14 @@ namespace SharpCompress.Writers.Zip private void WriteEndRecord(ulong size) { - - var zip64EndOfCentralDirectoryNeeded = entries.Count > ushort.MaxValue || streamPosition >= uint.MaxValue || size >= uint.MaxValue; + var zip64EndOfCentralDirectoryNeeded = + entries.Count > ushort.MaxValue + || streamPosition >= uint.MaxValue + || size >= uint.MaxValue; var sizevalue = size >= uint.MaxValue ? uint.MaxValue : (uint)size; - var streampositionvalue = streamPosition >= uint.MaxValue ? uint.MaxValue : (uint)streamPosition; + var streampositionvalue = + streamPosition >= uint.MaxValue ? uint.MaxValue : (uint)streamPosition; Span intBuf = stackalloc byte[8]; if (zip64EndOfCentralDirectoryNeeded) @@ -317,8 +351,13 @@ namespace SharpCompress.Writers.Zip private bool limitsExceeded; private bool isDisposed; - internal ZipWritingStream(ZipWriter writer, Stream originalStream, ZipCentralDirectoryEntry entry, - ZipCompressionMethod zipCompressionMethod, CompressionLevel compressionLevel) + internal ZipWritingStream( + ZipWriter writer, + Stream originalStream, + ZipCentralDirectoryEntry entry, + ZipCompressionMethod zipCompressionMethod, + CompressionLevel compressionLevel + ) { this.writer = writer; this.originalStream = originalStream; @@ -337,7 +376,11 @@ namespace SharpCompress.Writers.Zip public override long Length => throw new NotSupportedException(); - public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); } + public override long Position + { + get => throw new NotSupportedException(); + set => throw new NotSupportedException(); + } private Stream GetWriteStream(Stream writeStream) { @@ -346,38 +389,47 @@ namespace SharpCompress.Writers.Zip switch (zipCompressionMethod) { case ZipCompressionMethod.None: - { - return output; - } + { + return output; + } case ZipCompressionMethod.Deflate: - { - return new DeflateStream(counting, CompressionMode.Compress, compressionLevel); - } + { + return new DeflateStream( + counting, + CompressionMode.Compress, + compressionLevel + ); + } case ZipCompressionMethod.BZip2: - { - return new BZip2Stream(counting, CompressionMode.Compress, false); - } + { + return new BZip2Stream(counting, CompressionMode.Compress, false); + } case ZipCompressionMethod.LZMA: - { - counting.WriteByte(9); - counting.WriteByte(20); - counting.WriteByte(5); - counting.WriteByte(0); + { + counting.WriteByte(9); + counting.WriteByte(20); + counting.WriteByte(5); + counting.WriteByte(0); - LzmaStream lzmaStream = new LzmaStream(new LzmaEncoderProperties(!originalStream.CanSeek), - false, counting); - counting.Write(lzmaStream.Properties, 0, lzmaStream.Properties.Length); - return lzmaStream; - } + LzmaStream lzmaStream = new LzmaStream( + new LzmaEncoderProperties(!originalStream.CanSeek), + false, + counting + ); + counting.Write(lzmaStream.Properties, 0, lzmaStream.Properties.Length); + return lzmaStream; + } case ZipCompressionMethod.PPMd: - { - counting.Write(writer.PpmdProperties.Properties, 0, 2); - return new PpmdStream(writer.PpmdProperties, counting, true); - } + { + counting.Write(writer.PpmdProperties.Properties, 0, 2); + return new PpmdStream(writer.PpmdProperties, counting, true); + } default: - { - throw new NotSupportedException("CompressionMethod: " + zipCompressionMethod); - } + { + throw new NotSupportedException( + "CompressionMethod: " + zipCompressionMethod + ); + } } } @@ -408,7 +460,8 @@ namespace SharpCompress.Writers.Zip entry.Compressed = counting!.Count; entry.Decompressed = decompressed; - var zip64 = entry.Compressed >= uint.MaxValue || entry.Decompressed >= uint.MaxValue; + var zip64 = + entry.Compressed >= uint.MaxValue || entry.Decompressed >= uint.MaxValue; var compressedvalue = zip64 ? uint.MaxValue : (uint)counting.Count; var decompressedvalue = zip64 ? uint.MaxValue : (uint)entry.Decompressed; @@ -433,14 +486,18 @@ namespace SharpCompress.Writers.Zip // We should not get here as the Write call checks the limits if (zip64 && entry.Zip64HeaderOffset == 0) { - throw new NotSupportedException("Attempted to write a stream that is larger than 4GiB without setting the zip64 option"); + throw new NotSupportedException( + "Attempted to write a stream that is larger than 4GiB without setting the zip64 option" + ); } // If we have pre-allocated space for zip64 data, // fill it out, even if it is not required if (entry.Zip64HeaderOffset != 0) { - originalStream.Position = (long)(entry.HeaderOffset + entry.Zip64HeaderOffset); + originalStream.Position = (long)( + entry.HeaderOffset + entry.Zip64HeaderOffset + ); Span intBuf = stackalloc byte[8]; BinaryPrimitives.WriteUInt16LittleEndian(intBuf, 0x0001); originalStream.Write(intBuf.Slice(0, 2)); @@ -466,15 +523,18 @@ namespace SharpCompress.Writers.Zip // We should not get here as the Write call checks the limits if (zip64) { - throw new NotSupportedException("Streams larger than 4GiB are not supported for non-seekable streams"); + throw new NotSupportedException( + "Streams larger than 4GiB are not supported for non-seekable streams" + ); } Span intBuf = stackalloc byte[4]; - BinaryPrimitives.WriteUInt32LittleEndian(intBuf, ZipHeaderFactory.POST_DATA_DESCRIPTOR); + BinaryPrimitives.WriteUInt32LittleEndian( + intBuf, + ZipHeaderFactory.POST_DATA_DESCRIPTOR + ); originalStream.Write(intBuf); - writer.WriteFooter(entry.Crc, - compressedvalue, - decompressedvalue); + writer.WriteFooter(entry.Crc, compressedvalue, decompressedvalue); writer.streamPosition += (long)entry.Compressed + 16; } writer.entries.Add(entry); @@ -508,9 +568,15 @@ namespace SharpCompress.Writers.Zip if (entry.Zip64HeaderOffset == 0) { // Pre-check, the counting.Count is not exact, as we do not know the size before having actually compressed it - if (limitsExceeded || ((decompressed + (uint)count) > uint.MaxValue) || (counting!.Count + (uint)count) > uint.MaxValue) + if ( + limitsExceeded + || ((decompressed + (uint)count) > uint.MaxValue) + || (counting!.Count + (uint)count) > uint.MaxValue + ) { - throw new NotSupportedException("Attempted to write a stream that is larger than 4GiB without setting the zip64 option"); + throw new NotSupportedException( + "Attempted to write a stream that is larger than 4GiB without setting the zip64 option" + ); } } @@ -528,7 +594,9 @@ namespace SharpCompress.Writers.Zip // throwing an exception in Dispose() which is discouraged // as it can mask other errors limitsExceeded = true; - throw new NotSupportedException("Attempted to write a stream that is larger than 4GiB without setting the zip64 option"); + throw new NotSupportedException( + "Attempted to write a stream that is larger than 4GiB without setting the zip64 option" + ); } } } diff --git a/src/SharpCompress/Writers/Zip/ZipWriterEntryOptions.cs b/src/SharpCompress/Writers/Zip/ZipWriterEntryOptions.cs index e1ef77bf..0f4e8886 100644 --- a/src/SharpCompress/Writers/Zip/ZipWriterEntryOptions.cs +++ b/src/SharpCompress/Writers/Zip/ZipWriterEntryOptions.cs @@ -7,6 +7,7 @@ namespace SharpCompress.Writers.Zip public class ZipWriterEntryOptions { public CompressionType? CompressionType { get; set; } + /// /// When CompressionType.Deflate is used, this property is referenced. Defaults to CompressionLevel.Default. /// @@ -18,10 +19,10 @@ namespace SharpCompress.Writers.Zip /// /// Allocate an extra 20 bytes for this entry to store, - /// 64 bit length values, thus enabling streams - /// larger than 4GiB. - /// This option is not supported with non-seekable streams. + /// 64 bit length values, thus enabling streams + /// larger than 4GiB. + /// This option is not supported with non-seekable streams. /// public bool? EnableZip64 { get; set; } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Writers/Zip/ZipWriterOptions.cs b/src/SharpCompress/Writers/Zip/ZipWriterOptions.cs index 969e2349..e1758896 100644 --- a/src/SharpCompress/Writers/Zip/ZipWriterOptions.cs +++ b/src/SharpCompress/Writers/Zip/ZipWriterOptions.cs @@ -5,13 +5,9 @@ namespace SharpCompress.Writers.Zip { public class ZipWriterOptions : WriterOptions { - public ZipWriterOptions(CompressionType compressionType) - : base(compressionType) - { - } + public ZipWriterOptions(CompressionType compressionType) : base(compressionType) { } - internal ZipWriterOptions(WriterOptions options) - : base(options.CompressionType) + internal ZipWriterOptions(WriterOptions options) : base(options.CompressionType) { LeaveStreamOpen = options.LeaveStreamOpen; ArchiveEncoding = options.ArchiveEncoding; @@ -24,6 +20,7 @@ namespace SharpCompress.Writers.Zip ArchiveComment = writerOptions.ArchiveComment; } } + /// /// When CompressionType.Deflate is used, this property is referenced. Defaults to CompressionLevel.Default. /// @@ -32,12 +29,12 @@ namespace SharpCompress.Writers.Zip public string? ArchiveComment { get; set; } /// - /// Sets a value indicating if zip64 support is enabled. - /// If this is not set, individual stream lengths cannot exceed 4 GiB. - /// This option is not supported for non-seekable streams. - /// Archives larger than 4GiB are supported as long as all streams - /// are less than 4GiB in length. + /// Sets a value indicating if zip64 support is enabled. + /// If this is not set, individual stream lengths cannot exceed 4 GiB. + /// This option is not supported for non-seekable streams. + /// Archives larger than 4GiB are supported as long as all streams + /// are less than 4GiB in length. /// public bool UseZip64 { get; set; } } -} \ No newline at end of file +} diff --git a/tests/SharpCompress.Test/ADCTest.cs b/tests/SharpCompress.Test/ADCTest.cs index 039260c4..4be158d1 100644 --- a/tests/SharpCompress.Test/ADCTest.cs +++ b/tests/SharpCompress.Test/ADCTest.cs @@ -37,12 +37,20 @@ namespace SharpCompress.Test [Fact] public void TestBuffer() { - using (FileStream decFs = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "adc_decompressed.bin"))) + using ( + FileStream decFs = File.OpenRead( + Path.Combine(TEST_ARCHIVES_PATH, "adc_decompressed.bin") + ) + ) { byte[] decompressed = new byte[decFs.Length]; decFs.Read(decompressed, 0, decompressed.Length); - using (FileStream cmpFs = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "adc_compressed.bin"))) + using ( + FileStream cmpFs = File.OpenRead( + Path.Combine(TEST_ARCHIVES_PATH, "adc_compressed.bin") + ) + ) { byte[] compressed = new byte[cmpFs.Length]; cmpFs.Read(compressed, 0, compressed.Length); @@ -58,12 +66,20 @@ namespace SharpCompress.Test [Fact] public void TestBaseStream() { - using (FileStream decFs = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "adc_decompressed.bin"))) + using ( + FileStream decFs = File.OpenRead( + Path.Combine(TEST_ARCHIVES_PATH, "adc_decompressed.bin") + ) + ) { byte[] decompressed = new byte[decFs.Length]; decFs.Read(decompressed, 0, decompressed.Length); - using (FileStream cmpFs = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "adc_compressed.bin"))) + using ( + FileStream cmpFs = File.OpenRead( + Path.Combine(TEST_ARCHIVES_PATH, "adc_compressed.bin") + ) + ) { byte[]? test; @@ -77,12 +93,20 @@ namespace SharpCompress.Test [Fact] public void TestADCStreamWholeChunk() { - using (FileStream decFs = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "adc_decompressed.bin"))) + using ( + FileStream decFs = File.OpenRead( + Path.Combine(TEST_ARCHIVES_PATH, "adc_decompressed.bin") + ) + ) { byte[] decompressed = new byte[decFs.Length]; decFs.Read(decompressed, 0, decompressed.Length); - using (FileStream cmpFs = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "adc_compressed.bin"))) + using ( + FileStream cmpFs = File.OpenRead( + Path.Combine(TEST_ARCHIVES_PATH, "adc_compressed.bin") + ) + ) { using (ADCStream decStream = new ADCStream(cmpFs, CompressionMode.Decompress)) { @@ -99,12 +123,20 @@ namespace SharpCompress.Test [Fact] public void TestADCStream() { - using (FileStream decFs = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "adc_decompressed.bin"))) + using ( + FileStream decFs = File.OpenRead( + Path.Combine(TEST_ARCHIVES_PATH, "adc_decompressed.bin") + ) + ) { byte[] decompressed = new byte[decFs.Length]; decFs.Read(decompressed, 0, decompressed.Length); - using (FileStream cmpFs = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "adc_compressed.bin"))) + using ( + FileStream cmpFs = File.OpenRead( + Path.Combine(TEST_ARCHIVES_PATH, "adc_compressed.bin") + ) + ) { using (ADCStream decStream = new ADCStream(cmpFs, CompressionMode.Decompress)) { @@ -117,8 +149,7 @@ namespace SharpCompress.Test { count = decStream.Read(test, 0, test.Length); decMs.Write(test, 0, count); - } - while (count > 0); + } while (count > 0); Assert.Equal(decompressed, decMs.ToArray()); } diff --git a/tests/SharpCompress.Test/ArchiveTests.cs b/tests/SharpCompress.Test/ArchiveTests.cs index d93455c0..dcf033ca 100644 --- a/tests/SharpCompress.Test/ArchiveTests.cs +++ b/tests/SharpCompress.Test/ArchiveTests.cs @@ -27,8 +27,10 @@ namespace SharpCompress.Test ArchiveStreamReadExtractAll(new[] { testArchive }, compression); } - - protected void ArchiveStreamReadExtractAll(IEnumerable testArchives, CompressionType compression) + protected void ArchiveStreamReadExtractAll( + IEnumerable testArchives, + CompressionType compression + ) { foreach (var path in testArchives) { @@ -50,14 +52,18 @@ namespace SharpCompress.Test stream.ThrowOnDispose = false; return; } - foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) + foreach ( + var entry in archive.Entries.Where(entry => !entry.IsDirectory) + ) { - entry.WriteToDirectory(SCRATCH_FILES_PATH, - new ExtractionOptions - { - ExtractFullPath = true, - Overwrite = true - }); + entry.WriteToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions + { + ExtractFullPath = true, + Overwrite = true + } + ); } stream.ThrowOnDispose = false; } @@ -79,12 +85,21 @@ namespace SharpCompress.Test ArchiveStreamRead(readerOptions, testArchive); } - protected void ArchiveStreamRead(ReaderOptions? readerOptions = null, params string[] testArchives) + protected void ArchiveStreamRead( + ReaderOptions? readerOptions = null, + params string[] testArchives + ) { - ArchiveStreamRead(readerOptions, testArchives.Select(x => Path.Combine(TEST_ARCHIVES_PATH, x))); + ArchiveStreamRead( + readerOptions, + testArchives.Select(x => Path.Combine(TEST_ARCHIVES_PATH, x)) + ); } - protected void ArchiveStreamRead(ReaderOptions? readerOptions, IEnumerable testArchives) + protected void ArchiveStreamRead( + ReaderOptions? readerOptions, + IEnumerable testArchives + ) { foreach (var path in testArchives) { @@ -95,12 +110,10 @@ namespace SharpCompress.Test { foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) { - entry.WriteToDirectory(SCRATCH_FILES_PATH, - new ExtractionOptions() - { - ExtractFullPath = true, - Overwrite = true - }); + entry.WriteToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } + ); } } catch (IndexOutOfRangeException) @@ -115,54 +128,37 @@ namespace SharpCompress.Test } } - protected void ArchiveStreamMultiRead(ReaderOptions? readerOptions = null, params string[] testArchives) + protected void ArchiveStreamMultiRead( + ReaderOptions? readerOptions = null, + params string[] testArchives + ) { - ArchiveStreamMultiRead(readerOptions, testArchives.Select(x => Path.Combine(TEST_ARCHIVES_PATH, x))); + ArchiveStreamMultiRead( + readerOptions, + testArchives.Select(x => Path.Combine(TEST_ARCHIVES_PATH, x)) + ); } - protected void ArchiveStreamMultiRead(ReaderOptions? readerOptions, IEnumerable testArchives) + protected void ArchiveStreamMultiRead( + ReaderOptions? readerOptions, + IEnumerable testArchives + ) { - using (var archive = ArchiveFactory.Open(testArchives.Select(a => new FileInfo(a)), readerOptions)) - { - try - { - foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) - { - entry.WriteToDirectory(SCRATCH_FILES_PATH, - new ExtractionOptions() - { - ExtractFullPath = true, - Overwrite = true - }); - } - } - catch (IndexOutOfRangeException) - { - throw; - } - } - VerifyFiles(); - } - - protected void ArchiveOpenStreamRead(ReaderOptions? readerOptions = null, params string[] testArchives) - { - ArchiveOpenStreamRead(readerOptions, testArchives.Select(x => Path.Combine(TEST_ARCHIVES_PATH, x))); - } - - protected void ArchiveOpenStreamRead(ReaderOptions? readerOptions, IEnumerable testArchives) - { - using (var archive = ArchiveFactory.Open(testArchives.Select(f => new FileInfo(f)), readerOptions)) + using ( + var archive = ArchiveFactory.Open( + testArchives.Select(a => new FileInfo(a)), + readerOptions + ) + ) { try { foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) { - entry.WriteToDirectory(SCRATCH_FILES_PATH, - new ExtractionOptions() - { - ExtractFullPath = true, - Overwrite = true - }); + entry.WriteToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } + ); } } catch (IndexOutOfRangeException) @@ -173,16 +169,73 @@ namespace SharpCompress.Test VerifyFiles(); } - protected void ArchiveOpenEntryVolumeIndexTest(int[][] results, ReaderOptions? readerOptions = null, params string[] testArchives) + protected void ArchiveOpenStreamRead( + ReaderOptions? readerOptions = null, + params string[] testArchives + ) { - ArchiveOpenEntryVolumeIndexTest(results, readerOptions, testArchives.Select(x => Path.Combine(TEST_ARCHIVES_PATH, x))); + ArchiveOpenStreamRead( + readerOptions, + testArchives.Select(x => Path.Combine(TEST_ARCHIVES_PATH, x)) + ); } + protected void ArchiveOpenStreamRead( + ReaderOptions? readerOptions, + IEnumerable testArchives + ) + { + using ( + var archive = ArchiveFactory.Open( + testArchives.Select(f => new FileInfo(f)), + readerOptions + ) + ) + { + try + { + foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) + { + entry.WriteToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } + ); + } + } + catch (IndexOutOfRangeException) + { + throw; + } + } + VerifyFiles(); + } - protected void ArchiveOpenEntryVolumeIndexTest(int[][] results, ReaderOptions? readerOptions, IEnumerable testArchives) + protected void ArchiveOpenEntryVolumeIndexTest( + int[][] results, + ReaderOptions? readerOptions = null, + params string[] testArchives + ) + { + ArchiveOpenEntryVolumeIndexTest( + results, + readerOptions, + testArchives.Select(x => Path.Combine(TEST_ARCHIVES_PATH, x)) + ); + } + + protected void ArchiveOpenEntryVolumeIndexTest( + int[][] results, + ReaderOptions? readerOptions, + IEnumerable testArchives + ) { string[] src = testArchives.ToArray(); - using (var archive = ArchiveFactory.Open(testArchives.Select(f => new FileInfo(f)), readerOptions)) + using ( + var archive = ArchiveFactory.Open( + testArchives.Select(f => new FileInfo(f)), + readerOptions + ) + ) { try { @@ -191,8 +244,14 @@ namespace SharpCompress.Test { Assert.Equal(entry.VolumeIndexFirst, results[idx][0]); Assert.Equal(entry.VolumeIndexLast, results[idx][1]); - Assert.Equal(src[entry.VolumeIndexFirst], archive.Volumes.First(a => a.Index == entry.VolumeIndexFirst).FileName); - Assert.Equal(src[entry.VolumeIndexLast], archive.Volumes.First(a => a.Index == entry.VolumeIndexLast).FileName); + Assert.Equal( + src[entry.VolumeIndexFirst], + archive.Volumes.First(a => a.Index == entry.VolumeIndexFirst).FileName + ); + Assert.Equal( + src[entry.VolumeIndexLast], + archive.Volumes.First(a => a.Index == entry.VolumeIndexLast).FileName + ); idx++; } @@ -204,8 +263,6 @@ namespace SharpCompress.Test } } - - protected void ArchiveFileRead(string testArchive, ReaderOptions? readerOptions = null) { testArchive = Path.Combine(TEST_ARCHIVES_PATH, testArchive); @@ -213,12 +270,10 @@ namespace SharpCompress.Test { foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) { - entry.WriteToDirectory(SCRATCH_FILES_PATH, - new ExtractionOptions() - { - ExtractFullPath = true, - Overwrite = true - }); + entry.WriteToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } + ); } } VerifyFiles(); @@ -234,14 +289,16 @@ namespace SharpCompress.Test { foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) { - entry.WriteToDirectory(SCRATCH_FILES_PATH, + entry.WriteToDirectory( + SCRATCH_FILES_PATH, new ExtractionOptions() { ExtractFullPath = true, Overwrite = true, PreserveAttributes = true, PreserveFileTime = true - }); + } + ); } } VerifyFilesEx(); diff --git a/tests/SharpCompress.Test/Filters/BranchExecTests.cs b/tests/SharpCompress.Test/Filters/BranchExecTests.cs index 41dea9fd..138012c0 100644 --- a/tests/SharpCompress.Test/Filters/BranchExecTests.cs +++ b/tests/SharpCompress.Test/Filters/BranchExecTests.cs @@ -1,7 +1,7 @@ /* * BranchExecTests.cs -- Test for converters * - * + * * All data is extracted from busybox, where "ip" is the offset within the busybox file. */ @@ -12,87 +12,1177 @@ namespace SharpCompress.Test.Filters { public class BranchExecTests { - private static byte[] x86resultData { get; } = new byte[] { - 0x12, 0x00, 0x00, 0x00, 0x02, 0x0B, 0x00, 0x00, 0xE8, 0xBD, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x6D, 0x01, 0x00, 0x00, 0xF0, 0xCA, - 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0xBC, 0x09, 0x00, 0x00, 0x14, 0xC2, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, - 0x98, 0x0B, 0x00, 0x00, 0x60, 0x75, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0xF1, 0xFF, 0x42, 0x01, 0x00, 0x00, 0x08, 0xC8, 0x00, 0x00, 0x1C, 0x00, - }; + private static byte[] x86resultData { get; } = + new byte[] + { + 0x12, + 0x00, + 0x00, + 0x00, + 0x02, + 0x0B, + 0x00, + 0x00, + 0xE8, + 0xBD, + 0x00, + 0x00, + 0x00, + 0x07, + 0x00, + 0x00, + 0x12, + 0x00, + 0x00, + 0x00, + 0x6D, + 0x01, + 0x00, + 0x00, + 0xF0, + 0xCA, + 0x00, + 0x00, + 0x1C, + 0x00, + 0x00, + 0x00, + 0x12, + 0x00, + 0x00, + 0x00, + 0xBC, + 0x09, + 0x00, + 0x00, + 0x14, + 0xC2, + 0x00, + 0x00, + 0xE0, + 0x01, + 0x00, + 0x00, + 0x12, + 0x00, + 0x00, + 0x00, + 0x98, + 0x0B, + 0x00, + 0x00, + 0x60, + 0x75, + 0x0A, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x10, + 0x00, + 0xF1, + 0xFF, + 0x42, + 0x01, + 0x00, + 0x00, + 0x08, + 0xC8, + 0x00, + 0x00, + 0x1C, + 0x00, + }; - private static byte[] x86Data { get; } = new byte[] { - 0x12, 0x00, 0x00, 0x00, 0x02, 0x0B, 0x00, 0x00, 0xE8, 0xCA, 0x20, 0x00, 0x00, 0x07, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x6D, 0x01, 0x00, 0x00, 0xF0, 0xCA, - 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0xBC, 0x09, 0x00, 0x00, 0x14, 0xC2, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, - 0x98, 0x0B, 0x00, 0x00, 0x60, 0x75, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0xF1, 0xFF, 0x42, 0x01, 0x00, 0x00, 0x08, 0xC8, 0x00, 0x00, 0x1C, 0x00, - }; + private static byte[] x86Data { get; } = + new byte[] + { + 0x12, + 0x00, + 0x00, + 0x00, + 0x02, + 0x0B, + 0x00, + 0x00, + 0xE8, + 0xCA, + 0x20, + 0x00, + 0x00, + 0x07, + 0x00, + 0x00, + 0x12, + 0x00, + 0x00, + 0x00, + 0x6D, + 0x01, + 0x00, + 0x00, + 0xF0, + 0xCA, + 0x00, + 0x00, + 0x1C, + 0x00, + 0x00, + 0x00, + 0x12, + 0x00, + 0x00, + 0x00, + 0xBC, + 0x09, + 0x00, + 0x00, + 0x14, + 0xC2, + 0x00, + 0x00, + 0xE0, + 0x01, + 0x00, + 0x00, + 0x12, + 0x00, + 0x00, + 0x00, + 0x98, + 0x0B, + 0x00, + 0x00, + 0x60, + 0x75, + 0x0A, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x10, + 0x00, + 0xF1, + 0xFF, + 0x42, + 0x01, + 0x00, + 0x00, + 0x08, + 0xC8, + 0x00, + 0x00, + 0x1C, + 0x00, + }; - private static byte[] ppcResultData { get; } = new byte[] { - 0xF8, 0x6B, 0x2E, 0x8C, 0x95, 0xC5, 0x4B, 0x1B, 0x94, 0x78, 0x9E, 0x7C, 0xBD, 0x8B, 0xA8, 0xAF, 0x31, 0x20, 0xFE, 0x0F, 0xB3, 0x15, 0x9A, 0x7C, 0xD5, 0x5C, - 0xC2, 0xC0, 0xEC, 0xE9, 0x43, 0x2B, 0xD0, 0x9F, 0x2C, 0xFC, 0xB8, 0x2B, 0x6B, 0x15, 0xCD, 0x3F, 0x0C, 0xAF, 0x8F, 0x68, 0xB0, 0x6E, 0x6B, 0x30, 0x2E, 0x8C, - 0x3F, 0x7E, 0x96, 0x7C, 0x93, 0xB2, 0xA4, 0x0E, 0x43, 0xEA, 0x20, 0x10, 0x38, 0x6D, 0x37, 0xF8, 0x87, 0xFE, 0xA9, 0x63, 0x75, 0xF5, 0x56, 0x34, 0x4A, 0xE3, - 0xCF, 0x89, 0x18, 0x08, 0xC2, 0x76, 0x74, 0x12, 0xEC, 0xA7, 0x6D, 0xC2, 0xB7, 0x1B, 0x7A, 0xB2, 0xD4, 0xED - }; + private static byte[] ppcResultData { get; } = + new byte[] + { + 0xF8, + 0x6B, + 0x2E, + 0x8C, + 0x95, + 0xC5, + 0x4B, + 0x1B, + 0x94, + 0x78, + 0x9E, + 0x7C, + 0xBD, + 0x8B, + 0xA8, + 0xAF, + 0x31, + 0x20, + 0xFE, + 0x0F, + 0xB3, + 0x15, + 0x9A, + 0x7C, + 0xD5, + 0x5C, + 0xC2, + 0xC0, + 0xEC, + 0xE9, + 0x43, + 0x2B, + 0xD0, + 0x9F, + 0x2C, + 0xFC, + 0xB8, + 0x2B, + 0x6B, + 0x15, + 0xCD, + 0x3F, + 0x0C, + 0xAF, + 0x8F, + 0x68, + 0xB0, + 0x6E, + 0x6B, + 0x30, + 0x2E, + 0x8C, + 0x3F, + 0x7E, + 0x96, + 0x7C, + 0x93, + 0xB2, + 0xA4, + 0x0E, + 0x43, + 0xEA, + 0x20, + 0x10, + 0x38, + 0x6D, + 0x37, + 0xF8, + 0x87, + 0xFE, + 0xA9, + 0x63, + 0x75, + 0xF5, + 0x56, + 0x34, + 0x4A, + 0xE3, + 0xCF, + 0x89, + 0x18, + 0x08, + 0xC2, + 0x76, + 0x74, + 0x12, + 0xEC, + 0xA7, + 0x6D, + 0xC2, + 0xB7, + 0x1B, + 0x7A, + 0xB2, + 0xD4, + 0xED + }; - private static byte[] ppcData { get; } = new byte[] { - 0xF8, 0x6B, 0x2E, 0x8C, 0x95, 0xC5, 0x4B, 0x1B, 0x94, 0x78, 0x9E, 0x7C, 0xBD, 0x8B, 0xA8, 0xAF, 0x31, 0x20, 0xFE, 0x0F, 0xB3, 0x15, 0x9A, 0x7C, 0xD5, 0x5C, - 0xC2, 0xC0, 0xEC, 0xE9, 0x43, 0x2B, 0xD0, 0x9F, 0x2C, 0xFC, 0xB8, 0x2B, 0x6B, 0x15, 0xCD, 0x3F, 0x0C, 0xAF, 0x8F, 0x68, 0xB0, 0x6E, 0x6B, 0x30, 0x2E, 0x8C, - 0x3F, 0x7E, 0x96, 0x7C, 0x93, 0xB2, 0xA4, 0x0E, 0x43, 0xEA, 0x20, 0x10, 0x38, 0x6D, 0x37, 0xF8, 0x87, 0xFE, 0xA9, 0x63, 0x75, 0xF5, 0x56, 0x34, 0x4A, 0xE3, - 0xD6, 0x75, 0x18, 0x08, 0xC2, 0x76, 0x74, 0x12, 0xEC, 0xA7, 0x6D, 0xC2, 0xB7, 0x1B, 0x7A, 0xB2, 0xD4, 0xED - }; + private static byte[] ppcData { get; } = + new byte[] + { + 0xF8, + 0x6B, + 0x2E, + 0x8C, + 0x95, + 0xC5, + 0x4B, + 0x1B, + 0x94, + 0x78, + 0x9E, + 0x7C, + 0xBD, + 0x8B, + 0xA8, + 0xAF, + 0x31, + 0x20, + 0xFE, + 0x0F, + 0xB3, + 0x15, + 0x9A, + 0x7C, + 0xD5, + 0x5C, + 0xC2, + 0xC0, + 0xEC, + 0xE9, + 0x43, + 0x2B, + 0xD0, + 0x9F, + 0x2C, + 0xFC, + 0xB8, + 0x2B, + 0x6B, + 0x15, + 0xCD, + 0x3F, + 0x0C, + 0xAF, + 0x8F, + 0x68, + 0xB0, + 0x6E, + 0x6B, + 0x30, + 0x2E, + 0x8C, + 0x3F, + 0x7E, + 0x96, + 0x7C, + 0x93, + 0xB2, + 0xA4, + 0x0E, + 0x43, + 0xEA, + 0x20, + 0x10, + 0x38, + 0x6D, + 0x37, + 0xF8, + 0x87, + 0xFE, + 0xA9, + 0x63, + 0x75, + 0xF5, + 0x56, + 0x34, + 0x4A, + 0xE3, + 0xD6, + 0x75, + 0x18, + 0x08, + 0xC2, + 0x76, + 0x74, + 0x12, + 0xEC, + 0xA7, + 0x6D, + 0xC2, + 0xB7, + 0x1B, + 0x7A, + 0xB2, + 0xD4, + 0xED + }; - private static byte[] armResultData { get; } = new byte[] { - 0x7C, 0xFC, 0x0A, 0x00, 0x16, 0x42, 0x01, 0x00, 0x80, 0xFC, 0x0A, 0x00, 0x16, 0xB8, 0x00, 0x00, 0x84, 0xFC, 0x0A, 0x00, 0x16, 0x3A, 0x00, 0x00, 0x04, 0xE0, - 0x2D, 0xE5, 0x04, 0xD0, 0x4D, 0xE2, 0x0E, 0x04, 0x00, 0xEB, 0x04, 0xD0, 0x8D, 0xE2, 0x04, 0xE0, 0x9D, 0xE4, 0x1E, 0xFF, 0x2F, 0xE1, 0x04, 0xE0, 0x2D, 0xE5, - 0x04, 0xE0, 0x9F, 0xE5, 0x0E, 0xE0, 0x8F, 0xE0, 0x08, 0xF0, 0xBE, 0xE5, 0xF0, 0x3A, 0x0A, 0x00, 0x00, 0xC6, 0x8F, 0xE2, 0xA3, 0xCA, 0x8C, 0xE2, 0xF0, 0xFA, - 0xBC, 0xE5, 0x00, 0xC6, 0x8F, 0xE2, 0xA3, 0xCA, 0x8C, 0xE2, 0xE8, 0xFA, 0xBC, 0xE5, 0x00, 0xC6, 0x8F, 0xE2 - }; + private static byte[] armResultData { get; } = + new byte[] + { + 0x7C, + 0xFC, + 0x0A, + 0x00, + 0x16, + 0x42, + 0x01, + 0x00, + 0x80, + 0xFC, + 0x0A, + 0x00, + 0x16, + 0xB8, + 0x00, + 0x00, + 0x84, + 0xFC, + 0x0A, + 0x00, + 0x16, + 0x3A, + 0x00, + 0x00, + 0x04, + 0xE0, + 0x2D, + 0xE5, + 0x04, + 0xD0, + 0x4D, + 0xE2, + 0x0E, + 0x04, + 0x00, + 0xEB, + 0x04, + 0xD0, + 0x8D, + 0xE2, + 0x04, + 0xE0, + 0x9D, + 0xE4, + 0x1E, + 0xFF, + 0x2F, + 0xE1, + 0x04, + 0xE0, + 0x2D, + 0xE5, + 0x04, + 0xE0, + 0x9F, + 0xE5, + 0x0E, + 0xE0, + 0x8F, + 0xE0, + 0x08, + 0xF0, + 0xBE, + 0xE5, + 0xF0, + 0x3A, + 0x0A, + 0x00, + 0x00, + 0xC6, + 0x8F, + 0xE2, + 0xA3, + 0xCA, + 0x8C, + 0xE2, + 0xF0, + 0xFA, + 0xBC, + 0xE5, + 0x00, + 0xC6, + 0x8F, + 0xE2, + 0xA3, + 0xCA, + 0x8C, + 0xE2, + 0xE8, + 0xFA, + 0xBC, + 0xE5, + 0x00, + 0xC6, + 0x8F, + 0xE2 + }; - private static byte[] armData { get; } = new byte[] { - 0x7C, 0xFC, 0x0A, 0x00, 0x16, 0x42, 0x01, 0x00, 0x80, 0xFC, 0x0A, 0x00, 0x16, 0xB8, 0x00, 0x00, 0x84, 0xFC, 0x0A, 0x00, 0x16, 0x3A, 0x00, 0x00, 0x04, 0xE0, - 0x2D, 0xE5, 0x04, 0xD0, 0x4D, 0xE2, 0x18, 0x13, 0x00, 0xEB, 0x04, 0xD0, 0x8D, 0xE2, 0x04, 0xE0, 0x9D, 0xE4, 0x1E, 0xFF, 0x2F, 0xE1, 0x04, 0xE0, 0x2D, 0xE5, - 0x04, 0xE0, 0x9F, 0xE5, 0x0E, 0xE0, 0x8F, 0xE0, 0x08, 0xF0, 0xBE, 0xE5, 0xF0, 0x3A, 0x0A, 0x00, 0x00, 0xC6, 0x8F, 0xE2, 0xA3, 0xCA, 0x8C, 0xE2, 0xF0, 0xFA, - 0xBC, 0xE5, 0x00, 0xC6, 0x8F, 0xE2, 0xA3, 0xCA, 0x8C, 0xE2, 0xE8, 0xFA, 0xBC, 0xE5, 0x00, 0xC6, 0x8F, 0xE2 - }; + private static byte[] armData { get; } = + new byte[] + { + 0x7C, + 0xFC, + 0x0A, + 0x00, + 0x16, + 0x42, + 0x01, + 0x00, + 0x80, + 0xFC, + 0x0A, + 0x00, + 0x16, + 0xB8, + 0x00, + 0x00, + 0x84, + 0xFC, + 0x0A, + 0x00, + 0x16, + 0x3A, + 0x00, + 0x00, + 0x04, + 0xE0, + 0x2D, + 0xE5, + 0x04, + 0xD0, + 0x4D, + 0xE2, + 0x18, + 0x13, + 0x00, + 0xEB, + 0x04, + 0xD0, + 0x8D, + 0xE2, + 0x04, + 0xE0, + 0x9D, + 0xE4, + 0x1E, + 0xFF, + 0x2F, + 0xE1, + 0x04, + 0xE0, + 0x2D, + 0xE5, + 0x04, + 0xE0, + 0x9F, + 0xE5, + 0x0E, + 0xE0, + 0x8F, + 0xE0, + 0x08, + 0xF0, + 0xBE, + 0xE5, + 0xF0, + 0x3A, + 0x0A, + 0x00, + 0x00, + 0xC6, + 0x8F, + 0xE2, + 0xA3, + 0xCA, + 0x8C, + 0xE2, + 0xF0, + 0xFA, + 0xBC, + 0xE5, + 0x00, + 0xC6, + 0x8F, + 0xE2, + 0xA3, + 0xCA, + 0x8C, + 0xE2, + 0xE8, + 0xFA, + 0xBC, + 0xE5, + 0x00, + 0xC6, + 0x8F, + 0xE2 + }; - private static byte[] armtResultData { get; } = new byte[] { - 0x95, 0x23, 0xB6, 0xB1, 0xBE, 0x60, 0x79, 0xF0, 0xF6, 0x01, 0xD9, 0x7F, 0x2E, 0x03, 0x31, 0x1C, 0xFD, 0xD3, 0x40, 0x0F, 0x21, 0x3C, 0x06, 0x97, 0xE5, 0xC3, - 0x57, 0x11, 0x76, 0x6F, 0xE3, 0x70, 0xED, 0x49, 0xCB, 0xB5, 0xC9, 0x42, 0x59, 0x10, 0x2F, 0xBD, 0xAE, 0xB1, 0x40, 0x4D, 0x9D, 0x7C, 0xE9, 0xFC, 0x48, 0x3E, - 0xBC, 0x7F, 0x0B, 0x23, 0xB0, 0x8A, 0x4D, 0x02, 0x39, 0xC4, 0xFB, 0x66, 0x83, 0x7F, 0xA7, 0xBD, 0x12, 0xAC, 0xED, 0x31, 0x34, 0x93, 0x4D, 0x8D, 0xD7, 0x94, - 0x93, 0x1C, 0x0A, 0x50, 0x54, 0x4B, 0x03, 0x55, 0x27, 0xFE, 0xCE, 0x29, 0x66, 0x52, 0x81, 0xAE, 0x69, 0xA0, 0x69, 0xF2, 0x3D, 0xFF, 0xA1, 0x8A, 0x5D, 0x61, - 0x7D, 0xC5, 0x94, 0x0A, 0x7D, 0xED, 0x11, 0x0F - }; + private static byte[] armtResultData { get; } = + new byte[] + { + 0x95, + 0x23, + 0xB6, + 0xB1, + 0xBE, + 0x60, + 0x79, + 0xF0, + 0xF6, + 0x01, + 0xD9, + 0x7F, + 0x2E, + 0x03, + 0x31, + 0x1C, + 0xFD, + 0xD3, + 0x40, + 0x0F, + 0x21, + 0x3C, + 0x06, + 0x97, + 0xE5, + 0xC3, + 0x57, + 0x11, + 0x76, + 0x6F, + 0xE3, + 0x70, + 0xED, + 0x49, + 0xCB, + 0xB5, + 0xC9, + 0x42, + 0x59, + 0x10, + 0x2F, + 0xBD, + 0xAE, + 0xB1, + 0x40, + 0x4D, + 0x9D, + 0x7C, + 0xE9, + 0xFC, + 0x48, + 0x3E, + 0xBC, + 0x7F, + 0x0B, + 0x23, + 0xB0, + 0x8A, + 0x4D, + 0x02, + 0x39, + 0xC4, + 0xFB, + 0x66, + 0x83, + 0x7F, + 0xA7, + 0xBD, + 0x12, + 0xAC, + 0xED, + 0x31, + 0x34, + 0x93, + 0x4D, + 0x8D, + 0xD7, + 0x94, + 0x93, + 0x1C, + 0x0A, + 0x50, + 0x54, + 0x4B, + 0x03, + 0x55, + 0x27, + 0xFE, + 0xCE, + 0x29, + 0x66, + 0x52, + 0x81, + 0xAE, + 0x69, + 0xA0, + 0x69, + 0xF2, + 0x3D, + 0xFF, + 0xA1, + 0x8A, + 0x5D, + 0x61, + 0x7D, + 0xC5, + 0x94, + 0x0A, + 0x7D, + 0xED, + 0x11, + 0x0F + }; - private static byte[] armtData { get; } = new byte[] { - 0x95, 0x23, 0xB6, 0xB1, 0xBE, 0x60, 0x79, 0xF0, 0xF6, 0x01, 0xD9, 0x7F, 0x2E, 0x03, 0x31, 0x1C, 0xFD, 0xD3, 0x40, 0x0F, 0x21, 0x3C, 0x06, 0x97, 0xE5, 0xC3, - 0x57, 0x11, 0x76, 0x6F, 0xE3, 0x70, 0xED, 0x49, 0xCB, 0xB5, 0xC9, 0x42, 0x59, 0x10, 0x2F, 0xBD, 0xAE, 0xB1, 0x40, 0x4D, 0x9D, 0x7C, 0xE9, 0xFC, 0x48, 0x3E, - 0xBC, 0x7F, 0x0B, 0x23, 0xB0, 0x8A, 0x4D, 0x02, 0x39, 0xC4, 0xFB, 0x66, 0x83, 0x7F, 0xA7, 0xBD, 0x12, 0xAC, 0xED, 0x31, 0x34, 0x93, 0x4D, 0x8D, 0xD7, 0x94, - 0x93, 0x1C, 0x0A, 0x50, 0x54, 0x4B, 0x03, 0x55, 0x27, 0xFE, 0xCE, 0x29, 0x66, 0x52, 0x81, 0xAE, 0x69, 0xA0, 0x6A, 0xF2, 0x6F, 0xFC, 0xA1, 0x8A, 0x5D, 0x61, - 0x7D, 0xC5, 0x94, 0x0A, 0x7D, 0xED, 0x11, 0x0F - }; + private static byte[] armtData { get; } = + new byte[] + { + 0x95, + 0x23, + 0xB6, + 0xB1, + 0xBE, + 0x60, + 0x79, + 0xF0, + 0xF6, + 0x01, + 0xD9, + 0x7F, + 0x2E, + 0x03, + 0x31, + 0x1C, + 0xFD, + 0xD3, + 0x40, + 0x0F, + 0x21, + 0x3C, + 0x06, + 0x97, + 0xE5, + 0xC3, + 0x57, + 0x11, + 0x76, + 0x6F, + 0xE3, + 0x70, + 0xED, + 0x49, + 0xCB, + 0xB5, + 0xC9, + 0x42, + 0x59, + 0x10, + 0x2F, + 0xBD, + 0xAE, + 0xB1, + 0x40, + 0x4D, + 0x9D, + 0x7C, + 0xE9, + 0xFC, + 0x48, + 0x3E, + 0xBC, + 0x7F, + 0x0B, + 0x23, + 0xB0, + 0x8A, + 0x4D, + 0x02, + 0x39, + 0xC4, + 0xFB, + 0x66, + 0x83, + 0x7F, + 0xA7, + 0xBD, + 0x12, + 0xAC, + 0xED, + 0x31, + 0x34, + 0x93, + 0x4D, + 0x8D, + 0xD7, + 0x94, + 0x93, + 0x1C, + 0x0A, + 0x50, + 0x54, + 0x4B, + 0x03, + 0x55, + 0x27, + 0xFE, + 0xCE, + 0x29, + 0x66, + 0x52, + 0x81, + 0xAE, + 0x69, + 0xA0, + 0x6A, + 0xF2, + 0x6F, + 0xFC, + 0xA1, + 0x8A, + 0x5D, + 0x61, + 0x7D, + 0xC5, + 0x94, + 0x0A, + 0x7D, + 0xED, + 0x11, + 0x0F + }; - private static byte[] ia64ResultData { get; } = new byte[] { - 0x4D, 0xF8, 0xF2, 0x0D, 0x06, 0x2F, 0x74, 0x0F, 0xF0, 0x91, 0x06, 0x0B, 0x19, 0x22, 0x91, 0x5A, 0x66, 0x56, 0xA7, 0x15, 0x77, 0x1E, 0x2F, 0xA3, 0xE4, 0xDE, - 0x93, 0x1C, 0xD5, 0xCE, 0x6E, 0x45, 0x36, 0x15, 0x15, 0x65, 0x4E, 0xC5, 0xA3, 0x8C, 0x5A, 0x8B, 0x8A, 0x1C, 0x12, 0x5B, 0x39, 0x1F, 0xA0, 0xF2, 0x93, 0x7C, - 0x7F, 0x5D, 0xD9, 0x30, 0x1F, 0xF6, 0x5C, 0x10, 0x62, 0x3E, 0xB4, 0x64, 0x56, 0x48, 0xB2, 0x20, 0x39, 0xE8, 0x44, 0x10, 0x87, 0x9E, 0x2C, 0xFC, 0x29, 0x0E, - 0x20, 0x76, 0xCE, 0xDA, 0x93, 0x1C, 0xED, 0x54, 0x0D, 0xAF, 0xEC, 0xDE, 0x93, 0x1C, 0x2B, 0x72, 0xD5, 0x0D - }; + private static byte[] ia64ResultData { get; } = + new byte[] + { + 0x4D, + 0xF8, + 0xF2, + 0x0D, + 0x06, + 0x2F, + 0x74, + 0x0F, + 0xF0, + 0x91, + 0x06, + 0x0B, + 0x19, + 0x22, + 0x91, + 0x5A, + 0x66, + 0x56, + 0xA7, + 0x15, + 0x77, + 0x1E, + 0x2F, + 0xA3, + 0xE4, + 0xDE, + 0x93, + 0x1C, + 0xD5, + 0xCE, + 0x6E, + 0x45, + 0x36, + 0x15, + 0x15, + 0x65, + 0x4E, + 0xC5, + 0xA3, + 0x8C, + 0x5A, + 0x8B, + 0x8A, + 0x1C, + 0x12, + 0x5B, + 0x39, + 0x1F, + 0xA0, + 0xF2, + 0x93, + 0x7C, + 0x7F, + 0x5D, + 0xD9, + 0x30, + 0x1F, + 0xF6, + 0x5C, + 0x10, + 0x62, + 0x3E, + 0xB4, + 0x64, + 0x56, + 0x48, + 0xB2, + 0x20, + 0x39, + 0xE8, + 0x44, + 0x10, + 0x87, + 0x9E, + 0x2C, + 0xFC, + 0x29, + 0x0E, + 0x20, + 0x76, + 0xCE, + 0xDA, + 0x93, + 0x1C, + 0xED, + 0x54, + 0x0D, + 0xAF, + 0xEC, + 0xDE, + 0x93, + 0x1C, + 0x2B, + 0x72, + 0xD5, + 0x0D + }; - private static byte[] ia64Data { get; } = new byte[] { - 0x4D, 0xF8, 0xF2, 0x0D, 0x06, 0x2F, 0x74, 0x0F, 0xF0, 0x91, 0x06, 0x0B, 0x19, 0x22, 0x91, 0x5A, 0x66, 0x56, 0xA7, 0x15, 0x77, 0x1E, 0x2F, 0xA3, 0xE4, 0xDE, - 0x93, 0x1C, 0xD5, 0xCE, 0x6E, 0x45, 0x36, 0x15, 0x15, 0x65, 0x4E, 0xC5, 0xA3, 0x8C, 0x5A, 0x8B, 0x8A, 0x1C, 0x12, 0x5B, 0x39, 0x1F, 0xA0, 0xF2, 0x93, 0x7C, - 0x7F, 0x5D, 0xD9, 0x30, 0x1F, 0xF6, 0x5C, 0x10, 0x62, 0x3E, 0xB4, 0x64, 0x56, 0x48, 0xB2, 0x20, 0x39, 0xE8, 0x44, 0x80, 0x8C, 0x9E, 0x2C, 0xFC, 0x29, 0x0E, - 0x20, 0x76, 0xCE, 0xDA, 0x93, 0x1C, 0xED, 0x54, 0x0D, 0xAF, 0xEC, 0xDE, 0x93, 0x1C, 0x2B, 0x72, 0xD5, 0x0D - }; + private static byte[] ia64Data { get; } = + new byte[] + { + 0x4D, + 0xF8, + 0xF2, + 0x0D, + 0x06, + 0x2F, + 0x74, + 0x0F, + 0xF0, + 0x91, + 0x06, + 0x0B, + 0x19, + 0x22, + 0x91, + 0x5A, + 0x66, + 0x56, + 0xA7, + 0x15, + 0x77, + 0x1E, + 0x2F, + 0xA3, + 0xE4, + 0xDE, + 0x93, + 0x1C, + 0xD5, + 0xCE, + 0x6E, + 0x45, + 0x36, + 0x15, + 0x15, + 0x65, + 0x4E, + 0xC5, + 0xA3, + 0x8C, + 0x5A, + 0x8B, + 0x8A, + 0x1C, + 0x12, + 0x5B, + 0x39, + 0x1F, + 0xA0, + 0xF2, + 0x93, + 0x7C, + 0x7F, + 0x5D, + 0xD9, + 0x30, + 0x1F, + 0xF6, + 0x5C, + 0x10, + 0x62, + 0x3E, + 0xB4, + 0x64, + 0x56, + 0x48, + 0xB2, + 0x20, + 0x39, + 0xE8, + 0x44, + 0x80, + 0x8C, + 0x9E, + 0x2C, + 0xFC, + 0x29, + 0x0E, + 0x20, + 0x76, + 0xCE, + 0xDA, + 0x93, + 0x1C, + 0xED, + 0x54, + 0x0D, + 0xAF, + 0xEC, + 0xDE, + 0x93, + 0x1C, + 0x2B, + 0x72, + 0xD5, + 0x0D + }; - private static byte[] sparcResultData { get; } = new byte[] { - 0x78, 0x2E, 0x73, 0x6F, 0x2E, 0x33, 0x00, 0x00, 0x07, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0xA2, 0x0D, - 0x10, 0x12, 0x30, 0x03, 0xC9, 0x37, 0x40, 0x1A, 0x85, 0xD9, 0x44, 0x34, 0x40, 0x32, 0x85, 0xA0, 0x30, 0x40, 0x00, 0x70, 0x00, 0x40, 0x84, 0x80, 0x04, 0x00, - 0xE4, 0xAC, 0x07, 0x04, 0x21, 0x44, 0x02, 0x20, 0x10, 0x00, 0x40, 0xC2, 0x89, 0x98, 0x85, 0x00, 0x58, 0x6A, 0x41, 0x8E, 0x18, 0xA1, 0x91, 0x00, 0x10, 0x00, - }; + private static byte[] sparcResultData { get; } = + new byte[] + { + 0x78, + 0x2E, + 0x73, + 0x6F, + 0x2E, + 0x33, + 0x00, + 0x00, + 0x07, + 0x01, + 0x00, + 0x00, + 0x09, + 0x00, + 0x00, + 0x00, + 0x40, + 0x00, + 0x00, + 0x00, + 0x0B, + 0x00, + 0x00, + 0x00, + 0xA2, + 0x0D, + 0x10, + 0x12, + 0x30, + 0x03, + 0xC9, + 0x37, + 0x40, + 0x1A, + 0x85, + 0xD9, + 0x44, + 0x34, + 0x40, + 0x32, + 0x85, + 0xA0, + 0x30, + 0x40, + 0x00, + 0x70, + 0x00, + 0x40, + 0x84, + 0x80, + 0x04, + 0x00, + 0xE4, + 0xAC, + 0x07, + 0x04, + 0x21, + 0x44, + 0x02, + 0x20, + 0x10, + 0x00, + 0x40, + 0xC2, + 0x89, + 0x98, + 0x85, + 0x00, + 0x58, + 0x6A, + 0x41, + 0x8E, + 0x18, + 0xA1, + 0x91, + 0x00, + 0x10, + 0x00, + }; - private static byte[] sparcData { get; } = new byte[] { - 0x78, 0x2E, 0x73, 0x6F, 0x2E, 0x33, 0x00, 0x00, 0x07, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x44, 0x0B, 0x00, 0x00, 0x00, 0xA2, 0x0D, - 0x10, 0x12, 0x30, 0x03, 0xC9, 0x37, 0x40, 0x1A, 0x86, 0x21, 0x44, 0x34, 0x40, 0x32, 0x85, 0xA0, 0x30, 0x40, 0x00, 0x70, 0x00, 0x40, 0x84, 0x80, 0x04, 0x00, - 0xE4, 0xAC, 0x07, 0x04, 0x21, 0x44, 0x02, 0x20, 0x10, 0x00, 0x40, 0xC2, 0x89, 0x98, 0x85, 0x00, 0x58, 0x6A, 0x41, 0x8E, 0x18, 0xA1, 0x91, 0x00, 0x10, 0x00, - }; + private static byte[] sparcData { get; } = + new byte[] + { + 0x78, + 0x2E, + 0x73, + 0x6F, + 0x2E, + 0x33, + 0x00, + 0x00, + 0x07, + 0x01, + 0x00, + 0x00, + 0x09, + 0x00, + 0x00, + 0x00, + 0x40, + 0x00, + 0x00, + 0x44, + 0x0B, + 0x00, + 0x00, + 0x00, + 0xA2, + 0x0D, + 0x10, + 0x12, + 0x30, + 0x03, + 0xC9, + 0x37, + 0x40, + 0x1A, + 0x86, + 0x21, + 0x44, + 0x34, + 0x40, + 0x32, + 0x85, + 0xA0, + 0x30, + 0x40, + 0x00, + 0x70, + 0x00, + 0x40, + 0x84, + 0x80, + 0x04, + 0x00, + 0xE4, + 0xAC, + 0x07, + 0x04, + 0x21, + 0x44, + 0x02, + 0x20, + 0x10, + 0x00, + 0x40, + 0xC2, + 0x89, + 0x98, + 0x85, + 0x00, + 0x58, + 0x6A, + 0x41, + 0x8E, + 0x18, + 0xA1, + 0x91, + 0x00, + 0x10, + 0x00, + }; private void CompareBuffer(byte[] testBuffer, byte[] targetBuffer) { diff --git a/tests/SharpCompress.Test/GZip/GZipArchiveTests.cs b/tests/SharpCompress.Test/GZip/GZipArchiveTests.cs index 15389a4f..cfe0bf51 100644 --- a/tests/SharpCompress.Test/GZip/GZipArchiveTests.cs +++ b/tests/SharpCompress.Test/GZip/GZipArchiveTests.cs @@ -30,8 +30,10 @@ namespace SharpCompress.Test.GZip Assert.Equal(size, scratch.Length); Assert.Equal(size, test.Length); } - CompareArchivesByPath(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar"), - Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar")); + CompareArchivesByPath( + Path.Combine(SCRATCH_FILES_PATH, "Tar.tar"), + Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar") + ); } [Fact] @@ -50,11 +52,12 @@ namespace SharpCompress.Test.GZip Assert.Equal(size, scratch.Length); Assert.Equal(size, test.Length); } - CompareArchivesByPath(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar"), - Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar")); + CompareArchivesByPath( + Path.Combine(SCRATCH_FILES_PATH, "Tar.tar"), + Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar") + ); } - [Fact] public void GZip_Archive_NoAdd() { @@ -62,12 +65,13 @@ namespace SharpCompress.Test.GZip using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz"))) using (var archive = GZipArchive.Open(stream)) { - Assert.Throws(() => archive.AddEntry("jpg\\test.jpg", jpg)); + Assert.Throws( + () => archive.AddEntry("jpg\\test.jpg", jpg) + ); archive.SaveTo(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz")); } } - [Fact] public void GZip_Archive_Multiple_Reads() { diff --git a/tests/SharpCompress.Test/GZip/GZipReaderTests.cs b/tests/SharpCompress.Test/GZip/GZipReaderTests.cs index ed308c98..a2c8071d 100644 --- a/tests/SharpCompress.Test/GZip/GZipReaderTests.cs +++ b/tests/SharpCompress.Test/GZip/GZipReaderTests.cs @@ -18,13 +18,16 @@ namespace SharpCompress.Test.GZip Read("Tar.tar.gz", CompressionType.GZip); } - [Fact] public void GZip_Reader_Generic2() { //read only as GZip itme using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz"))) - using (var reader = SharpCompress.Readers.GZip.GZipReader.Open(new RewindableStream(stream))) + using ( + var reader = SharpCompress.Readers.GZip.GZipReader.Open( + new RewindableStream(stream) + ) + ) { while (reader.MoveToNextEntry()) // Crash here { diff --git a/tests/SharpCompress.Test/GZip/GZipWriterTests.cs b/tests/SharpCompress.Test/GZip/GZipWriterTests.cs index 5c109bd5..212e275e 100644 --- a/tests/SharpCompress.Test/GZip/GZipWriterTests.cs +++ b/tests/SharpCompress.Test/GZip/GZipWriterTests.cs @@ -8,8 +8,7 @@ namespace SharpCompress.Test.GZip { public class GZipWriterTests : WriterTests { - public GZipWriterTests() - : base(ArchiveType.GZip) + public GZipWriterTests() : base(ArchiveType.GZip) { UseExtensionInsteadOfNameToVerify = true; } @@ -17,25 +16,41 @@ namespace SharpCompress.Test.GZip [Fact] public void GZip_Writer_Generic() { - using (Stream stream = File.Open(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz"), FileMode.OpenOrCreate, FileAccess.Write)) + using ( + Stream stream = File.Open( + Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz"), + FileMode.OpenOrCreate, + FileAccess.Write + ) + ) using (var writer = WriterFactory.Open(stream, ArchiveType.GZip, CompressionType.GZip)) { writer.Write("Tar.tar", Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar")); } - CompareArchivesByPath(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz"), - Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz")); + CompareArchivesByPath( + Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz"), + Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz") + ); } [Fact] public void GZip_Writer() { - using (Stream stream = File.Open(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz"), FileMode.OpenOrCreate, FileAccess.Write)) + using ( + Stream stream = File.Open( + Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz"), + FileMode.OpenOrCreate, + FileAccess.Write + ) + ) using (var writer = new GZipWriter(stream)) { writer.Write("Tar.tar", Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar")); } - CompareArchivesByPath(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz"), - Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz")); + CompareArchivesByPath( + Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz"), + Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz") + ); } [Fact] @@ -43,24 +58,34 @@ namespace SharpCompress.Test.GZip { Assert.Throws(() => { - using (Stream stream = File.OpenWrite(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz"))) - using (var writer = WriterFactory.Open(stream, ArchiveType.GZip, CompressionType.BZip2)) - { - } + using ( + Stream stream = File.OpenWrite(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz")) + ) + using ( + var writer = WriterFactory.Open(stream, ArchiveType.GZip, CompressionType.BZip2) + ) { } }); } [Fact] public void GZip_Writer_Entry_Path_With_Dir() { - using (Stream stream = File.Open(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz"), FileMode.OpenOrCreate, FileAccess.Write)) + using ( + Stream stream = File.Open( + Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz"), + FileMode.OpenOrCreate, + FileAccess.Write + ) + ) using (var writer = new GZipWriter(stream)) { var path = Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar"); writer.Write(path, path); //covers issue #532 } - CompareArchivesByPath(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz"), - Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz")); + CompareArchivesByPath( + Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz"), + Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz") + ); } } } diff --git a/tests/SharpCompress.Test/Mocks/FlushOnDisposeStream.cs b/tests/SharpCompress.Test/Mocks/FlushOnDisposeStream.cs index 22e84ef9..fb1106d5 100644 --- a/tests/SharpCompress.Test/Mocks/FlushOnDisposeStream.cs +++ b/tests/SharpCompress.Test/Mocks/FlushOnDisposeStream.cs @@ -24,7 +24,11 @@ namespace SharpCompress.Test.Mocks public override long Length => this.inner.Length; - public override long Position { get => this.inner.Position; set => this.inner.Position = value; } + public override long Position + { + get => this.inner.Position; + set => this.inner.Position = value; + } public override void Flush() { diff --git a/tests/SharpCompress.Test/Mocks/ForwardOnlyStream.cs b/tests/SharpCompress.Test/Mocks/ForwardOnlyStream.cs index aaa52c51..9c10941f 100644 --- a/tests/SharpCompress.Test/Mocks/ForwardOnlyStream.cs +++ b/tests/SharpCompress.Test/Mocks/ForwardOnlyStream.cs @@ -65,4 +65,4 @@ namespace SharpCompress.Test.Mocks throw new NotSupportedException(); } } -} \ No newline at end of file +} diff --git a/tests/SharpCompress.Test/Mocks/TestStream.cs b/tests/SharpCompress.Test/Mocks/TestStream.cs index 64bee443..000cf408 100644 --- a/tests/SharpCompress.Test/Mocks/TestStream.cs +++ b/tests/SharpCompress.Test/Mocks/TestStream.cs @@ -6,9 +6,8 @@ namespace SharpCompress.Test.Mocks { private readonly Stream stream; - public TestStream(Stream stream) : this(stream, stream.CanRead, stream.CanWrite, stream.CanSeek) - { - } + public TestStream(Stream stream) + : this(stream, stream.CanRead, stream.CanWrite, stream.CanSeek) { } public bool IsDisposed { get; private set; } diff --git a/tests/SharpCompress.Test/Rar/RarArchiveTests.cs b/tests/SharpCompress.Test/Rar/RarArchiveTests.cs index 3adf92ea..6c61215c 100644 --- a/tests/SharpCompress.Test/Rar/RarArchiveTests.cs +++ b/tests/SharpCompress.Test/Rar/RarArchiveTests.cs @@ -20,7 +20,10 @@ namespace SharpCompress.Test.Rar [Fact] public void Rar_EncryptedFileAndHeader_NoPasswordExceptionTest() { - Assert.Throws(typeof(CryptographicException), () => ReadRarPassword("Rar.encrypted_filesAndHeader.rar", null)); + Assert.Throws( + typeof(CryptographicException), + () => ReadRarPassword("Rar.encrypted_filesAndHeader.rar", null) + ); } /*[Fact] @@ -32,7 +35,10 @@ namespace SharpCompress.Test.Rar [Fact] public void Rar5_EncryptedFileAndHeader_NoPasswordExceptionTest() { - Assert.Throws(typeof(CryptographicException), () => ReadRarPassword("Rar5.encrypted_filesAndHeader.rar", null)); + Assert.Throws( + typeof(CryptographicException), + () => ReadRarPassword("Rar5.encrypted_filesAndHeader.rar", null) + ); } [Fact] @@ -62,22 +68,22 @@ namespace SharpCompress.Test.Rar private void ReadRarPassword(string testArchive, string? password) { using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, testArchive))) - using (var archive = RarArchive.Open(stream, new ReaderOptions() - { - Password = password, - LeaveStreamOpen = true - })) + using ( + var archive = RarArchive.Open( + stream, + new ReaderOptions() { Password = password, LeaveStreamOpen = true } + ) + ) { foreach (var entry in archive.Entries) { if (!entry.IsDirectory) { Assert.Equal(CompressionType.Rar, entry.CompressionType); - entry.WriteToDirectory(SCRATCH_FILES_PATH, new ExtractionOptions() - { - ExtractFullPath = true, - Overwrite = true - }); + entry.WriteToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } + ); } } } @@ -87,25 +93,26 @@ namespace SharpCompress.Test.Rar [Fact] public void Rar_Multi_Archive_Encrypted() { - Assert.Throws(() => ArchiveFileReadPassword("Rar.EncryptedParts.part01.rar", "test")); + Assert.Throws( + () => ArchiveFileReadPassword("Rar.EncryptedParts.part01.rar", "test") + ); } protected void ArchiveFileReadPassword(string archiveName, string password) { - using (var archive = RarArchive.Open(Path.Combine(TEST_ARCHIVES_PATH, archiveName), new ReaderOptions() - { - Password = password, - LeaveStreamOpen = true - })) + using ( + var archive = RarArchive.Open( + Path.Combine(TEST_ARCHIVES_PATH, archiveName), + new ReaderOptions() { Password = password, LeaveStreamOpen = true } + ) + ) { foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) { - entry.WriteToDirectory(SCRATCH_FILES_PATH, - new ExtractionOptions() - { - ExtractFullPath = true, - Overwrite = true - }); + entry.WriteToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } + ); } } VerifyFiles(); @@ -149,11 +156,10 @@ namespace SharpCompress.Test.Rar { foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) { - entry.WriteToDirectory(SCRATCH_FILES_PATH, new ExtractionOptions() - { - ExtractFullPath = true, - Overwrite = true - }); + entry.WriteToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } + ); } } } @@ -164,19 +170,19 @@ namespace SharpCompress.Test.Rar { using (var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Rar.jpeg.jpg"))) { - using (var archive = RarArchive.Open(stream, new ReaderOptions() - { - LookForHeader = true - })) + using ( + var archive = RarArchive.Open( + stream, + new ReaderOptions() { LookForHeader = true } + ) + ) { foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) { - entry.WriteToDirectory(SCRATCH_FILES_PATH, - new ExtractionOptions() - { - ExtractFullPath = true, - Overwrite = true - }); + entry.WriteToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } + ); } } VerifyFiles(); @@ -204,19 +210,16 @@ namespace SharpCompress.Test.Rar Assert.False(archive.IsSolid); foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) { - entry.WriteToDirectory(SCRATCH_FILES_PATH, - new ExtractionOptions() - { - ExtractFullPath = true, - Overwrite = true - }); + entry.WriteToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } + ); } } } VerifyFiles(); } - [Fact] public void Rar_IsSolidEntryStreamCheck() { @@ -252,7 +255,6 @@ namespace SharpCompress.Test.Rar } } - [Fact] public void Rar_Solid_ArchiveStreamRead() { @@ -280,40 +282,52 @@ namespace SharpCompress.Test.Rar [Fact] public void Rar_Multi_ArchiveStreamRead() { - DoRar_Multi_ArchiveStreamRead(new string[] { - "Rar.multi.part01.rar", - "Rar.multi.part02.rar", - "Rar.multi.part03.rar", - "Rar.multi.part04.rar", - "Rar.multi.part05.rar", - "Rar.multi.part06.rar"}, false); + DoRar_Multi_ArchiveStreamRead( + new string[] + { + "Rar.multi.part01.rar", + "Rar.multi.part02.rar", + "Rar.multi.part03.rar", + "Rar.multi.part04.rar", + "Rar.multi.part05.rar", + "Rar.multi.part06.rar" + }, + false + ); } [Fact] public void Rar5_Multi_ArchiveStreamRead() { - DoRar_Multi_ArchiveStreamRead(new string[] { - "Rar5.multi.part01.rar", - "Rar5.multi.part02.rar", - "Rar5.multi.part03.rar", - "Rar5.multi.part04.rar", - "Rar5.multi.part05.rar", - "Rar5.multi.part06.rar"}, false); + DoRar_Multi_ArchiveStreamRead( + new string[] + { + "Rar5.multi.part01.rar", + "Rar5.multi.part02.rar", + "Rar5.multi.part03.rar", + "Rar5.multi.part04.rar", + "Rar5.multi.part05.rar", + "Rar5.multi.part06.rar" + }, + false + ); } private void DoRar_Multi_ArchiveStreamRead(string[] archives, bool isSolid) { - using (var archive = RarArchive.Open(archives.Select(s => Path.Combine(TEST_ARCHIVES_PATH, s)) - .Select(File.OpenRead))) + using ( + var archive = RarArchive.Open( + archives.Select(s => Path.Combine(TEST_ARCHIVES_PATH, s)).Select(File.OpenRead) + ) + ) { Assert.Equal(archive.IsSolid, isSolid); foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) { - entry.WriteToDirectory(SCRATCH_FILES_PATH, new ExtractionOptions() - { - ExtractFullPath = true, - Overwrite = true - }); + entry.WriteToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } + ); } } } @@ -321,13 +335,18 @@ namespace SharpCompress.Test.Rar [Fact] public void Rar5_MultiSolid_ArchiveStreamRead() { - DoRar_Multi_ArchiveStreamRead(new string[] { - "Rar.multi.solid.part01.rar", - "Rar.multi.solid.part02.rar", - "Rar.multi.solid.part03.rar", - "Rar.multi.solid.part04.rar", - "Rar.multi.solid.part05.rar", - "Rar.multi.solid.part06.rar"}, true); + DoRar_Multi_ArchiveStreamRead( + new string[] + { + "Rar.multi.solid.part01.rar", + "Rar.multi.solid.part02.rar", + "Rar.multi.solid.part03.rar", + "Rar.multi.solid.part04.rar", + "Rar.multi.solid.part05.rar", + "Rar.multi.solid.part06.rar" + }, + true + ); } [Fact] @@ -381,18 +400,19 @@ namespace SharpCompress.Test.Rar [Fact] public void Rar_Jpg_ArchiveFileRead() { - using (var archive = RarArchive.Open(Path.Combine(TEST_ARCHIVES_PATH, "Rar.jpeg.jpg"), new ReaderOptions() - { - LookForHeader = true - })) + using ( + var archive = RarArchive.Open( + Path.Combine(TEST_ARCHIVES_PATH, "Rar.jpeg.jpg"), + new ReaderOptions() { LookForHeader = true } + ) + ) { foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) { - entry.WriteToDirectory(SCRATCH_FILES_PATH, new ExtractionOptions() - { - ExtractFullPath = true, - Overwrite = true - }); + entry.WriteToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } + ); } } VerifyFiles(); @@ -413,14 +433,19 @@ namespace SharpCompress.Test.Rar [Fact] public void Rar2_Multi_ArchiveStreamRead() { - DoRar_Multi_ArchiveStreamRead(new string[] { - "Rar2.multi.rar", - "Rar2.multi.r00", - "Rar2.multi.r01", - "Rar2.multi.r02", - "Rar2.multi.r03", - "Rar2.multi.r04", - "Rar2.multi.r05"}, false); + DoRar_Multi_ArchiveStreamRead( + new string[] + { + "Rar2.multi.rar", + "Rar2.multi.r00", + "Rar2.multi.r01", + "Rar2.multi.r02", + "Rar2.multi.r03", + "Rar2.multi.r04", + "Rar2.multi.r05" + }, + false + ); } [Fact] @@ -487,138 +512,174 @@ namespace SharpCompress.Test.Rar public void Rar_GetPartsSplit() { //uses first part to search for all parts and compares against this array - ArchiveGetParts(new string[] { - "Rar4.split.001", - "Rar4.split.002", - "Rar4.split.003", - "Rar4.split.004", - "Rar4.split.005", - "Rar4.split.006"}); + ArchiveGetParts( + new string[] + { + "Rar4.split.001", + "Rar4.split.002", + "Rar4.split.003", + "Rar4.split.004", + "Rar4.split.005", + "Rar4.split.006" + } + ); } + [Fact] public void Rar_GetPartsOld() { //uses first part to search for all parts and compares against this array - ArchiveGetParts(new string[] { - "Rar2.multi.rar", - "Rar2.multi.r00", - "Rar2.multi.r01", - "Rar2.multi.r02", - "Rar2.multi.r03", - "Rar2.multi.r04", - "Rar2.multi.r05"}); + ArchiveGetParts( + new string[] + { + "Rar2.multi.rar", + "Rar2.multi.r00", + "Rar2.multi.r01", + "Rar2.multi.r02", + "Rar2.multi.r03", + "Rar2.multi.r04", + "Rar2.multi.r05" + } + ); } + [Fact] public void Rar_GetPartsNew() { //uses first part to search for all parts and compares against this array - ArchiveGetParts(new string[] { - "Rar4.multi.part01.rar", - "Rar4.multi.part02.rar", - "Rar4.multi.part03.rar", - "Rar4.multi.part04.rar", - "Rar4.multi.part05.rar", - "Rar4.multi.part06.rar", - "Rar4.multi.part07.rar"}); + ArchiveGetParts( + new string[] + { + "Rar4.multi.part01.rar", + "Rar4.multi.part02.rar", + "Rar4.multi.part03.rar", + "Rar4.multi.part04.rar", + "Rar4.multi.part05.rar", + "Rar4.multi.part06.rar", + "Rar4.multi.part07.rar" + } + ); } [Fact] public void Rar4_Multi_ArchiveStreamRead() { - DoRar_Multi_ArchiveStreamRead(new string[] { - "Rar4.multi.part01.rar", - "Rar4.multi.part02.rar", - "Rar4.multi.part03.rar", - "Rar4.multi.part04.rar", - "Rar4.multi.part05.rar", - "Rar4.multi.part06.rar", - "Rar4.multi.part07.rar"}, false); + DoRar_Multi_ArchiveStreamRead( + new string[] + { + "Rar4.multi.part01.rar", + "Rar4.multi.part02.rar", + "Rar4.multi.part03.rar", + "Rar4.multi.part04.rar", + "Rar4.multi.part05.rar", + "Rar4.multi.part06.rar", + "Rar4.multi.part07.rar" + }, + false + ); } //no extension to test the lib identifies the archive by content not ext [Fact] public void Rar4_Split_ArchiveStreamRead() { - ArchiveStreamMultiRead(null, new string[] { - "Rar4.split.001", - "Rar4.split.002", - "Rar4.split.003", - "Rar4.split.004", - "Rar4.split.005", - "Rar4.split.006"}); + ArchiveStreamMultiRead( + null, + new string[] + { + "Rar4.split.001", + "Rar4.split.002", + "Rar4.split.003", + "Rar4.split.004", + "Rar4.split.005", + "Rar4.split.006" + } + ); } + //will detect and load other files [Fact] public void Rar4_Multi_ArchiveFirstFileRead() { ArchiveFileRead("Rar4.multi.part01.rar"); - //"Rar4.multi.part02.rar", - //"Rar4.multi.part03.rar", - //"Rar4.multi.part04.rar", - //"Rar4.multi.part05.rar", - //"Rar4.multi.part06.rar", - //"Rar4.multi.part07.rar" + //"Rar4.multi.part02.rar", + //"Rar4.multi.part03.rar", + //"Rar4.multi.part04.rar", + //"Rar4.multi.part05.rar", + //"Rar4.multi.part06.rar", + //"Rar4.multi.part07.rar" } - //will detect and load other files - [Fact] + + //will detect and load other files + [Fact] public void Rar4_Split_ArchiveFirstFileRead() { ArchiveFileRead("Rar4.split.001"); - //"Rar4.split.002", - //"Rar4.split.003", - //"Rar4.split.004", - //"Rar4.split.005", - //"Rar4.split.006" + //"Rar4.split.002", + //"Rar4.split.003", + //"Rar4.split.004", + //"Rar4.split.005", + //"Rar4.split.006" } + //will detect and load other files [Fact] public void Rar4_Split_ArchiveStreamFirstFileRead() { - ArchiveStreamMultiRead(null, new string[] { - "Rar4.split.001", - //"Rar4.split.002", - //"Rar4.split.003", - //"Rar4.split.004", - //"Rar4.split.005", - //"Rar4.split.006" - }); + ArchiveStreamMultiRead( + null, + new string[] + { + "Rar4.split.001", + //"Rar4.split.002", + //"Rar4.split.003", + //"Rar4.split.004", + //"Rar4.split.005", + //"Rar4.split.006" + } + ); } //open with ArchiveFactory.Open and stream [Fact] public void Rar4_Split_ArchiveOpen() { - ArchiveOpenStreamRead(null, + ArchiveOpenStreamRead( + null, "Rar4.split.001", "Rar4.split.002", "Rar4.split.003", "Rar4.split.004", "Rar4.split.005", - "Rar4.split.006"); + "Rar4.split.006" + ); } //open with ArchiveFactory.Open and stream [Fact] public void Rar4_Multi_ArchiveOpen() { - ArchiveOpenStreamRead(null, + ArchiveOpenStreamRead( + null, "Rar4.multi.part01.rar", "Rar4.multi.part02.rar", "Rar4.multi.part03.rar", "Rar4.multi.part04.rar", "Rar4.multi.part05.rar", "Rar4.multi.part06.rar", - "Rar4.multi.part07.rar"); + "Rar4.multi.part07.rar" + ); } [Fact] public void Rar4_Multi_ArchiveOpenEntryVolumeIndexTest() { ArchiveOpenEntryVolumeIndexTest( - new[] { + new[] + { new[] { 0, 1 }, //exe - Rar4.multi.part01.rar to Rar4.multi.part02.rar new[] { 1, 5 }, //jpg - Rar4.multi.part02.rar to Rar4.multi.part06.rar - new[] { 5, 6 } //txt - Rar4.multi.part06.rar to Rar4.multi.part07.rar + new[] { 5, 6 } //txt - Rar4.multi.part06.rar to Rar4.multi.part07.rar }, null, "Rar4.multi.part01.rar", @@ -627,10 +688,11 @@ namespace SharpCompress.Test.Rar "Rar4.multi.part04.rar", "Rar4.multi.part05.rar", "Rar4.multi.part06.rar", - "Rar4.multi.part07.rar"); + "Rar4.multi.part07.rar" + ); } - [Fact] + [Fact] public void Rar_Multi_ArchiveFileRead() { ArchiveFileRead("Rar.multi.part01.rar"); @@ -677,7 +739,9 @@ namespace SharpCompress.Test.Rar private void DoRar_IsFirstVolume_False(string notFirstFilename) { - using (var archive = RarArchive.Open(Path.Combine(TEST_ARCHIVES_PATH, notFirstFilename))) + using ( + var archive = RarArchive.Open(Path.Combine(TEST_ARCHIVES_PATH, notFirstFilename)) + ) { Assert.True(archive.IsMultipartVolume()); Assert.False(archive.IsFirstVolume()); diff --git a/tests/SharpCompress.Test/Rar/RarHeaderFactoryTest.cs b/tests/SharpCompress.Test/Rar/RarHeaderFactoryTest.cs index a9c4c798..745935d2 100644 --- a/tests/SharpCompress.Test/Rar/RarHeaderFactoryTest.cs +++ b/tests/SharpCompress.Test/Rar/RarHeaderFactoryTest.cs @@ -17,7 +17,8 @@ namespace SharpCompress.Test.Rar { rarHeaderFactory = new RarHeaderFactory( StreamingMode.Seekable, - new ReaderOptions { LeaveStreamOpen = true }); + new ReaderOptions { LeaveStreamOpen = true } + ); } [Fact] @@ -46,11 +47,20 @@ namespace SharpCompress.Test.Rar private void ReadEncryptedFlag(string testArchive, bool isEncrypted) { - using (var stream = new FileStream(Path.Combine(TEST_ARCHIVES_PATH, testArchive), FileMode.Open, FileAccess.Read)) + using ( + var stream = new FileStream( + Path.Combine(TEST_ARCHIVES_PATH, testArchive), + FileMode.Open, + FileAccess.Read + ) + ) { foreach (var header in rarHeaderFactory.ReadHeaders(stream)) { - if (header.HeaderType == HeaderType.Archive || header.HeaderType == HeaderType.Crypt) + if ( + header.HeaderType == HeaderType.Archive + || header.HeaderType == HeaderType.Crypt + ) { Assert.Equal(isEncrypted, rarHeaderFactory.IsEncrypted); break; diff --git a/tests/SharpCompress.Test/Rar/RarReaderTests.cs b/tests/SharpCompress.Test/Rar/RarReaderTests.cs index 0ac4e667..bb841475 100644 --- a/tests/SharpCompress.Test/Rar/RarReaderTests.cs +++ b/tests/SharpCompress.Test/Rar/RarReaderTests.cs @@ -13,39 +13,51 @@ namespace SharpCompress.Test.Rar [Fact] public void Rar_Multi_Reader() { - DoRar_Multi_Reader(new string[] { - "Rar.multi.part01.rar", - "Rar.multi.part02.rar", - "Rar.multi.part03.rar", - "Rar.multi.part04.rar", - "Rar.multi.part05.rar", - "Rar.multi.part06.rar"}); + DoRar_Multi_Reader( + new string[] + { + "Rar.multi.part01.rar", + "Rar.multi.part02.rar", + "Rar.multi.part03.rar", + "Rar.multi.part04.rar", + "Rar.multi.part05.rar", + "Rar.multi.part06.rar" + } + ); } [Fact] public void Rar5_Multi_Reader() { - DoRar_Multi_Reader(new string[] { - "Rar5.multi.part01.rar", - "Rar5.multi.part02.rar", - "Rar5.multi.part03.rar", - "Rar5.multi.part04.rar", - "Rar5.multi.part05.rar", - "Rar5.multi.part06.rar"}); + DoRar_Multi_Reader( + new string[] + { + "Rar5.multi.part01.rar", + "Rar5.multi.part02.rar", + "Rar5.multi.part03.rar", + "Rar5.multi.part04.rar", + "Rar5.multi.part05.rar", + "Rar5.multi.part06.rar" + } + ); } private void DoRar_Multi_Reader(string[] archives) { - using (var reader = RarReader.Open(archives.Select(s => Path.Combine(TEST_ARCHIVES_PATH, s)) - .Select(p => File.OpenRead(p)))) + using ( + var reader = RarReader.Open( + archives + .Select(s => Path.Combine(TEST_ARCHIVES_PATH, s)) + .Select(p => File.OpenRead(p)) + ) + ) { while (reader.MoveToNextEntry()) { - reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, new ExtractionOptions() - { - ExtractFullPath = true, - Overwrite = true - }); + reader.WriteEntryToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } + ); } } VerifyFiles(); @@ -54,81 +66,97 @@ namespace SharpCompress.Test.Rar [Fact] public void Rar_Multi_Reader_Encrypted() { - DoRar_Multi_Reader_Encrypted(new string[] { - "Rar.EncryptedParts.part01.rar", - "Rar.EncryptedParts.part02.rar", - "Rar.EncryptedParts.part03.rar", - "Rar.EncryptedParts.part04.rar", - "Rar.EncryptedParts.part05.rar", - "Rar.EncryptedParts.part06.rar"}); + DoRar_Multi_Reader_Encrypted( + new string[] + { + "Rar.EncryptedParts.part01.rar", + "Rar.EncryptedParts.part02.rar", + "Rar.EncryptedParts.part03.rar", + "Rar.EncryptedParts.part04.rar", + "Rar.EncryptedParts.part05.rar", + "Rar.EncryptedParts.part06.rar" + } + ); } private void DoRar_Multi_Reader_Encrypted(string[] archives) { Assert.Throws(() => - { - using (var reader = RarReader.Open(archives.Select(s => Path.Combine(TEST_ARCHIVES_PATH, s)) - .Select(p => File.OpenRead(p)), - new ReaderOptions() - { - Password = "test" - })) - { - while (reader.MoveToNextEntry()) - { - reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, - new ExtractionOptions() - { - ExtractFullPath = true, - Overwrite = true - }); - } - } - VerifyFiles(); - }); + { + using ( + var reader = RarReader.Open( + archives + .Select(s => Path.Combine(TEST_ARCHIVES_PATH, s)) + .Select(p => File.OpenRead(p)), + new ReaderOptions() { Password = "test" } + ) + ) + { + while (reader.MoveToNextEntry()) + { + reader.WriteEntryToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } + ); + } + } + VerifyFiles(); + }); } [Fact] public void Rar_Multi_Reader_Delete_Files() { - DoRar_Multi_Reader_Delete_Files(new string[] { - "Rar.multi.part01.rar", - "Rar.multi.part02.rar", - "Rar.multi.part03.rar", - "Rar.multi.part04.rar", - "Rar.multi.part05.rar", - "Rar.multi.part06.rar"}); + DoRar_Multi_Reader_Delete_Files( + new string[] + { + "Rar.multi.part01.rar", + "Rar.multi.part02.rar", + "Rar.multi.part03.rar", + "Rar.multi.part04.rar", + "Rar.multi.part05.rar", + "Rar.multi.part06.rar" + } + ); } [Fact] public void Rar5_Multi_Reader_Delete_Files() { - DoRar_Multi_Reader_Delete_Files(new string[] { - "Rar5.multi.part01.rar", - "Rar5.multi.part02.rar", - "Rar5.multi.part03.rar", - "Rar5.multi.part04.rar", - "Rar5.multi.part05.rar", - "Rar5.multi.part06.rar"}); + DoRar_Multi_Reader_Delete_Files( + new string[] + { + "Rar5.multi.part01.rar", + "Rar5.multi.part02.rar", + "Rar5.multi.part03.rar", + "Rar5.multi.part04.rar", + "Rar5.multi.part05.rar", + "Rar5.multi.part06.rar" + } + ); } private void DoRar_Multi_Reader_Delete_Files(string[] archives) { - foreach (var file in archives) { - File.Copy(Path.Combine(TEST_ARCHIVES_PATH, file), Path.Combine(SCRATCH2_FILES_PATH, file)); + File.Copy( + Path.Combine(TEST_ARCHIVES_PATH, file), + Path.Combine(SCRATCH2_FILES_PATH, file) + ); } - var streams = archives.Select(s => Path.Combine(SCRATCH2_FILES_PATH, s)).Select(File.OpenRead).ToList(); + var streams = archives + .Select(s => Path.Combine(SCRATCH2_FILES_PATH, s)) + .Select(File.OpenRead) + .ToList(); using (var reader = RarReader.Open(streams)) { while (reader.MoveToNextEntry()) { - reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, new ExtractionOptions() - { - ExtractFullPath = true, - Overwrite = true - }); + reader.WriteEntryToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } + ); } } foreach (var stream in streams) @@ -233,7 +261,9 @@ namespace SharpCompress.Test.Rar using (var entryStream = reader.OpenEntryStream()) { string file = Path.GetFileName(reader.Entry.Key); - string folder = Path.GetDirectoryName(reader.Entry.Key) ?? throw new ArgumentNullException(); + string folder = + Path.GetDirectoryName(reader.Entry.Key) + ?? throw new ArgumentNullException(); string destdir = Path.Combine(SCRATCH_FILES_PATH, folder); if (!Directory.Exists(destdir)) { @@ -255,43 +285,48 @@ namespace SharpCompress.Test.Rar [Fact] public void Rar_Reader_Audio_program() { - using (var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Rar.Audio_program.rar"))) - using (var reader = ReaderFactory.Open(stream, new ReaderOptions() - { - LookForHeader = true - })) + using ( + var stream = File.OpenRead( + Path.Combine(TEST_ARCHIVES_PATH, "Rar.Audio_program.rar") + ) + ) + using ( + var reader = ReaderFactory.Open( + stream, + new ReaderOptions() { LookForHeader = true } + ) + ) { while (reader.MoveToNextEntry()) { Assert.Equal(CompressionType.Rar, reader.Entry.CompressionType); - reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, new ExtractionOptions() - { - ExtractFullPath = true, - Overwrite = true - }); + reader.WriteEntryToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } + ); } } - CompareFilesByPath(Path.Combine(SCRATCH_FILES_PATH, "test.dat"), - Path.Combine(MISC_TEST_FILES_PATH, "test.dat")); + CompareFilesByPath( + Path.Combine(SCRATCH_FILES_PATH, "test.dat"), + Path.Combine(MISC_TEST_FILES_PATH, "test.dat") + ); } [Fact] public void Rar_Jpg_Reader() { using (var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Rar.jpeg.jpg"))) - using (var reader = RarReader.Open(stream, new ReaderOptions() - { - LookForHeader = true - })) + using ( + var reader = RarReader.Open(stream, new ReaderOptions() { LookForHeader = true }) + ) { while (reader.MoveToNextEntry()) { Assert.Equal(CompressionType.Rar, reader.Entry.CompressionType); - reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, new ExtractionOptions() - { - ExtractFullPath = true, - Overwrite = true - }); + reader.WriteEntryToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } + ); } } VerifyFiles(); @@ -324,21 +359,22 @@ namespace SharpCompress.Test.Rar private void DoRar_Solid_Skip_Reader(string filename) { using (var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, filename))) - using (var reader = ReaderFactory.Open(stream, new ReaderOptions() - { - LookForHeader = true - })) + using ( + var reader = ReaderFactory.Open( + stream, + new ReaderOptions() { LookForHeader = true } + ) + ) { while (reader.MoveToNextEntry()) { if (reader.Entry.Key.Contains("jpg")) { Assert.Equal(CompressionType.Rar, reader.Entry.CompressionType); - reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, new ExtractionOptions() - { - ExtractFullPath = true, - Overwrite = true - }); + reader.WriteEntryToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } + ); } } } @@ -359,21 +395,22 @@ namespace SharpCompress.Test.Rar private void DoRar_Reader_Skip(string filename) { using (var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, filename))) - using (var reader = ReaderFactory.Open(stream, new ReaderOptions() - { - LookForHeader = true - })) + using ( + var reader = ReaderFactory.Open( + stream, + new ReaderOptions() { LookForHeader = true } + ) + ) { while (reader.MoveToNextEntry()) { if (reader.Entry.Key.Contains("jpg")) { Assert.Equal(CompressionType.Rar, reader.Entry.CompressionType); - reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, new ExtractionOptions() - { - ExtractFullPath = true, - Overwrite = true - }); + reader.WriteEntryToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } + ); } } } diff --git a/tests/SharpCompress.Test/ReaderTests.cs b/tests/SharpCompress.Test/ReaderTests.cs index 4d230a20..8d02d1e6 100644 --- a/tests/SharpCompress.Test/ReaderTests.cs +++ b/tests/SharpCompress.Test/ReaderTests.cs @@ -9,7 +9,11 @@ namespace SharpCompress.Test { public abstract class ReaderTests : TestBase { - protected void Read(string testArchive, CompressionType expectedCompression, ReaderOptions? options = null) + protected void Read( + string testArchive, + CompressionType expectedCompression, + ReaderOptions? options = null + ) { testArchive = Path.Combine(TEST_ARCHIVES_PATH, testArchive); @@ -23,11 +27,20 @@ namespace SharpCompress.Test VerifyFiles(); } - private void ReadImpl(string testArchive, CompressionType expectedCompression, ReaderOptions options) + private void ReadImpl( + string testArchive, + CompressionType expectedCompression, + ReaderOptions options + ) { using (var file = File.OpenRead(testArchive)) { - using (var protectedStream = NonDisposingStream.Create(new ForwardOnlyStream(file), throwOnDispose: true)) + using ( + var protectedStream = NonDisposingStream.Create( + new ForwardOnlyStream(file), + throwOnDispose: true + ) + ) { using (var testStream = new TestStream(protectedStream)) { @@ -35,12 +48,16 @@ namespace SharpCompress.Test { UseReader(reader, expectedCompression); protectedStream.ThrowOnDispose = false; - Assert.False(testStream.IsDisposed, "{nameof(testStream)} prematurely closed"); + Assert.False( + testStream.IsDisposed, + "{nameof(testStream)} prematurely closed" + ); } // Boolean XOR -- If the stream should be left open (true), then the stream should not be diposed (false) // and if the stream should be closed (false), then the stream should be disposed (true) - var message = $"{nameof(options.LeaveStreamOpen)} is set to '{options.LeaveStreamOpen}', so {nameof(testStream.IsDisposed)} should be set to '{!testStream.IsDisposed}', but is set to {testStream.IsDisposed}"; + var message = + $"{nameof(options.LeaveStreamOpen)} is set to '{options.LeaveStreamOpen}', so {nameof(testStream.IsDisposed)} should be set to '{!testStream.IsDisposed}', but is set to {testStream.IsDisposed}"; Assert.True(options.LeaveStreamOpen != testStream.IsDisposed, message); } } @@ -54,11 +71,10 @@ namespace SharpCompress.Test if (!reader.Entry.IsDirectory) { Assert.Equal(expectedCompression, reader.Entry.CompressionType); - reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, new ExtractionOptions() - { - ExtractFullPath = true, - Overwrite = true - }); + reader.WriteEntryToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } + ); } } } diff --git a/tests/SharpCompress.Test/SevenZip/SevenZipArchiveTests.cs b/tests/SharpCompress.Test/SevenZip/SevenZipArchiveTests.cs index ad1c71ed..4532a613 100644 --- a/tests/SharpCompress.Test/SevenZip/SevenZipArchiveTests.cs +++ b/tests/SharpCompress.Test/SevenZip/SevenZipArchiveTests.cs @@ -12,11 +12,13 @@ namespace SharpCompress.Test.SevenZip { ArchiveStreamRead("7Zip.solid.7z"); } + [Fact] public void SevenZipArchive_NonSolid_StreamRead() { ArchiveStreamRead("7Zip.nonsolid.7z"); } + [Fact] public void SevenZipArchive_LZMA_StreamRead() { @@ -32,7 +34,10 @@ namespace SharpCompress.Test.SevenZip [Fact] public void SevenZipArchive_LZMAAES_StreamRead() { - ArchiveStreamRead("7Zip.LZMA.Aes.7z", new ReaderOptions() { Password = "testpassword" }); + ArchiveStreamRead( + "7Zip.LZMA.Aes.7z", + new ReaderOptions() { Password = "testpassword" } + ); } [Fact] @@ -40,11 +45,16 @@ namespace SharpCompress.Test.SevenZip { ArchiveFileRead("7Zip.LZMA.Aes.7z", new ReaderOptions() { Password = "testpassword" }); } + [Fact] public void SevenZipArchive_LZMAAES_NoPasswordExceptionTest() { - Assert.Throws(typeof(CryptographicException), () => ArchiveFileRead("7Zip.LZMA.Aes.7z", new ReaderOptions() { Password = null })); //was failing with ArgumentNullException not CryptographicException like rar + Assert.Throws( + typeof(CryptographicException), + () => ArchiveFileRead("7Zip.LZMA.Aes.7z", new ReaderOptions() { Password = null }) + ); //was failing with ArgumentNullException not CryptographicException like rar } + [Fact] public void SevenZipArchive_PPMd_StreamRead() { @@ -108,26 +118,35 @@ namespace SharpCompress.Test.SevenZip [Fact] public void SevenZipArchive_BZip2_Split() { - Assert.Throws(() => ArchiveStreamRead(null, "Original.7z.001", - "Original.7z.002", - "Original.7z.003", - "Original.7z.004", - "Original.7z.005", - "Original.7z.006", - "Original.7z.007")); + Assert.Throws( + () => + ArchiveStreamRead( + null, + "Original.7z.001", + "Original.7z.002", + "Original.7z.003", + "Original.7z.004", + "Original.7z.005", + "Original.7z.006", + "Original.7z.007" + ) + ); } //Same as archive as Original.7z.001 ... 007 files without the root directory 'Original\' in the archive - this caused the verify to fail [Fact] public void SevenZipArchive_BZip2_Split_Working() { - ArchiveStreamMultiRead(null, "7Zip.BZip2.split.001", - "7Zip.BZip2.split.002", - "7Zip.BZip2.split.003", - "7Zip.BZip2.split.004", - "7Zip.BZip2.split.005", - "7Zip.BZip2.split.006", - "7Zip.BZip2.split.007"); + ArchiveStreamMultiRead( + null, + "7Zip.BZip2.split.001", + "7Zip.BZip2.split.002", + "7Zip.BZip2.split.003", + "7Zip.BZip2.split.004", + "7Zip.BZip2.split.005", + "7Zip.BZip2.split.006", + "7Zip.BZip2.split.007" + ); } //will detect and load other files @@ -135,14 +154,12 @@ namespace SharpCompress.Test.SevenZip public void SevenZipArchive_BZip2_Split_FirstFileRead() { ArchiveFileRead("7Zip.BZip2.split.001"); - //"7Zip.BZip2.split.002", - //"7Zip.BZip2.split.003", - //"7Zip.BZip2.split.004", - //"7Zip.BZip2.split.005", - //"7Zip.BZip2.split.006", - //"7Zip.BZip2.split.007" + //"7Zip.BZip2.split.002", + //"7Zip.BZip2.split.003", + //"7Zip.BZip2.split.004", + //"7Zip.BZip2.split.005", + //"7Zip.BZip2.split.006", + //"7Zip.BZip2.split.007" } - - } } diff --git a/tests/SharpCompress.Test/Streams/LzmaStreamTests.cs b/tests/SharpCompress.Test/Streams/LzmaStreamTests.cs index fd14be48..54ac757b 100644 --- a/tests/SharpCompress.Test/Streams/LzmaStreamTests.cs +++ b/tests/SharpCompress.Test/Streams/LzmaStreamTests.cs @@ -1,4 +1,3 @@ - using System; using System.IO; using SharpCompress.Compressors.LZMA; @@ -19,44 +18,497 @@ namespace SharpCompress.Test.Streams Assert.Equal('X', decompressor.ReadByte()); } - private static byte[] lzmaData { get; } = new byte[] { - 0x5D, 0x00, 0x20, 0x00, 0x00, 0x48, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x24, 0x18, 0x2F, 0xEB, 0x20, 0x78, 0xBA, 0x78, 0x70, 0xDC, 0x43, 0x2C, 0x32, 0xC9, - 0xC3, 0x97, 0x4D, 0x10, 0x74, 0xE2, 0x20, 0xBF, 0x5A, 0xB4, 0xB3, 0xC4, 0x31, 0x80, 0x26, - 0x3E, 0x6A, 0xEA, 0x51, 0xFC, 0xE4, 0x8D, 0x54, 0x96, 0x05, 0xCC, 0x78, 0x59, 0xAC, 0xD4, - 0x21, 0x65, 0x8F, 0xA9, 0xC8, 0x0D, 0x9B, 0xE2, 0xC2, 0xF9, 0x7C, 0x3C, 0xDD, 0x4D, 0x38, - 0x04, 0x0B, 0xF8, 0x0B, 0x68, 0xA5, 0x93, 0x6C, 0x64, 0xAC, 0xCF, 0x71, 0x68, 0xE8, 0x69, - 0x25, 0xC6, 0x17, 0x28, 0xF1, 0x7C, 0xF1, 0xDC, 0x47, 0x51, 0x4D, 0x1E, 0x0E, 0x0B, 0x80, - 0x37, 0x24, 0x58, 0x80, 0xF7, 0xB4, 0xAC, 0x54, 0xF1, 0x0F, 0x7F, 0x0F, 0x0F, 0xF5, 0x9C, - 0xDE, 0x54, 0x4F, 0xA3, 0x7B, 0x20, 0xC5, 0xA8, 0x18, 0x3B, 0xED, 0xDC, 0x04, 0xF6, 0xFB, - 0x86, 0xE0, 0xAB, 0xB6, 0x87, 0x99, 0x92, 0x43, 0x7B, 0x2C, 0xCC, 0x31, 0x83, 0x90, 0xFF, - 0xF1, 0x76, 0x03, 0x90 - }; + private static byte[] lzmaData { get; } = + new byte[] + { + 0x5D, + 0x00, + 0x20, + 0x00, + 0x00, + 0x48, + 0x01, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x80, + 0x24, + 0x18, + 0x2F, + 0xEB, + 0x20, + 0x78, + 0xBA, + 0x78, + 0x70, + 0xDC, + 0x43, + 0x2C, + 0x32, + 0xC9, + 0xC3, + 0x97, + 0x4D, + 0x10, + 0x74, + 0xE2, + 0x20, + 0xBF, + 0x5A, + 0xB4, + 0xB3, + 0xC4, + 0x31, + 0x80, + 0x26, + 0x3E, + 0x6A, + 0xEA, + 0x51, + 0xFC, + 0xE4, + 0x8D, + 0x54, + 0x96, + 0x05, + 0xCC, + 0x78, + 0x59, + 0xAC, + 0xD4, + 0x21, + 0x65, + 0x8F, + 0xA9, + 0xC8, + 0x0D, + 0x9B, + 0xE2, + 0xC2, + 0xF9, + 0x7C, + 0x3C, + 0xDD, + 0x4D, + 0x38, + 0x04, + 0x0B, + 0xF8, + 0x0B, + 0x68, + 0xA5, + 0x93, + 0x6C, + 0x64, + 0xAC, + 0xCF, + 0x71, + 0x68, + 0xE8, + 0x69, + 0x25, + 0xC6, + 0x17, + 0x28, + 0xF1, + 0x7C, + 0xF1, + 0xDC, + 0x47, + 0x51, + 0x4D, + 0x1E, + 0x0E, + 0x0B, + 0x80, + 0x37, + 0x24, + 0x58, + 0x80, + 0xF7, + 0xB4, + 0xAC, + 0x54, + 0xF1, + 0x0F, + 0x7F, + 0x0F, + 0x0F, + 0xF5, + 0x9C, + 0xDE, + 0x54, + 0x4F, + 0xA3, + 0x7B, + 0x20, + 0xC5, + 0xA8, + 0x18, + 0x3B, + 0xED, + 0xDC, + 0x04, + 0xF6, + 0xFB, + 0x86, + 0xE0, + 0xAB, + 0xB6, + 0x87, + 0x99, + 0x92, + 0x43, + 0x7B, + 0x2C, + 0xCC, + 0x31, + 0x83, + 0x90, + 0xFF, + 0xF1, + 0x76, + 0x03, + 0x90 + }; - private static byte[] lzmaResultData { get; } = new byte[] { - 0x01, 0x00, 0xFD, 0x01, 0x00, 0x00, 0x00, 0x00, 0xFA, 0x61, 0x18, 0x5F, 0x02, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, - 0x00, 0x00, 0x02, 0x00, 0xB4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x3D, 0x61, 0xE5, 0x5E, 0x03, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x12, 0x00, 0x00, 0x00, 0x02, 0x00, 0xB4, 0x01, 0x00, 0x00, 0x00, 0x00, 0xE2, 0x61, 0x18, - 0x5F, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, - 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x01, 0x00, 0xFD, 0x01, 0x00, 0x00, 0x00, 0x00, 0x14, - 0x62, 0x18, 0x5F, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x40, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x02, 0x00, 0xB4, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x7F, 0x61, 0xE5, 0x5E, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x3B, 0x00, 0x00, 0x00, 0xCB, 0x15, 0x00, 0x00, 0x02, 0x00, 0xB4, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x7F, 0x61, 0xE5, 0x5E, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x00, 0x00, 0xCB, 0x15, 0x00, 0x00, 0x02, 0x00, 0xB4, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x3D, 0x61, 0xE5, 0x5E, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x02, - 0x00, 0xB4, 0x01, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x96, 0x40, 0x5C, 0x08, 0x00, 0x00, 0x00, - 0x60, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x83, 0x12, - 0x00, 0xD4, 0x99, 0x00, 0x00, 0x43, 0x95, 0x00, 0x00, 0xEB, 0x7A, 0x00, 0x00, 0x40, 0x6F, - 0x00, 0x00, 0xD2, 0x6F, 0x00, 0x00, 0x67, 0x74, 0x00, 0x00, 0x02, 0x69, 0x00, 0x00, 0x76, - 0x79, 0x00, 0x00, 0x98, 0x66, 0x00, 0x00, 0x23, 0x25, 0x00, 0x00, 0x01, 0x00, 0xFD, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x3B, 0x2F, 0xC0, 0x5F, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x03, 0x00, 0x00, 0x00, 0x69, 0x00, 0x3D, 0x00, 0x0A, 0x00, 0x00, 0x00 - }; + private static byte[] lzmaResultData { get; } = + new byte[] + { + 0x01, + 0x00, + 0xFD, + 0x01, + 0x00, + 0x00, + 0x00, + 0x00, + 0xFA, + 0x61, + 0x18, + 0x5F, + 0x02, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x02, + 0x00, + 0x00, + 0x00, + 0x03, + 0x00, + 0x00, + 0x00, + 0x01, + 0x00, + 0x00, + 0x00, + 0x02, + 0x00, + 0xB4, + 0x01, + 0x00, + 0x00, + 0x00, + 0x00, + 0x3D, + 0x61, + 0xE5, + 0x5E, + 0x03, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x12, + 0x00, + 0x00, + 0x00, + 0x02, + 0x00, + 0xB4, + 0x01, + 0x00, + 0x00, + 0x00, + 0x00, + 0xE2, + 0x61, + 0x18, + 0x5F, + 0x04, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x12, + 0x00, + 0x00, + 0x00, + 0x29, + 0x00, + 0x00, + 0x00, + 0x01, + 0x00, + 0xFD, + 0x01, + 0x00, + 0x00, + 0x00, + 0x00, + 0x14, + 0x62, + 0x18, + 0x5F, + 0x01, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x03, + 0x00, + 0x00, + 0x00, + 0x40, + 0x00, + 0x00, + 0x00, + 0x09, + 0x00, + 0x00, + 0x00, + 0x02, + 0x00, + 0xB4, + 0x01, + 0x00, + 0x00, + 0x00, + 0x00, + 0x7F, + 0x61, + 0xE5, + 0x5E, + 0x05, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x3B, + 0x00, + 0x00, + 0x00, + 0xCB, + 0x15, + 0x00, + 0x00, + 0x02, + 0x00, + 0xB4, + 0x01, + 0x00, + 0x00, + 0x00, + 0x00, + 0x7F, + 0x61, + 0xE5, + 0x5E, + 0x06, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x3B, + 0x00, + 0x00, + 0x00, + 0xCB, + 0x15, + 0x00, + 0x00, + 0x02, + 0x00, + 0xB4, + 0x01, + 0x00, + 0x00, + 0x00, + 0x00, + 0x3D, + 0x61, + 0xE5, + 0x5E, + 0x07, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x12, + 0x00, + 0x00, + 0x00, + 0x02, + 0x00, + 0xB4, + 0x01, + 0x00, + 0x00, + 0x00, + 0x00, + 0xFC, + 0x96, + 0x40, + 0x5C, + 0x08, + 0x00, + 0x00, + 0x00, + 0x60, + 0x00, + 0x00, + 0x00, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0x00, + 0x00, + 0x00, + 0x00, + 0xF8, + 0x83, + 0x12, + 0x00, + 0xD4, + 0x99, + 0x00, + 0x00, + 0x43, + 0x95, + 0x00, + 0x00, + 0xEB, + 0x7A, + 0x00, + 0x00, + 0x40, + 0x6F, + 0x00, + 0x00, + 0xD2, + 0x6F, + 0x00, + 0x00, + 0x67, + 0x74, + 0x00, + 0x00, + 0x02, + 0x69, + 0x00, + 0x00, + 0x76, + 0x79, + 0x00, + 0x00, + 0x98, + 0x66, + 0x00, + 0x00, + 0x23, + 0x25, + 0x00, + 0x00, + 0x01, + 0x00, + 0xFD, + 0x01, + 0x00, + 0x00, + 0x00, + 0x00, + 0x3B, + 0x2F, + 0xC0, + 0x5F, + 0x09, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x03, + 0x00, + 0x00, + 0x00, + 0x69, + 0x00, + 0x3D, + 0x00, + 0x0A, + 0x00, + 0x00, + 0x00 + }; [Fact] public void TestLzmaBuffer() diff --git a/tests/SharpCompress.Test/Streams/ZlibBaseStreamTests.cs b/tests/SharpCompress.Test/Streams/ZlibBaseStreamTests.cs index 51d2085b..99bdeb38 100644 --- a/tests/SharpCompress.Test/Streams/ZlibBaseStreamTests.cs +++ b/tests/SharpCompress.Test/Streams/ZlibBaseStreamTests.cs @@ -13,7 +13,29 @@ namespace SharpCompress.Test.Streams [Fact] public void TestChunkedZlibCompressesEverything() { - byte[] plainData = new byte[] { 0xf7, 0x1b, 0xda, 0x0f, 0xb6, 0x2b, 0x3d, 0x91, 0xd7, 0xe1, 0xb5, 0x11, 0x34, 0x5a, 0x51, 0x3f, 0x8b, 0xce, 0x49, 0xd2 }; + byte[] plainData = new byte[] + { + 0xf7, + 0x1b, + 0xda, + 0x0f, + 0xb6, + 0x2b, + 0x3d, + 0x91, + 0xd7, + 0xe1, + 0xb5, + 0x11, + 0x34, + 0x5a, + 0x51, + 0x3f, + 0x8b, + 0xce, + 0x49, + 0xd2 + }; byte[] buf = new byte[plainData.Length * 2]; MemoryStream plainStream1 = new MemoryStream(plainData); @@ -34,11 +56,11 @@ namespace SharpCompress.Test.Streams Assert.Equal(total, realCompressedSize); } - + [Fact] public void Zlib_should_read_the_previously_written_message() { - var message = new string('a', 131073); // 131073 causes the failure, but 131072 (-1) doesn't + var message = new string('a', 131073); // 131073 causes the failure, but 131072 (-1) doesn't var bytes = Encoding.ASCII.GetBytes(message); using (var inputStream = new MemoryStream(bytes)) @@ -63,7 +85,13 @@ namespace SharpCompress.Test.Streams private void Compress(Stream input, Stream output, int compressionLevel) { - using (var zlibStream = new ZlibStream(NonDisposingStream.Create(output), CompressionMode.Compress, (CompressionLevel)compressionLevel)) + using ( + var zlibStream = new ZlibStream( + NonDisposingStream.Create(output), + CompressionMode.Compress, + (CompressionLevel)compressionLevel + ) + ) { zlibStream.FlushMode = FlushType.Sync; input.CopyTo(zlibStream); @@ -72,7 +100,12 @@ namespace SharpCompress.Test.Streams private void Decompress(Stream input, Stream output) { - using (var zlibStream = new ZlibStream(NonDisposingStream.Create(input), CompressionMode.Decompress)) + using ( + var zlibStream = new ZlibStream( + NonDisposingStream.Create(input), + CompressionMode.Decompress + ) + ) { zlibStream.CopyTo(output); } diff --git a/tests/SharpCompress.Test/Tar/TarArchiveTests.cs b/tests/SharpCompress.Test/Tar/TarArchiveTests.cs index 17da414d..45b32694 100644 --- a/tests/SharpCompress.Test/Tar/TarArchiveTests.cs +++ b/tests/SharpCompress.Test/Tar/TarArchiveTests.cs @@ -37,9 +37,9 @@ namespace SharpCompress.Test.Tar { string archive = "Tar_FileName_Exactly_100_Characters.tar"; - // create the 100 char filename - string filename = "filename_with_exactly_100_characters_______________________________________________________________X"; + string filename = + "filename_with_exactly_100_characters_______________________________________________________________X"; // Step 1: create a tar file containing a file with the test name using (Stream stream = File.OpenWrite(Path.Combine(SCRATCH2_FILES_PATH, archive))) @@ -63,7 +63,10 @@ namespace SharpCompress.Test.Tar foreach (var entry in archive2.Entries) { - Assert.Equal("dummy filecontent", new StreamReader(entry.OpenEntryStream()).ReadLine()); + Assert.Equal( + "dummy filecontent", + new StreamReader(entry.OpenEntryStream()).ReadLine() + ); } } } @@ -76,7 +79,10 @@ namespace SharpCompress.Test.Tar { Assert.Equal(5, archive.Entries.Count); Assert.Contains("very long filename/", archive.Entries.Select(entry => entry.Key)); - Assert.Contains("very long filename/very long filename very long filename very long filename very long filename very long filename very long filename very long filename very long filename very long filename very long filename.jpg", archive.Entries.Select(entry => entry.Key)); + Assert.Contains( + "very long filename/very long filename very long filename very long filename very long filename very long filename very long filename very long filename very long filename very long filename very long filename.jpg", + archive.Entries.Select(entry => entry.Key) + ); Assert.Contains("z_file 1.txt", archive.Entries.Select(entry => entry.Key)); Assert.Contains("z_file 2.txt", archive.Entries.Select(entry => entry.Key)); Assert.Contains("z_file 3.txt", archive.Entries.Select(entry => entry.Key)); @@ -88,7 +94,6 @@ namespace SharpCompress.Test.Tar { string archive = "Tar_VeryLongFilepathReadback.tar"; - // create a very long filename string longFilename = ""; for (int i = 0; i < 600; i = longFilename.Length) @@ -120,7 +125,10 @@ namespace SharpCompress.Test.Tar foreach (var entry in archive2.Entries) { - Assert.Equal("dummy filecontent", new StreamReader(entry.OpenEntryStream()).ReadLine()); + Assert.Equal( + "dummy filecontent", + new StreamReader(entry.OpenEntryStream()).ReadLine() + ); } } } @@ -133,11 +141,26 @@ namespace SharpCompress.Test.Tar { Assert.Equal(6, archive.Entries.Count); Assert.Contains("Directory/", archive.Entries.Select(entry => entry.Key)); - Assert.Contains("Directory/Some file with veeeeeeeeeery loooooooooong name", archive.Entries.Select(entry => entry.Key)); - Assert.Contains("Directory/Directory with veeeeeeeeeery loooooooooong name/", archive.Entries.Select(entry => entry.Key)); - Assert.Contains("Directory/Directory with veeeeeeeeeery loooooooooong name/Some file with veeeeeeeeeery loooooooooong name", archive.Entries.Select(entry => entry.Key)); - Assert.Contains("Directory/Directory with veeeeeeeeeery loooooooooong name/Directory with veeeeeeeeeery loooooooooong name/", archive.Entries.Select(entry => entry.Key)); - Assert.Contains("Directory/Directory with veeeeeeeeeery loooooooooong name/Directory with veeeeeeeeeery loooooooooong name/Some file with veeeeeeeeeery loooooooooong name", archive.Entries.Select(entry => entry.Key)); + Assert.Contains( + "Directory/Some file with veeeeeeeeeery loooooooooong name", + archive.Entries.Select(entry => entry.Key) + ); + Assert.Contains( + "Directory/Directory with veeeeeeeeeery loooooooooong name/", + archive.Entries.Select(entry => entry.Key) + ); + Assert.Contains( + "Directory/Directory with veeeeeeeeeery loooooooooong name/Some file with veeeeeeeeeery loooooooooong name", + archive.Entries.Select(entry => entry.Key) + ); + Assert.Contains( + "Directory/Directory with veeeeeeeeeery loooooooooong name/Directory with veeeeeeeeeery loooooooooong name/", + archive.Entries.Select(entry => entry.Key) + ); + Assert.Contains( + "Directory/Directory with veeeeeeeeeery loooooooooong name/Directory with veeeeeeeeeery loooooooooong name/Some file with veeeeeeeeeery loooooooooong name", + archive.Entries.Select(entry => entry.Key) + ); } } @@ -161,6 +184,7 @@ namespace SharpCompress.Test.Tar } CompareArchivesByPath(unmodified, scratchPath); } + [Fact] public void Tar_Random_Write_Add() { @@ -186,7 +210,9 @@ namespace SharpCompress.Test.Tar using (var archive = TarArchive.Open(unmodified)) { - var entry = archive.Entries.Single(x => x.Key.EndsWith("jpg", StringComparison.OrdinalIgnoreCase)); + var entry = archive.Entries.Single( + x => x.Key.EndsWith("jpg", StringComparison.OrdinalIgnoreCase) + ); archive.RemoveEntry(entry); archive.SaveTo(scratchPath, CompressionType.None); } @@ -214,6 +240,7 @@ namespace SharpCompress.Test.Tar Assert.True(archive.Type == ArchiveType.Tar); } } + [Theory] [InlineData(10)] [InlineData(128)] @@ -221,10 +248,7 @@ namespace SharpCompress.Test.Tar { using (var mstm = new MemoryStream()) { - var enc = new ArchiveEncoding() - { - Default = Encoding.UTF8 - }; + var enc = new ArchiveEncoding() { Default = Encoding.UTF8 }; var twopt = new TarWriterOptions(CompressionType.None, true); twopt.ArchiveEncoding = enc; var fname = new string((char)0x3042, length); @@ -235,10 +259,7 @@ namespace SharpCompress.Test.Tar } using (var inputMemory = new MemoryStream(mstm.ToArray())) { - var tropt = new ReaderOptions() - { - ArchiveEncoding = enc - }; + var tropt = new ReaderOptions() { ArchiveEncoding = enc }; using (var tr = TarReader.Open(inputMemory, tropt)) { while (tr.MoveToNextEntry()) @@ -254,7 +275,10 @@ namespace SharpCompress.Test.Tar public void Tar_Read_One_At_A_Time() { var archiveEncoding = new ArchiveEncoding { Default = Encoding.UTF8, }; - var tarWriterOptions = new TarWriterOptions(CompressionType.None, true) { ArchiveEncoding = archiveEncoding, }; + var tarWriterOptions = new TarWriterOptions(CompressionType.None, true) + { + ArchiveEncoding = archiveEncoding, + }; var testBytes = Encoding.UTF8.GetBytes("This is a test."); using (var memoryStream = new MemoryStream()) diff --git a/tests/SharpCompress.Test/Tar/TarReaderTests.cs b/tests/SharpCompress.Test/Tar/TarReaderTests.cs index 4e299dd2..966b82bf 100644 --- a/tests/SharpCompress.Test/Tar/TarReaderTests.cs +++ b/tests/SharpCompress.Test/Tar/TarReaderTests.cs @@ -25,7 +25,11 @@ namespace SharpCompress.Test.Tar [Fact] public void Tar_Skip() { - using (Stream stream = new ForwardOnlyStream(File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar")))) + using ( + Stream stream = new ForwardOnlyStream( + File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar")) + ) + ) using (IReader reader = ReaderFactory.Open(stream)) { int x = 0; @@ -36,12 +40,10 @@ namespace SharpCompress.Test.Tar x++; if (x % 2 == 0) { - reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, - new ExtractionOptions() - { - ExtractFullPath = true, - Overwrite = true - }); + reader.WriteEntryToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } + ); } } } @@ -86,7 +88,9 @@ namespace SharpCompress.Test.Tar using (var entryStream = reader.OpenEntryStream()) { string file = Path.GetFileName(reader.Entry.Key); - string folder = Path.GetDirectoryName(reader.Entry.Key) ?? throw new ArgumentNullException(); + string folder = + Path.GetDirectoryName(reader.Entry.Key) + ?? throw new ArgumentNullException(); string destdir = Path.Combine(SCRATCH_FILES_PATH, folder); if (!Directory.Exists(destdir)) { @@ -110,7 +114,11 @@ namespace SharpCompress.Test.Tar { var filePaths = new List(); - using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.LongPathsWithLongNameExtension.tar"))) + using ( + Stream stream = File.OpenRead( + Path.Combine(TEST_ARCHIVES_PATH, "Tar.LongPathsWithLongNameExtension.tar") + ) + ) using (var reader = TarReader.Open(stream)) { while (reader.MoveToNextEntry()) @@ -124,8 +132,14 @@ namespace SharpCompress.Test.Tar Assert.Equal(3, filePaths.Count); Assert.Contains("a.txt", filePaths); - Assert.Contains("wp-content/plugins/gravityformsextend/lib/Aws/Symfony/Component/ClassLoader/Tests/Fixtures/Apc/beta/Apc/ApcPrefixCollision/A/B/Bar.php", filePaths); - Assert.Contains("wp-content/plugins/gravityformsextend/lib/Aws/Symfony/Component/ClassLoader/Tests/Fixtures/Apc/beta/Apc/ApcPrefixCollision/A/B/Foo.php", filePaths); + Assert.Contains( + "wp-content/plugins/gravityformsextend/lib/Aws/Symfony/Component/ClassLoader/Tests/Fixtures/Apc/beta/Apc/ApcPrefixCollision/A/B/Bar.php", + filePaths + ); + Assert.Contains( + "wp-content/plugins/gravityformsextend/lib/Aws/Symfony/Component/ClassLoader/Tests/Fixtures/Apc/beta/Apc/ApcPrefixCollision/A/B/Foo.php", + filePaths + ); } [Fact] @@ -174,17 +188,15 @@ namespace SharpCompress.Test.Tar using (var entryStream = reader.OpenEntryStream()) { - - using (FlushOnDisposeStream flushingStream = new FlushOnDisposeStream(entryStream)) + using ( + FlushOnDisposeStream flushingStream = new FlushOnDisposeStream(entryStream) + ) { - // Extract inner.tar.gz using (var innerReader = ReaderFactory.Open(flushingStream)) { - Assert.True(innerReader.MoveToNextEntry()); Assert.Equal("test", innerReader.Entry.Key); - } } } @@ -196,8 +208,13 @@ namespace SharpCompress.Test.Tar public void Tar_GZip_With_Symlink_Entries() { var isWindows = System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform( - System.Runtime.InteropServices.OSPlatform.Windows); - using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "TarWithSymlink.tar.gz"))) + System.Runtime.InteropServices.OSPlatform.Windows + ); + using ( + Stream stream = File.OpenRead( + Path.Combine(TEST_ARCHIVES_PATH, "TarWithSymlink.tar.gz") + ) + ) using (var reader = TarReader.Open(stream)) { List names = new List(); @@ -207,24 +224,26 @@ namespace SharpCompress.Test.Tar { continue; } - reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, - new ExtractionOptions() - { - ExtractFullPath = true, - Overwrite = true, - WriteSymbolicLink = (sourcePath, targetPath) => - { - if (!isWindows) - { - var link = new Mono.Unix.UnixSymbolicLinkInfo(sourcePath); - if (File.Exists(sourcePath)) - { - link.Delete(); // equivalent to ln -s -f - } - link.CreateSymbolicLinkTo(targetPath); - } - } - }); + reader.WriteEntryToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() + { + ExtractFullPath = true, + Overwrite = true, + WriteSymbolicLink = (sourcePath, targetPath) => + { + if (!isWindows) + { + var link = new Mono.Unix.UnixSymbolicLinkInfo(sourcePath); + if (File.Exists(sourcePath)) + { + link.Delete(); // equivalent to ln -s -f + } + link.CreateSymbolicLinkTo(targetPath); + } + } + } + ); if (!isWindows) { if (reader.Entry.LinkTarget != null) @@ -236,8 +255,10 @@ namespace SharpCompress.Test.Tar // need to convert the link to an absolute path for comparison var target = reader.Entry.LinkTarget; var realTarget = System.IO.Path.GetFullPath( - System.IO.Path.Combine($"{System.IO.Path.GetDirectoryName(path)}", - target) + System.IO.Path.Combine( + $"{System.IO.Path.GetDirectoryName(path)}", + target + ) ); Assert.Equal(realTarget, link.GetContents().ToString()); @@ -252,6 +273,5 @@ namespace SharpCompress.Test.Tar } } #endif - } } diff --git a/tests/SharpCompress.Test/Tar/TarWriterTests.cs b/tests/SharpCompress.Test/Tar/TarWriterTests.cs index e38e61f9..d9bff3d8 100644 --- a/tests/SharpCompress.Test/Tar/TarWriterTests.cs +++ b/tests/SharpCompress.Test/Tar/TarWriterTests.cs @@ -8,8 +8,7 @@ namespace SharpCompress.Test.Tar { public class TarWriterTests : WriterTests { - public TarWriterTests() - : base(ArchiveType.Tar) + public TarWriterTests() : base(ArchiveType.Tar) { UseExtensionInsteadOfNameToVerify = true; } @@ -17,25 +16,47 @@ namespace SharpCompress.Test.Tar [Fact] public void Tar_Writer() { - Write(CompressionType.None, "Tar.noEmptyDirs.tar", "Tar.noEmptyDirs.tar", Encoding.GetEncoding(866)); + Write( + CompressionType.None, + "Tar.noEmptyDirs.tar", + "Tar.noEmptyDirs.tar", + Encoding.GetEncoding(866) + ); } [Fact] public void Tar_BZip2_Writer() { - Write(CompressionType.BZip2, "Tar.noEmptyDirs.tar.bz2", "Tar.noEmptyDirs.tar.bz2", Encoding.GetEncoding(866)); + Write( + CompressionType.BZip2, + "Tar.noEmptyDirs.tar.bz2", + "Tar.noEmptyDirs.tar.bz2", + Encoding.GetEncoding(866) + ); } [Fact] public void Tar_LZip_Writer() { - Write(CompressionType.LZip, "Tar.noEmptyDirs.tar.lz", "Tar.noEmptyDirs.tar.lz", Encoding.GetEncoding(866)); + Write( + CompressionType.LZip, + "Tar.noEmptyDirs.tar.lz", + "Tar.noEmptyDirs.tar.lz", + Encoding.GetEncoding(866) + ); } [Fact] public void Tar_Rar_Write() { - Assert.Throws(() => Write(CompressionType.Rar, "Zip.ppmd.noEmptyDirs.zip", "Zip.ppmd.noEmptyDirs.zip")); + Assert.Throws( + () => + Write( + CompressionType.Rar, + "Zip.ppmd.noEmptyDirs.zip", + "Zip.ppmd.noEmptyDirs.zip" + ) + ); } [Theory] @@ -44,15 +65,24 @@ namespace SharpCompress.Test.Tar public void Tar_Finalize_Archive(bool finalizeArchive) { using (MemoryStream stream = new MemoryStream()) - using (Stream content = File.OpenRead(Path.Combine(ORIGINAL_FILES_PATH, "jpg", "test.jpg"))) + using ( + Stream content = File.OpenRead(Path.Combine(ORIGINAL_FILES_PATH, "jpg", "test.jpg")) + ) { - using (TarWriter writer = new TarWriter(stream, new TarWriterOptions(CompressionType.None, finalizeArchive))) + using ( + TarWriter writer = new TarWriter( + stream, + new TarWriterOptions(CompressionType.None, finalizeArchive) + ) + ) { writer.Write("doesn't matter", content, null); } var paddedContentWithHeader = content.Length / 512 * 512 + 512 + 512; - var expectedStreamLength = finalizeArchive ? paddedContentWithHeader + 512 * 2 : paddedContentWithHeader; + var expectedStreamLength = finalizeArchive + ? paddedContentWithHeader + 512 * 2 + : paddedContentWithHeader; Assert.Equal(expectedStreamLength, stream.Length); } } diff --git a/tests/SharpCompress.Test/TestBase.cs b/tests/SharpCompress.Test/TestBase.cs index 1ec9a376..455d4845 100644 --- a/tests/SharpCompress.Test/TestBase.cs +++ b/tests/SharpCompress.Test/TestBase.cs @@ -20,7 +20,10 @@ namespace SharpCompress.Test public TestBase() { - var index = AppDomain.CurrentDomain.BaseDirectory.IndexOf("SharpCompress.Test", StringComparison.OrdinalIgnoreCase); + var index = AppDomain.CurrentDomain.BaseDirectory.IndexOf( + "SharpCompress.Test", + StringComparison.OrdinalIgnoreCase + ); var path = AppDomain.CurrentDomain.BaseDirectory.Substring(0, index); SOLUTION_BASE_PATH = Path.GetDirectoryName(path) ?? throw new ArgumentNullException(); @@ -28,7 +31,11 @@ namespace SharpCompress.Test ORIGINAL_FILES_PATH = Path.Combine(SOLUTION_BASE_PATH, "TestArchives", "Original"); MISC_TEST_FILES_PATH = Path.Combine(SOLUTION_BASE_PATH, "TestArchives", "MiscTest"); - SCRATCH_BASE_PATH = Path.Combine(SOLUTION_BASE_PATH, "TestArchives", Guid.NewGuid().ToString()); + SCRATCH_BASE_PATH = Path.Combine( + SOLUTION_BASE_PATH, + "TestArchives", + Guid.NewGuid().ToString() + ); SCRATCH_FILES_PATH = Path.Combine(SCRATCH_BASE_PATH, "Scratch"); SCRATCH2_FILES_PATH = Path.Combine(SCRATCH_BASE_PATH, "Scratch2"); @@ -70,11 +77,11 @@ namespace SharpCompress.Test protected void VerifyFilesByName() { - var extracted = - Directory.EnumerateFiles(SCRATCH_FILES_PATH, "*.*", SearchOption.AllDirectories) + var extracted = Directory + .EnumerateFiles(SCRATCH_FILES_PATH, "*.*", SearchOption.AllDirectories) .ToLookup(path => path.Substring(SCRATCH_FILES_PATH.Length)); - var original = - Directory.EnumerateFiles(ORIGINAL_FILES_PATH, "*.*", SearchOption.AllDirectories) + var original = Directory + .EnumerateFiles(ORIGINAL_FILES_PATH, "*.*", SearchOption.AllDirectories) .ToLookup(path => path.Substring(ORIGINAL_FILES_PATH.Length)); Assert.Equal(extracted.Count, original.Count); @@ -92,11 +99,11 @@ namespace SharpCompress.Test /// protected void VerifyFilesByNameEx() { - var extracted = - Directory.EnumerateFiles(SCRATCH_FILES_PATH, "*.*", SearchOption.AllDirectories) + var extracted = Directory + .EnumerateFiles(SCRATCH_FILES_PATH, "*.*", SearchOption.AllDirectories) .ToLookup(path => path.Substring(SCRATCH_FILES_PATH.Length)); - var original = - Directory.EnumerateFiles(ORIGINAL_FILES_PATH, "*.*", SearchOption.AllDirectories) + var original = Directory + .EnumerateFiles(ORIGINAL_FILES_PATH, "*.*", SearchOption.AllDirectories) .ToLookup(path => path.Substring(ORIGINAL_FILES_PATH.Length)); Assert.Equal(extracted.Count, original.Count); @@ -115,11 +122,11 @@ namespace SharpCompress.Test /// protected void VerifyFilesByExtensionEx() { - var extracted = - Directory.EnumerateFiles(SCRATCH_FILES_PATH, "*.*", SearchOption.AllDirectories) + var extracted = Directory + .EnumerateFiles(SCRATCH_FILES_PATH, "*.*", SearchOption.AllDirectories) .ToLookup(path => Path.GetExtension(path)); - var original = - Directory.EnumerateFiles(ORIGINAL_FILES_PATH, "*.*", SearchOption.AllDirectories) + var original = Directory + .EnumerateFiles(ORIGINAL_FILES_PATH, "*.*", SearchOption.AllDirectories) .ToLookup(path => Path.GetExtension(path)); Assert.Equal(extracted.Count, original.Count); @@ -137,11 +144,11 @@ namespace SharpCompress.Test protected void VerifyFilesByExtension() { - var extracted = - Directory.EnumerateFiles(SCRATCH_FILES_PATH, "*.*", SearchOption.AllDirectories) + var extracted = Directory + .EnumerateFiles(SCRATCH_FILES_PATH, "*.*", SearchOption.AllDirectories) .ToLookup(path => Path.GetExtension(path)); - var original = - Directory.EnumerateFiles(ORIGINAL_FILES_PATH, "*.*", SearchOption.AllDirectories) + var original = Directory + .EnumerateFiles(ORIGINAL_FILES_PATH, "*.*", SearchOption.AllDirectories) .ToLookup(path => Path.GetExtension(path)); Assert.Equal(extracted.Count, original.Count); @@ -215,6 +222,5 @@ namespace SharpCompress.Test Assert.Equal(archive1Entries[i], archive2Entries[i]); } } - } } diff --git a/tests/SharpCompress.Test/WriterTests.cs b/tests/SharpCompress.Test/WriterTests.cs index c38fed29..ad322949 100644 --- a/tests/SharpCompress.Test/WriterTests.cs +++ b/tests/SharpCompress.Test/WriterTests.cs @@ -16,7 +16,12 @@ namespace SharpCompress.Test this.type = type; } - protected void Write(CompressionType compressionType, string archive, string archiveToVerifyAgainst, Encoding? encoding = null) + protected void Write( + CompressionType compressionType, + string archive, + string archiveToVerifyAgainst, + Encoding? encoding = null + ) { using (Stream stream = File.OpenWrite(Path.Combine(SCRATCH2_FILES_PATH, archive))) { @@ -32,8 +37,10 @@ namespace SharpCompress.Test writer.WriteAll(ORIGINAL_FILES_PATH, "*", SearchOption.AllDirectories); } } - CompareArchivesByPath(Path.Combine(SCRATCH2_FILES_PATH, archive), - Path.Combine(TEST_ARCHIVES_PATH, archiveToVerifyAgainst)); + CompareArchivesByPath( + Path.Combine(SCRATCH2_FILES_PATH, archive), + Path.Combine(TEST_ARCHIVES_PATH, archiveToVerifyAgainst) + ); using (Stream stream = File.OpenRead(Path.Combine(SCRATCH2_FILES_PATH, archive))) { @@ -41,12 +48,17 @@ namespace SharpCompress.Test readerOptions.ArchiveEncoding.Default = encoding ?? Encoding.Default; - using (var reader = ReaderFactory.Open(NonDisposingStream.Create(stream), readerOptions)) + using ( + var reader = ReaderFactory.Open( + NonDisposingStream.Create(stream), + readerOptions + ) + ) { - reader.WriteAllToDirectory(SCRATCH_FILES_PATH, new ExtractionOptions() - { - ExtractFullPath = true - }); + reader.WriteAllToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() { ExtractFullPath = true } + ); } } VerifyFiles(); diff --git a/tests/SharpCompress.Test/Xz/Crc32Tests.cs b/tests/SharpCompress.Test/Xz/Crc32Tests.cs index 95082872..7afa27a1 100644 --- a/tests/SharpCompress.Test/Xz/Crc32Tests.cs +++ b/tests/SharpCompress.Test/Xz/Crc32Tests.cs @@ -9,7 +9,8 @@ namespace SharpCompress.Test.Xz { private const string SimpleString = @"The quick brown fox jumps over the lazy dog."; private readonly byte[] SimpleBytes = Encoding.ASCII.GetBytes(SimpleString); - private const string SimpleString2 = @"Life moves pretty fast. If you don't stop and look around once in a while, you could miss it."; + private const string SimpleString2 = + @"Life moves pretty fast. If you don't stop and look around once in a while, you could miss it."; private readonly byte[] SimpleBytes2 = Encoding.ASCII.GetBytes(SimpleString2); [Fact] @@ -27,6 +28,5 @@ namespace SharpCompress.Test.Xz Assert.Equal((UInt32)0x6ee3ad88, actual); } - } } diff --git a/tests/SharpCompress.Test/Xz/Crc64Tests.cs b/tests/SharpCompress.Test/Xz/Crc64Tests.cs index 3095dba4..f4ef9493 100644 --- a/tests/SharpCompress.Test/Xz/Crc64Tests.cs +++ b/tests/SharpCompress.Test/Xz/Crc64Tests.cs @@ -9,7 +9,8 @@ namespace SharpCompress.Test.Xz { private const string SimpleString = @"The quick brown fox jumps over the lazy dog."; private readonly byte[] SimpleBytes = Encoding.ASCII.GetBytes(SimpleString); - private const string SimpleString2 = @"Life moves pretty fast. If you don't stop and look around once in a while, you could miss it."; + private const string SimpleString2 = + @"Life moves pretty fast. If you don't stop and look around once in a while, you could miss it."; private readonly byte[] SimpleBytes2 = Encoding.ASCII.GetBytes(SimpleString2); [Fact] @@ -27,6 +28,5 @@ namespace SharpCompress.Test.Xz Assert.Equal((UInt64)0x416B4150508661EE, actual); } - } } diff --git a/tests/SharpCompress.Test/Xz/Filters/BCJTests.cs b/tests/SharpCompress.Test/Xz/Filters/BCJTests.cs index c562a43b..a18005dd 100644 --- a/tests/SharpCompress.Test/Xz/Filters/BCJTests.cs +++ b/tests/SharpCompress.Test/Xz/Filters/BCJTests.cs @@ -17,6 +17,7 @@ namespace SharpCompress.Test.Xz.Filters private readonly PowerPCFilter ppcFilter; private readonly SparcFilter sparcFilter; private readonly X86Filter x86Filter; + public BCJTests() { armFilter = new ArmFilter(); diff --git a/tests/SharpCompress.Test/Xz/XZBlockTests.cs b/tests/SharpCompress.Test/Xz/XZBlockTests.cs index 97e2f704..0e070c67 100644 --- a/tests/SharpCompress.Test/Xz/XZBlockTests.cs +++ b/tests/SharpCompress.Test/Xz/XZBlockTests.cs @@ -36,7 +36,10 @@ namespace SharpCompress.Test.Xz using (Stream indexBlockStream = new MemoryStream(bytes)) { var XZBlock = new XZBlock(indexBlockStream, CheckType.CRC64, 8); - Assert.Throws(() => { ReadBytes(XZBlock, 1); }); + Assert.Throws(() => + { + ReadBytes(XZBlock, 1); + }); } } @@ -49,7 +52,10 @@ namespace SharpCompress.Test.Xz { Rewind(badCrcStream); var XZBlock = new XZBlock(badCrcStream, CheckType.CRC64, 8); - var ex = Assert.Throws(() => { ReadBytes(XZBlock, 1); }); + var ex = Assert.Throws(() => + { + ReadBytes(XZBlock, 1); + }); Assert.Equal("Block header corrupt", ex.Message); } } diff --git a/tests/SharpCompress.Test/Xz/XZHeaderTests.cs b/tests/SharpCompress.Test/Xz/XZHeaderTests.cs index 026c0c17..30893fbc 100644 --- a/tests/SharpCompress.Test/Xz/XZHeaderTests.cs +++ b/tests/SharpCompress.Test/Xz/XZHeaderTests.cs @@ -15,7 +15,10 @@ namespace SharpCompress.Test.Xz { BinaryReader br = new BinaryReader(badMagicNumberStream); var header = new XZHeader(br); - var ex = Assert.Throws(() => { header.Process(); }); + var ex = Assert.Throws(() => + { + header.Process(); + }); Assert.Equal("Invalid XZ Stream", ex.Message); } } @@ -29,7 +32,10 @@ namespace SharpCompress.Test.Xz { BinaryReader br = new BinaryReader(badCrcStream); var header = new XZHeader(br); - var ex = Assert.Throws(() => { header.Process(); }); + var ex = Assert.Throws(() => + { + header.Process(); + }); Assert.Equal("Stream header corrupt", ex.Message); } } @@ -46,7 +52,10 @@ namespace SharpCompress.Test.Xz { BinaryReader br = new BinaryReader(badFlagStream); var header = new XZHeader(br); - var ex = Assert.Throws(() => { header.Process(); }); + var ex = Assert.Throws(() => + { + header.Process(); + }); Assert.Equal("Unknown XZ Stream Version", ex.Message); } } diff --git a/tests/SharpCompress.Test/Xz/XZIndexTests.cs b/tests/SharpCompress.Test/Xz/XZIndexTests.cs index 543f984e..898d71f4 100644 --- a/tests/SharpCompress.Test/Xz/XZIndexTests.cs +++ b/tests/SharpCompress.Test/Xz/XZIndexTests.cs @@ -83,7 +83,26 @@ namespace SharpCompress.Test.Xz public void SkipsPadding() { // Index with 3-byte padding. - using (Stream badStream = new MemoryStream(new byte[] { 0x00, 0x01, 0x10, 0x80, 0x01, 0x00, 0x00, 0x00, 0xB1, 0x01, 0xD9, 0xC9, 0xFF })) + using ( + Stream badStream = new MemoryStream( + new byte[] + { + 0x00, + 0x01, + 0x10, + 0x80, + 0x01, + 0x00, + 0x00, + 0x00, + 0xB1, + 0x01, + 0xD9, + 0xC9, + 0xFF + } + ) + ) { BinaryReader br = new BinaryReader(badStream); var index = new XZIndex(br, false); diff --git a/tests/SharpCompress.Test/Xz/XZTestsBase.cs b/tests/SharpCompress.Test/Xz/XZTestsBase.cs index a0e3032e..e5a3b53c 100644 --- a/tests/SharpCompress.Test/Xz/XZTestsBase.cs +++ b/tests/SharpCompress.Test/Xz/XZTestsBase.cs @@ -37,10 +37,42 @@ namespace SharpCompress.Test.Xz protected Stream CompressedEmptyStream { get; } = new MemoryStream(CompressedEmpty); - protected static byte[] CompressedEmpty { get; } = new byte[] { - 0xfd, 0x37, 0x7a, 0x58, 0x5a, 0x00, 0x00, 0x01, 0x69, 0x22, 0xde, 0x36, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xdf, 0x44, 0x21, 0x90, 0x42, 0x99, 0x0d, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x59, 0x5a - }; + protected static byte[] CompressedEmpty { get; } = + new byte[] + { + 0xfd, + 0x37, + 0x7a, + 0x58, + 0x5a, + 0x00, + 0x00, + 0x01, + 0x69, + 0x22, + 0xde, + 0x36, + 0x00, + 0x00, + 0x00, + 0x00, + 0x1c, + 0xdf, + 0x44, + 0x21, + 0x90, + 0x42, + 0x99, + 0x0d, + 0x01, + 0x00, + 0x00, + 0x00, + 0x00, + 0x01, + 0x59, + 0x5a + }; protected static byte[] OriginalEmptyBytes => Encoding.ASCII.GetBytes(OriginalEmpty); @@ -48,102 +80,1071 @@ namespace SharpCompress.Test.Xz protected Stream CompressedStream { get; } = new MemoryStream(Compressed); - protected static byte[] Compressed { get; } = new byte[] { - 0xfd, 0x37, 0x7a, 0x58, 0x5a, 0x00, 0x00, 0x04, 0xe6, 0xd6, 0xb4, 0x46, 0x02, 0x00, 0x21, 0x01, - 0x16, 0x00, 0x00, 0x00, 0x74, 0x2f, 0xe5, 0xa3, 0xe0, 0x01, 0xe4, 0x01, 0x3c, 0x5d, 0x00, 0x26, - 0x98, 0x4a, 0x47, 0xc6, 0x6a, 0x27, 0xd7, 0x36, 0x7a, 0x05, 0xb9, 0x4f, 0xd7, 0xde, 0x52, 0x4c, - 0xca, 0x26, 0x4f, 0x23, 0x60, 0x4d, 0xf3, 0x1f, 0xa3, 0x67, 0x49, 0x53, 0xd0, 0xf5, 0xc7, 0xa9, - 0x3e, 0xd6, 0xb5, 0x3d, 0x2b, 0x02, 0xbe, 0x83, 0x27, 0xe2, 0xa6, 0xc3, 0x13, 0x4a, 0x31, 0x14, - 0x33, 0xed, 0x9a, 0x85, 0x1d, 0x05, 0x6e, 0x7e, 0xa4, 0x91, 0xbf, 0x46, 0x71, 0x7d, 0xa7, 0xfb, - 0x12, 0x10, 0xdf, 0x21, 0x73, 0x75, 0xd8, 0xd9, 0xab, 0x8f, 0x1f, 0x8b, 0xb0, 0xb9, 0x3f, 0x9a, - 0xa5, 0x1e, 0xd4, 0x2f, 0xdf, 0x09, 0xb3, 0xfe, 0x45, 0xef, 0x16, 0xec, 0x95, 0x68, 0x64, 0xbb, - 0x42, 0x0c, 0x8b, 0x96, 0x27, 0x30, 0x62, 0x42, 0x91, 0x7c, 0xf3, 0x6e, 0x4d, 0x03, 0xc5, 0x00, - 0x04, 0x73, 0xdd, 0xee, 0xb0, 0xaa, 0xd6, 0x0b, 0x11, 0x90, 0x81, 0xd4, 0xaa, 0x69, 0x63, 0xfa, - 0x2f, 0xb4, 0x25, 0x0a, 0x7f, 0xf9, 0x47, 0x77, 0xb1, 0x1f, 0xc3, 0xb4, 0x4d, 0x51, 0xf8, 0x23, - 0x3a, 0x7c, 0x44, 0xc8, 0xcc, 0xca, 0x72, 0x09, 0xae, 0xc9, 0x7b, 0x7e, 0x91, 0x5d, 0xff, 0xc4, - 0xeb, 0xfd, 0xa1, 0x9b, 0xd4, 0x8d, 0xd7, 0xd3, 0x57, 0xac, 0x7e, 0x3b, 0x97, 0x2e, 0xe4, 0xc2, - 0x2e, 0x93, 0x3d, 0xb0, 0x16, 0x64, 0x78, 0x45, 0xb1, 0xc9, 0x40, 0x96, 0xcf, 0x5b, 0xc2, 0x2f, - 0xaa, 0xba, 0xcf, 0x98, 0x38, 0x21, 0x3d, 0x1a, 0x13, 0xe8, 0xa6, 0xa6, 0xdf, 0xf4, 0x3d, 0x01, - 0xa1, 0x9d, 0xc1, 0x3e, 0x37, 0xac, 0x20, 0xc4, 0xef, 0x18, 0xb1, 0xeb, 0x35, 0xf4, 0x66, 0x9a, - 0x47, 0x3c, 0xce, 0x7c, 0xad, 0xdb, 0x2e, 0x39, 0xf5, 0x8d, 0x4a, 0x1d, 0x65, 0xc2, 0x0f, 0xa4, - 0x40, 0x7e, 0xe6, 0xa7, 0x17, 0xce, 0x75, 0x7f, 0xd9, 0xa3, 0xf9, 0x27, 0x42, 0xd7, 0x98, 0x54, - 0x17, 0xa7, 0x7a, 0x7c, 0x82, 0xdf, 0xeb, 0x08, 0x28, 0x86, 0xdd, 0x57, 0x77, 0x92, 0x80, 0x5f, - 0x7b, 0x3b, 0xce, 0x77, 0x72, 0xff, 0xa3, 0x85, 0xd8, 0x5c, 0x8a, 0xb7, 0x83, 0x58, 0xfa, 0xbd, - 0x72, 0xe3, 0x66, 0x9d, 0x3b, 0xff, 0x13, 0x5b, 0x0b, 0xf1, 0x6c, 0xa6, 0xb1, 0x3b, 0x85, 0x3b, - 0x47, 0x91, 0xc8, 0x7c, 0x38, 0xe2, 0xe5, 0x54, 0xf8, 0x27, 0xee, 0x00, 0xff, 0xd3, 0x68, 0xf1, - 0xc6, 0xc7, 0xd7, 0x24, 0x00, 0x01, 0xd8, 0x02, 0xe5, 0x03, 0x00, 0x00, 0xac, 0x16, 0x1f, 0xa4, - 0xb1, 0xc4, 0x67, 0xfb, 0x02, 0x00, 0x00, 0x00, 0x00, 0x04, 0x59, 0x5a - }; + protected static byte[] Compressed { get; } = + new byte[] + { + 0xfd, + 0x37, + 0x7a, + 0x58, + 0x5a, + 0x00, + 0x00, + 0x04, + 0xe6, + 0xd6, + 0xb4, + 0x46, + 0x02, + 0x00, + 0x21, + 0x01, + 0x16, + 0x00, + 0x00, + 0x00, + 0x74, + 0x2f, + 0xe5, + 0xa3, + 0xe0, + 0x01, + 0xe4, + 0x01, + 0x3c, + 0x5d, + 0x00, + 0x26, + 0x98, + 0x4a, + 0x47, + 0xc6, + 0x6a, + 0x27, + 0xd7, + 0x36, + 0x7a, + 0x05, + 0xb9, + 0x4f, + 0xd7, + 0xde, + 0x52, + 0x4c, + 0xca, + 0x26, + 0x4f, + 0x23, + 0x60, + 0x4d, + 0xf3, + 0x1f, + 0xa3, + 0x67, + 0x49, + 0x53, + 0xd0, + 0xf5, + 0xc7, + 0xa9, + 0x3e, + 0xd6, + 0xb5, + 0x3d, + 0x2b, + 0x02, + 0xbe, + 0x83, + 0x27, + 0xe2, + 0xa6, + 0xc3, + 0x13, + 0x4a, + 0x31, + 0x14, + 0x33, + 0xed, + 0x9a, + 0x85, + 0x1d, + 0x05, + 0x6e, + 0x7e, + 0xa4, + 0x91, + 0xbf, + 0x46, + 0x71, + 0x7d, + 0xa7, + 0xfb, + 0x12, + 0x10, + 0xdf, + 0x21, + 0x73, + 0x75, + 0xd8, + 0xd9, + 0xab, + 0x8f, + 0x1f, + 0x8b, + 0xb0, + 0xb9, + 0x3f, + 0x9a, + 0xa5, + 0x1e, + 0xd4, + 0x2f, + 0xdf, + 0x09, + 0xb3, + 0xfe, + 0x45, + 0xef, + 0x16, + 0xec, + 0x95, + 0x68, + 0x64, + 0xbb, + 0x42, + 0x0c, + 0x8b, + 0x96, + 0x27, + 0x30, + 0x62, + 0x42, + 0x91, + 0x7c, + 0xf3, + 0x6e, + 0x4d, + 0x03, + 0xc5, + 0x00, + 0x04, + 0x73, + 0xdd, + 0xee, + 0xb0, + 0xaa, + 0xd6, + 0x0b, + 0x11, + 0x90, + 0x81, + 0xd4, + 0xaa, + 0x69, + 0x63, + 0xfa, + 0x2f, + 0xb4, + 0x25, + 0x0a, + 0x7f, + 0xf9, + 0x47, + 0x77, + 0xb1, + 0x1f, + 0xc3, + 0xb4, + 0x4d, + 0x51, + 0xf8, + 0x23, + 0x3a, + 0x7c, + 0x44, + 0xc8, + 0xcc, + 0xca, + 0x72, + 0x09, + 0xae, + 0xc9, + 0x7b, + 0x7e, + 0x91, + 0x5d, + 0xff, + 0xc4, + 0xeb, + 0xfd, + 0xa1, + 0x9b, + 0xd4, + 0x8d, + 0xd7, + 0xd3, + 0x57, + 0xac, + 0x7e, + 0x3b, + 0x97, + 0x2e, + 0xe4, + 0xc2, + 0x2e, + 0x93, + 0x3d, + 0xb0, + 0x16, + 0x64, + 0x78, + 0x45, + 0xb1, + 0xc9, + 0x40, + 0x96, + 0xcf, + 0x5b, + 0xc2, + 0x2f, + 0xaa, + 0xba, + 0xcf, + 0x98, + 0x38, + 0x21, + 0x3d, + 0x1a, + 0x13, + 0xe8, + 0xa6, + 0xa6, + 0xdf, + 0xf4, + 0x3d, + 0x01, + 0xa1, + 0x9d, + 0xc1, + 0x3e, + 0x37, + 0xac, + 0x20, + 0xc4, + 0xef, + 0x18, + 0xb1, + 0xeb, + 0x35, + 0xf4, + 0x66, + 0x9a, + 0x47, + 0x3c, + 0xce, + 0x7c, + 0xad, + 0xdb, + 0x2e, + 0x39, + 0xf5, + 0x8d, + 0x4a, + 0x1d, + 0x65, + 0xc2, + 0x0f, + 0xa4, + 0x40, + 0x7e, + 0xe6, + 0xa7, + 0x17, + 0xce, + 0x75, + 0x7f, + 0xd9, + 0xa3, + 0xf9, + 0x27, + 0x42, + 0xd7, + 0x98, + 0x54, + 0x17, + 0xa7, + 0x7a, + 0x7c, + 0x82, + 0xdf, + 0xeb, + 0x08, + 0x28, + 0x86, + 0xdd, + 0x57, + 0x77, + 0x92, + 0x80, + 0x5f, + 0x7b, + 0x3b, + 0xce, + 0x77, + 0x72, + 0xff, + 0xa3, + 0x85, + 0xd8, + 0x5c, + 0x8a, + 0xb7, + 0x83, + 0x58, + 0xfa, + 0xbd, + 0x72, + 0xe3, + 0x66, + 0x9d, + 0x3b, + 0xff, + 0x13, + 0x5b, + 0x0b, + 0xf1, + 0x6c, + 0xa6, + 0xb1, + 0x3b, + 0x85, + 0x3b, + 0x47, + 0x91, + 0xc8, + 0x7c, + 0x38, + 0xe2, + 0xe5, + 0x54, + 0xf8, + 0x27, + 0xee, + 0x00, + 0xff, + 0xd3, + 0x68, + 0xf1, + 0xc6, + 0xc7, + 0xd7, + 0x24, + 0x00, + 0x01, + 0xd8, + 0x02, + 0xe5, + 0x03, + 0x00, + 0x00, + 0xac, + 0x16, + 0x1f, + 0xa4, + 0xb1, + 0xc4, + 0x67, + 0xfb, + 0x02, + 0x00, + 0x00, + 0x00, + 0x00, + 0x04, + 0x59, + 0x5a + }; protected static byte[] OriginalBytes => Encoding.ASCII.GetBytes(Original); protected static string Original { get; } = - "Mary had a little lamb,\r\n" + - "His fleece was white as snow,\r\n" + - "And everywhere that Mary went,\r\n" + - "The lamb was sure to go.\r\n" + - "\r\n" + - "He followed her to school one day,\r\n" + - "Which was against the rule,\r\n" + - "It made the children laugh and play\r\n" + - "To see a lamb at school.\r\n" + - "\r\n" + - "And so the teacher turned it out,\r\n" + - "But still it lingered near,\r\n" + - "And waited patiently about,\r\n" + - "Till Mary did appear.\r\n" + - "\r\n" + - "\"Why does the lamb love Mary so?\"\r\n" + - "The eager children cry.\r\n" + - "\"Why, Mary loves the lamb, you know.\"\r\n" + - "The teacher did reply."; + "Mary had a little lamb,\r\n" + + "His fleece was white as snow,\r\n" + + "And everywhere that Mary went,\r\n" + + "The lamb was sure to go.\r\n" + + "\r\n" + + "He followed her to school one day,\r\n" + + "Which was against the rule,\r\n" + + "It made the children laugh and play\r\n" + + "To see a lamb at school.\r\n" + + "\r\n" + + "And so the teacher turned it out,\r\n" + + "But still it lingered near,\r\n" + + "And waited patiently about,\r\n" + + "Till Mary did appear.\r\n" + + "\r\n" + + "\"Why does the lamb love Mary so?\"\r\n" + + "The eager children cry.\r\n" + + "\"Why, Mary loves the lamb, you know.\"\r\n" + + "The teacher did reply."; protected Stream CompressedIndexedStream { get; } = new MemoryStream(CompressedIndexed); - protected static byte[] CompressedIndexed { get; } = new byte[] { - 0xfd, 0x37, 0x7a, 0x58, 0x5a, 0x00, 0x00, 0x01, 0x69, 0x22, 0xde, 0x36, 0x03, 0xc0, 0xe3, 0x02, - 0x80, 0x20, 0x21, 0x01, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xe5, 0xd7, 0x32, 0xe0, 0x0f, 0xff, 0x01, - 0x5b, 0x5d, 0x00, 0x26, 0x98, 0x4a, 0x47, 0xc6, 0x6a, 0x27, 0xd7, 0x36, 0x7a, 0x05, 0xb9, 0x4f, - 0xd7, 0xde, 0x3a, 0x0e, 0xee, 0x1b, 0xd7, 0x81, 0xe9, 0xf5, 0x90, 0x1e, 0xd5, 0x9e, 0x88, 0x32, - 0x1c, 0x7b, 0x43, 0x84, 0x02, 0x58, 0x92, 0xcf, 0x97, 0xfc, 0xae, 0x01, 0x83, 0x23, 0x48, 0x93, - 0xc6, 0x56, 0xcc, 0x6d, 0xb1, 0x23, 0x10, 0x24, 0x3b, 0x9e, 0x06, 0xaa, 0xc0, 0xce, 0x86, 0x0a, - 0xb7, 0x9f, 0x99, 0x61, 0xbe, 0x3b, 0x6d, 0xfe, 0x60, 0xef, 0x14, 0x35, 0x7f, 0x21, 0xe8, 0x96, - 0x0e, 0xbd, 0x41, 0x7c, 0x65, 0x89, 0x96, 0x28, 0x5e, 0x85, 0xa6, 0x4b, 0xf3, 0xf9, 0xf8, 0x25, - 0x31, 0x4a, 0xbb, 0x72, 0xce, 0xcf, 0x53, 0xdf, 0x13, 0x42, 0x2d, 0xbc, 0x95, 0xa5, 0x6d, 0xc4, - 0x8c, 0x72, 0x99, 0xe8, 0x9a, 0xcf, 0x80, 0xd4, 0xc4, 0x3f, 0x55, 0xc3, 0x9b, 0x00, 0xce, 0x65, - 0x27, 0x6e, 0xbf, 0xb2, 0x88, 0xab, 0xc0, 0x5f, 0xf9, 0xd0, 0xc8, 0xbb, 0xd7, 0x48, 0xd7, 0x2e, - 0x5e, 0xbb, 0x23, 0x35, 0x6e, 0x62, 0xb6, 0x13, 0xd4, 0x06, 0xd1, 0x5b, 0x97, 0xee, 0x5b, 0x89, - 0x78, 0x07, 0x24, 0x74, 0x59, 0x06, 0x1e, 0x7f, 0x8c, 0xb0, 0x48, 0xff, 0x0a, 0x76, 0xb2, 0x07, - 0xa0, 0x99, 0xf5, 0x4b, 0x68, 0xd4, 0x55, 0x32, 0xb3, 0x17, 0x7b, 0xb6, 0x26, 0xdb, 0x1c, 0xc3, - 0x0b, 0xda, 0x3e, 0x46, 0xba, 0x1a, 0x67, 0x23, 0xb7, 0x2a, 0x40, 0xdc, 0xc9, 0xa2, 0xe4, 0xb5, - 0x68, 0x5c, 0x81, 0x60, 0xa7, 0xad, 0xe6, 0xba, 0xbb, 0x0d, 0x82, 0x8a, 0xe2, 0x03, 0xa9, 0x22, - 0x09, 0x5e, 0xd8, 0x69, 0xfa, 0x29, 0xd1, 0x32, 0xa1, 0xf0, 0x9b, 0x3c, 0xc3, 0x0b, 0x9a, 0x53, - 0xf0, 0x3e, 0xf3, 0x1b, 0x77, 0xee, 0x8f, 0xa6, 0x15, 0x02, 0x77, 0x14, 0x54, 0x60, 0xae, 0xbe, - 0x91, 0x9e, 0xe6, 0x8b, 0x87, 0x6e, 0x46, 0x44, 0x64, 0xc7, 0x58, 0x90, 0x62, 0x25, 0x32, 0xf9, - 0xcd, 0xd2, 0x73, 0x2e, 0x3f, 0xd7, 0x5d, 0x3c, 0x86, 0x1c, 0xa8, 0x35, 0xa9, 0xc2, 0xcb, 0x59, - 0xcb, 0xac, 0xb3, 0x03, 0x12, 0xd4, 0x8a, 0xde, 0xd5, 0xc1, 0xd8, 0x0c, 0x32, 0x49, 0x87, 0x97, - 0x62, 0x4f, 0x32, 0x39, 0x63, 0x5b, 0x8b, 0xd1, 0x6c, 0x5c, 0x90, 0xd9, 0x93, 0x13, 0xae, 0x70, - 0xf5, 0x2f, 0x40, 0xaf, 0x01, 0x95, 0x01, 0x0c, 0xc5, 0xfa, 0x82, 0xf8, 0x71, 0x9d, 0x53, 0xe6, - 0x47, 0x6e, 0x99, 0x54, 0x57, 0x41, 0x72, 0xea, 0xf5, 0x78, 0xdd, 0x86, 0xbd, 0x00, 0x00, 0x00, - 0x72, 0x6a, 0xf2, 0x47, 0x03, 0xc0, 0xcb, 0x01, 0x8d, 0x02, 0x21, 0x01, 0x00, 0x00, 0x00, 0x00, - 0xfb, 0xa7, 0xf7, 0x94, 0xe0, 0x01, 0x0c, 0x00, 0xc3, 0x5d, 0x00, 0x06, 0x82, 0xca, 0x9b, 0x77, - 0x93, 0x57, 0xb3, 0x76, 0xbd, 0x8b, 0xcb, 0xee, 0xf4, 0x2c, 0xff, 0x7f, 0x95, 0x33, 0x15, 0x10, - 0xa5, 0xf9, 0xfd, 0xa6, 0xbb, 0x9e, 0xf9, 0x75, 0x67, 0xee, 0xec, 0x8b, 0x40, 0xea, 0x32, 0x47, - 0x3d, 0x26, 0xbe, 0x11, 0x9c, 0xa6, 0x40, 0xbe, 0x84, 0x1f, 0x1b, 0x35, 0x1a, 0x66, 0x10, 0x9c, - 0xf4, 0x12, 0x1a, 0x95, 0x81, 0xb5, 0x55, 0x6b, 0xc5, 0x42, 0xfd, 0x37, 0x70, 0xc5, 0x08, 0xa4, - 0x27, 0x67, 0x11, 0x0b, 0x1f, 0xcc, 0xdb, 0x54, 0x9b, 0x5a, 0x5f, 0xee, 0x21, 0x63, 0xdd, 0x4b, - 0xbc, 0x49, 0x95, 0x6d, 0xf4, 0xcb, 0x9a, 0x9a, 0x5e, 0xe4, 0x7d, 0x0f, 0x02, 0x22, 0xa9, 0x42, - 0x46, 0x1a, 0x04, 0x87, 0x43, 0x72, 0x59, 0xa4, 0xd6, 0xeb, 0x69, 0x36, 0xde, 0xea, 0x53, 0x8c, - 0x89, 0xd7, 0x22, 0xa6, 0xf7, 0xa8, 0x4c, 0x72, 0x6c, 0x80, 0x69, 0x01, 0xb2, 0xa7, 0xe8, 0x8b, - 0x94, 0xaf, 0x0e, 0x47, 0x58, 0x1d, 0x0e, 0x5c, 0x7c, 0x33, 0x9f, 0x21, 0x17, 0x2c, 0x4f, 0x3d, - 0x72, 0xff, 0xcf, 0x7a, 0x4f, 0x82, 0x5b, 0x85, 0x28, 0x70, 0xf4, 0x8c, 0x81, 0x41, 0xb8, 0x20, - 0x5c, 0x3e, 0x02, 0x5e, 0x5a, 0x61, 0xbb, 0x2f, 0x64, 0xc5, 0x4e, 0x53, 0xe4, 0xca, 0xe4, 0xd9, - 0x75, 0xaf, 0x15, 0x4d, 0xff, 0x01, 0xec, 0x13, 0x4a, 0x70, 0x00, 0x04, 0xf9, 0xfa, 0x00, 0x00, - 0x99, 0x57, 0xc4, 0x96, 0x00, 0x02, 0xf7, 0x02, 0x80, 0x20, 0xdf, 0x01, 0x8d, 0x02, 0x00, 0x00, - 0x4c, 0x41, 0xe6, 0xa1, 0x9b, 0xe3, 0x51, 0x40, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x59, 0x5a - }; + protected static byte[] CompressedIndexed { get; } = + new byte[] + { + 0xfd, + 0x37, + 0x7a, + 0x58, + 0x5a, + 0x00, + 0x00, + 0x01, + 0x69, + 0x22, + 0xde, + 0x36, + 0x03, + 0xc0, + 0xe3, + 0x02, + 0x80, + 0x20, + 0x21, + 0x01, + 0x00, + 0x00, + 0x00, + 0x00, + 0x7e, + 0xe5, + 0xd7, + 0x32, + 0xe0, + 0x0f, + 0xff, + 0x01, + 0x5b, + 0x5d, + 0x00, + 0x26, + 0x98, + 0x4a, + 0x47, + 0xc6, + 0x6a, + 0x27, + 0xd7, + 0x36, + 0x7a, + 0x05, + 0xb9, + 0x4f, + 0xd7, + 0xde, + 0x3a, + 0x0e, + 0xee, + 0x1b, + 0xd7, + 0x81, + 0xe9, + 0xf5, + 0x90, + 0x1e, + 0xd5, + 0x9e, + 0x88, + 0x32, + 0x1c, + 0x7b, + 0x43, + 0x84, + 0x02, + 0x58, + 0x92, + 0xcf, + 0x97, + 0xfc, + 0xae, + 0x01, + 0x83, + 0x23, + 0x48, + 0x93, + 0xc6, + 0x56, + 0xcc, + 0x6d, + 0xb1, + 0x23, + 0x10, + 0x24, + 0x3b, + 0x9e, + 0x06, + 0xaa, + 0xc0, + 0xce, + 0x86, + 0x0a, + 0xb7, + 0x9f, + 0x99, + 0x61, + 0xbe, + 0x3b, + 0x6d, + 0xfe, + 0x60, + 0xef, + 0x14, + 0x35, + 0x7f, + 0x21, + 0xe8, + 0x96, + 0x0e, + 0xbd, + 0x41, + 0x7c, + 0x65, + 0x89, + 0x96, + 0x28, + 0x5e, + 0x85, + 0xa6, + 0x4b, + 0xf3, + 0xf9, + 0xf8, + 0x25, + 0x31, + 0x4a, + 0xbb, + 0x72, + 0xce, + 0xcf, + 0x53, + 0xdf, + 0x13, + 0x42, + 0x2d, + 0xbc, + 0x95, + 0xa5, + 0x6d, + 0xc4, + 0x8c, + 0x72, + 0x99, + 0xe8, + 0x9a, + 0xcf, + 0x80, + 0xd4, + 0xc4, + 0x3f, + 0x55, + 0xc3, + 0x9b, + 0x00, + 0xce, + 0x65, + 0x27, + 0x6e, + 0xbf, + 0xb2, + 0x88, + 0xab, + 0xc0, + 0x5f, + 0xf9, + 0xd0, + 0xc8, + 0xbb, + 0xd7, + 0x48, + 0xd7, + 0x2e, + 0x5e, + 0xbb, + 0x23, + 0x35, + 0x6e, + 0x62, + 0xb6, + 0x13, + 0xd4, + 0x06, + 0xd1, + 0x5b, + 0x97, + 0xee, + 0x5b, + 0x89, + 0x78, + 0x07, + 0x24, + 0x74, + 0x59, + 0x06, + 0x1e, + 0x7f, + 0x8c, + 0xb0, + 0x48, + 0xff, + 0x0a, + 0x76, + 0xb2, + 0x07, + 0xa0, + 0x99, + 0xf5, + 0x4b, + 0x68, + 0xd4, + 0x55, + 0x32, + 0xb3, + 0x17, + 0x7b, + 0xb6, + 0x26, + 0xdb, + 0x1c, + 0xc3, + 0x0b, + 0xda, + 0x3e, + 0x46, + 0xba, + 0x1a, + 0x67, + 0x23, + 0xb7, + 0x2a, + 0x40, + 0xdc, + 0xc9, + 0xa2, + 0xe4, + 0xb5, + 0x68, + 0x5c, + 0x81, + 0x60, + 0xa7, + 0xad, + 0xe6, + 0xba, + 0xbb, + 0x0d, + 0x82, + 0x8a, + 0xe2, + 0x03, + 0xa9, + 0x22, + 0x09, + 0x5e, + 0xd8, + 0x69, + 0xfa, + 0x29, + 0xd1, + 0x32, + 0xa1, + 0xf0, + 0x9b, + 0x3c, + 0xc3, + 0x0b, + 0x9a, + 0x53, + 0xf0, + 0x3e, + 0xf3, + 0x1b, + 0x77, + 0xee, + 0x8f, + 0xa6, + 0x15, + 0x02, + 0x77, + 0x14, + 0x54, + 0x60, + 0xae, + 0xbe, + 0x91, + 0x9e, + 0xe6, + 0x8b, + 0x87, + 0x6e, + 0x46, + 0x44, + 0x64, + 0xc7, + 0x58, + 0x90, + 0x62, + 0x25, + 0x32, + 0xf9, + 0xcd, + 0xd2, + 0x73, + 0x2e, + 0x3f, + 0xd7, + 0x5d, + 0x3c, + 0x86, + 0x1c, + 0xa8, + 0x35, + 0xa9, + 0xc2, + 0xcb, + 0x59, + 0xcb, + 0xac, + 0xb3, + 0x03, + 0x12, + 0xd4, + 0x8a, + 0xde, + 0xd5, + 0xc1, + 0xd8, + 0x0c, + 0x32, + 0x49, + 0x87, + 0x97, + 0x62, + 0x4f, + 0x32, + 0x39, + 0x63, + 0x5b, + 0x8b, + 0xd1, + 0x6c, + 0x5c, + 0x90, + 0xd9, + 0x93, + 0x13, + 0xae, + 0x70, + 0xf5, + 0x2f, + 0x40, + 0xaf, + 0x01, + 0x95, + 0x01, + 0x0c, + 0xc5, + 0xfa, + 0x82, + 0xf8, + 0x71, + 0x9d, + 0x53, + 0xe6, + 0x47, + 0x6e, + 0x99, + 0x54, + 0x57, + 0x41, + 0x72, + 0xea, + 0xf5, + 0x78, + 0xdd, + 0x86, + 0xbd, + 0x00, + 0x00, + 0x00, + 0x72, + 0x6a, + 0xf2, + 0x47, + 0x03, + 0xc0, + 0xcb, + 0x01, + 0x8d, + 0x02, + 0x21, + 0x01, + 0x00, + 0x00, + 0x00, + 0x00, + 0xfb, + 0xa7, + 0xf7, + 0x94, + 0xe0, + 0x01, + 0x0c, + 0x00, + 0xc3, + 0x5d, + 0x00, + 0x06, + 0x82, + 0xca, + 0x9b, + 0x77, + 0x93, + 0x57, + 0xb3, + 0x76, + 0xbd, + 0x8b, + 0xcb, + 0xee, + 0xf4, + 0x2c, + 0xff, + 0x7f, + 0x95, + 0x33, + 0x15, + 0x10, + 0xa5, + 0xf9, + 0xfd, + 0xa6, + 0xbb, + 0x9e, + 0xf9, + 0x75, + 0x67, + 0xee, + 0xec, + 0x8b, + 0x40, + 0xea, + 0x32, + 0x47, + 0x3d, + 0x26, + 0xbe, + 0x11, + 0x9c, + 0xa6, + 0x40, + 0xbe, + 0x84, + 0x1f, + 0x1b, + 0x35, + 0x1a, + 0x66, + 0x10, + 0x9c, + 0xf4, + 0x12, + 0x1a, + 0x95, + 0x81, + 0xb5, + 0x55, + 0x6b, + 0xc5, + 0x42, + 0xfd, + 0x37, + 0x70, + 0xc5, + 0x08, + 0xa4, + 0x27, + 0x67, + 0x11, + 0x0b, + 0x1f, + 0xcc, + 0xdb, + 0x54, + 0x9b, + 0x5a, + 0x5f, + 0xee, + 0x21, + 0x63, + 0xdd, + 0x4b, + 0xbc, + 0x49, + 0x95, + 0x6d, + 0xf4, + 0xcb, + 0x9a, + 0x9a, + 0x5e, + 0xe4, + 0x7d, + 0x0f, + 0x02, + 0x22, + 0xa9, + 0x42, + 0x46, + 0x1a, + 0x04, + 0x87, + 0x43, + 0x72, + 0x59, + 0xa4, + 0xd6, + 0xeb, + 0x69, + 0x36, + 0xde, + 0xea, + 0x53, + 0x8c, + 0x89, + 0xd7, + 0x22, + 0xa6, + 0xf7, + 0xa8, + 0x4c, + 0x72, + 0x6c, + 0x80, + 0x69, + 0x01, + 0xb2, + 0xa7, + 0xe8, + 0x8b, + 0x94, + 0xaf, + 0x0e, + 0x47, + 0x58, + 0x1d, + 0x0e, + 0x5c, + 0x7c, + 0x33, + 0x9f, + 0x21, + 0x17, + 0x2c, + 0x4f, + 0x3d, + 0x72, + 0xff, + 0xcf, + 0x7a, + 0x4f, + 0x82, + 0x5b, + 0x85, + 0x28, + 0x70, + 0xf4, + 0x8c, + 0x81, + 0x41, + 0xb8, + 0x20, + 0x5c, + 0x3e, + 0x02, + 0x5e, + 0x5a, + 0x61, + 0xbb, + 0x2f, + 0x64, + 0xc5, + 0x4e, + 0x53, + 0xe4, + 0xca, + 0xe4, + 0xd9, + 0x75, + 0xaf, + 0x15, + 0x4d, + 0xff, + 0x01, + 0xec, + 0x13, + 0x4a, + 0x70, + 0x00, + 0x04, + 0xf9, + 0xfa, + 0x00, + 0x00, + 0x99, + 0x57, + 0xc4, + 0x96, + 0x00, + 0x02, + 0xf7, + 0x02, + 0x80, + 0x20, + 0xdf, + 0x01, + 0x8d, + 0x02, + 0x00, + 0x00, + 0x4c, + 0x41, + 0xe6, + 0xa1, + 0x9b, + 0xe3, + 0x51, + 0x40, + 0x03, + 0x00, + 0x00, + 0x00, + 0x00, + 0x01, + 0x59, + 0x5a + }; protected static byte[] OriginalIndexedBytes => Encoding.ASCII.GetBytes(OriginalIndexed); - protected static string OriginalIndexed { get; } = Original + Original + Original + Original + Original + Original + Original + Original + Original; + protected static string OriginalIndexed { get; } = + Original + + Original + + Original + + Original + + Original + + Original + + Original + + Original + + Original; } } diff --git a/tests/SharpCompress.Test/Zip/Zip64Tests.cs b/tests/SharpCompress.Test/Zip/Zip64Tests.cs index 8e683f9e..c1f4453f 100644 --- a/tests/SharpCompress.Test/Zip/Zip64Tests.cs +++ b/tests/SharpCompress.Test/Zip/Zip64Tests.cs @@ -14,10 +14,7 @@ namespace SharpCompress.Test.Zip { public class Zip64Tests : WriterTests { - public Zip64Tests() - : base(ArchiveType.Zip) - { - } + public Zip64Tests() : base(ArchiveType.Zip) { } // 4GiB + 1 private const long FOUR_GB_LIMIT = ((long)uint.MaxValue) + 1; @@ -66,9 +63,7 @@ namespace SharpCompress.Test.Zip RunSingleTest(1, FOUR_GB_LIMIT, set_zip64: false, forward_only: false); throw new InvalidOperationException("Test did not fail?"); } - catch (NotSupportedException) - { - } + catch (NotSupportedException) { } } [Trait("zip64", "true")] @@ -80,9 +75,7 @@ namespace SharpCompress.Test.Zip RunSingleTest(1, FOUR_GB_LIMIT, set_zip64: true, forward_only: true); throw new InvalidOperationException("Test did not fail?"); } - catch (NotSupportedException) - { - } + catch (NotSupportedException) { } } [Trait("zip64", "true")] @@ -94,12 +87,17 @@ namespace SharpCompress.Test.Zip RunSingleTest(1, FOUR_GB_LIMIT, set_zip64: false, forward_only: true); throw new InvalidOperationException("Test did not fail?"); } - catch (NotSupportedException) - { - } + catch (NotSupportedException) { } } - public void RunSingleTest(long files, long filesize, bool set_zip64, bool forward_only, long write_chunk_size = 1024 * 1024, string filename = "zip64-test.zip") + public void RunSingleTest( + long files, + long filesize, + bool set_zip64, + bool forward_only, + long write_chunk_size = 1024 * 1024, + string filename = "zip64-test.zip" + ) { filename = Path.Combine(SCRATCH2_FILES_PATH, filename); @@ -110,33 +108,55 @@ namespace SharpCompress.Test.Zip if (!File.Exists(filename)) { - CreateZipArchive(filename, files, filesize, write_chunk_size, set_zip64, forward_only); + CreateZipArchive( + filename, + files, + filesize, + write_chunk_size, + set_zip64, + forward_only + ); } var resForward = ReadForwardOnly(filename); if (resForward.Item1 != files) { - throw new InvalidOperationException($"Incorrect number of items reported: {resForward.Item1}, should have been {files}"); + throw new InvalidOperationException( + $"Incorrect number of items reported: {resForward.Item1}, should have been {files}" + ); } if (resForward.Item2 != files * filesize) { - throw new InvalidOperationException($"Incorrect combined size reported: {resForward.Item2}, should have been {files * filesize}"); + throw new InvalidOperationException( + $"Incorrect combined size reported: {resForward.Item2}, should have been {files * filesize}" + ); } var resArchive = ReadArchive(filename); if (resArchive.Item1 != files) { - throw new InvalidOperationException($"Incorrect number of items reported: {resArchive.Item1}, should have been {files}"); + throw new InvalidOperationException( + $"Incorrect number of items reported: {resArchive.Item1}, should have been {files}" + ); } if (resArchive.Item2 != files * filesize) { - throw new InvalidOperationException($"Incorrect number of items reported: {resArchive.Item2}, should have been {files * filesize}"); + throw new InvalidOperationException( + $"Incorrect number of items reported: {resArchive.Item2}, should have been {files * filesize}" + ); } } - public void CreateZipArchive(string filename, long files, long filesize, long chunksize, bool set_zip64, bool forward_only) + public void CreateZipArchive( + string filename, + long files, + long filesize, + long chunksize, + bool set_zip64, + bool forward_only + ) { var data = new byte[chunksize]; @@ -144,13 +164,15 @@ namespace SharpCompress.Test.Zip var opts = new ZipWriterOptions(CompressionType.Deflate) { UseZip64 = set_zip64 }; // Use no compression to ensure we hit the limits (actually inflates a bit, but seems better than using method==Store) - var eo = new ZipWriterEntryOptions() { DeflateCompressionLevel = Compressors.Deflate.CompressionLevel.None }; + var eo = new ZipWriterEntryOptions() + { + DeflateCompressionLevel = Compressors.Deflate.CompressionLevel.None + }; using (var zip = File.OpenWrite(filename)) using (var st = forward_only ? (Stream)new ForwardOnlyStream(zip) : zip) using (var zipWriter = (ZipWriter)WriterFactory.Open(st, ArchiveType.Zip, opts)) { - for (var i = 0; i < files; i++) { using (var str = zipWriter.WriteToStream(i.ToString(), eo)) @@ -177,8 +199,7 @@ namespace SharpCompress.Test.Zip { while (rd.MoveToNextEntry()) { - using (rd.OpenEntryStream()) - { } + using (rd.OpenEntryStream()) { } count++; if (prev != null) diff --git a/tests/SharpCompress.Test/Zip/ZipArchiveTests.cs b/tests/SharpCompress.Test/Zip/ZipArchiveTests.cs index 07f158b1..c1375801 100644 --- a/tests/SharpCompress.Test/Zip/ZipArchiveTests.cs +++ b/tests/SharpCompress.Test/Zip/ZipArchiveTests.cs @@ -30,26 +30,31 @@ namespace SharpCompress.Test.Zip { ArchiveStreamRead("Zip.bzip2.dd.zip"); } + [Fact] public void Zip_BZip2_ArchiveStreamRead() { ArchiveStreamRead("Zip.bzip2.zip"); } + [Fact] public void Zip_Deflate_Streamed2_ArchiveStreamRead() { ArchiveStreamRead("Zip.deflate.dd-.zip"); } + [Fact] public void Zip_Deflate_Streamed_ArchiveStreamRead() { ArchiveStreamRead("Zip.deflate.dd.zip"); } + [Fact] public void Zip_Deflate_ArchiveStreamRead() { ArchiveStreamRead("Zip.deflate.zip"); } + [Fact] public void Zip_Deflate64_ArchiveStreamRead() { @@ -61,21 +66,25 @@ namespace SharpCompress.Test.Zip { ArchiveStreamRead("Zip.lzma.dd.zip"); } + [Fact] public void Zip_LZMA_ArchiveStreamRead() { ArchiveStreamRead("Zip.lzma.zip"); } + [Fact] public void Zip_PPMd_Streamed_ArchiveStreamRead() { ArchiveStreamRead("Zip.ppmd.dd.zip"); } + [Fact] public void Zip_PPMd_ArchiveStreamRead() { ArchiveStreamRead("Zip.ppmd.zip"); } + [Fact] public void Zip_None_ArchiveStreamRead() { @@ -87,53 +96,65 @@ namespace SharpCompress.Test.Zip { ArchiveFileRead("Zip.bzip2.dd.zip"); } + [Fact] public void Zip_BZip2_ArchiveFileRead() { ArchiveFileRead("Zip.bzip2.zip"); } + [Fact] public void WinZip26_ArchiveFileRead() { ArchiveFileRead("WinZip26.zip"); } + [Fact] public void WinZip26_Multi_ArchiveFileRead() { - ArchiveStreamMultiRead(null, "WinZip26.nocomp.multi.zip", - "WinZip26.nocomp.multi.z01"); //min split size is 64k so no compression used + ArchiveStreamMultiRead(null, "WinZip26.nocomp.multi.zip", "WinZip26.nocomp.multi.z01"); //min split size is 64k so no compression used } + [Fact] public void WinZip26_X_BZip2_ArchiveFileRead() { ArchiveFileRead("WinZip26_BZip2.zipx"); } + [Fact] public void WinZip26_X_Lzma_ArchiveFileRead() { ArchiveFileRead("WinZip26_LZMA.zipx"); } + [Fact] public void WinZip26_X_Multi_ArchiveFileRead() { - ArchiveStreamMultiRead(null, "WinZip26.nocomp.multi.zipx", - "WinZip26.nocomp.multi.zx01"); //min split size is 64k so no compression used + ArchiveStreamMultiRead( + null, + "WinZip26.nocomp.multi.zipx", + "WinZip26.nocomp.multi.zx01" + ); //min split size is 64k so no compression used } + [Fact] public void Zip_Deflate_Streamed2_ArchiveFileRead() { ArchiveFileRead("Zip.deflate.dd-.zip"); } + [Fact] public void Zip_Deflate_Streamed_ArchiveFileRead() { ArchiveFileRead("Zip.deflate.dd.zip"); } + [Fact] public void Zip_Deflate_ArchiveFileRead() { ArchiveFileRead("Zip.deflate.zip"); } + //will detect and load other files [Fact] public void Zip_Deflate_Multi_ArchiveFirstFileRead() @@ -141,68 +162,82 @@ namespace SharpCompress.Test.Zip ArchiveFileRead("WinZip26.nocomp.multi.zip"); //"WinZip26.nocomp.multi.z01" } + //will detect and load other files [Fact] public void ZipX_Deflate_Multi_ArchiveFirstFileRead() { ArchiveFileRead("WinZip26.nocomp.multi.zipx"); - //"WinZip26.nocomp.multi.zx01" + //"WinZip26.nocomp.multi.zx01" } + [Fact] public void Zip_GetParts() { //uses first part to search for all parts and compares against this array - ArchiveGetParts(new string[] { - "Infozip.nocomp.multi.zip", - "Infozip.nocomp.multi.z01"}); + ArchiveGetParts( + new string[] { "Infozip.nocomp.multi.zip", "Infozip.nocomp.multi.z01" } + ); } + [Fact] public void ZipX_GetParts() { //uses first part to search for all parts and compares against this array - ArchiveGetParts(new string[] { - "WinZip26.nocomp.multi.zipx", - "WinZip26.nocomp.multi.zx01"}); + ArchiveGetParts( + new string[] { "WinZip26.nocomp.multi.zipx", "WinZip26.nocomp.multi.zx01" } + ); } + [Fact] public void Zip_GetPartsSplit() { //uses first part to search for all parts and compares against this array - ArchiveGetParts(new string[] { - "Zip.deflate.split.001", - "Zip.deflate.split.002", - "Zip.deflate.split.003", - "Zip.deflate.split.004", - "Zip.deflate.split.005", - "Zip.deflate.split.006"}); + ArchiveGetParts( + new string[] + { + "Zip.deflate.split.001", + "Zip.deflate.split.002", + "Zip.deflate.split.003", + "Zip.deflate.split.004", + "Zip.deflate.split.005", + "Zip.deflate.split.006" + } + ); } + //will detect and load other files [Fact] public void Zip_Deflate_Split_ArchiveFirstFileRead() { ArchiveFileRead("Zip.deflate.split.001"); - //"Zip.deflate.split.002", - //"Zip.deflate.split.003", - //"Zip.deflate.split.004", - //"Zip.deflate.split.005", - //"Zip.deflate.split.006" + //"Zip.deflate.split.002", + //"Zip.deflate.split.003", + //"Zip.deflate.split.004", + //"Zip.deflate.split.005", + //"Zip.deflate.split.006" } + [Fact] public void Zip_Deflate_Split_ArchiveFileRead() { - ArchiveStreamMultiRead(null, "Zip.deflate.split.001", - "Zip.deflate.split.002", - "Zip.deflate.split.003", - "Zip.deflate.split.004", - "Zip.deflate.split.005", - "Zip.deflate.split.006"); + ArchiveStreamMultiRead( + null, + "Zip.deflate.split.001", + "Zip.deflate.split.002", + "Zip.deflate.split.003", + "Zip.deflate.split.004", + "Zip.deflate.split.005", + "Zip.deflate.split.006" + ); } + [Fact] public void Zip_InfoZip_Multi_ArchiveFileRead() { - ArchiveStreamMultiRead(null, "Infozip.nocomp.multi.zip", - "Infozip.nocomp.multi.z01"); //min split size is 64k so no compression used + ArchiveStreamMultiRead(null, "Infozip.nocomp.multi.zip", "Infozip.nocomp.multi.z01"); //min split size is 64k so no compression used } + [Fact] public void Zip_Deflate64_ArchiveFileRead() { @@ -214,21 +249,25 @@ namespace SharpCompress.Test.Zip { ArchiveFileRead("Zip.lzma.dd.zip"); } + [Fact] public void Zip_LZMA_ArchiveFileRead() { ArchiveFileRead("Zip.lzma.zip"); } + [Fact] public void Zip_PPMd_Streamed_ArchiveFileRead() { ArchiveFileRead("Zip.ppmd.dd.zip"); } + [Fact] public void Zip_PPMd_ArchiveFileRead() { ArchiveFileRead("Zip.ppmd.zip"); } + [Fact] public void Zip_None_ArchiveFileRead() { @@ -256,7 +295,9 @@ namespace SharpCompress.Test.Zip using (var archive = ZipArchive.Open(unmodified)) { - var entry = archive.Entries.Single(x => x.Key.EndsWith("jpg", StringComparison.OrdinalIgnoreCase)); + var entry = archive.Entries.Single( + x => x.Key.EndsWith("jpg", StringComparison.OrdinalIgnoreCase) + ); archive.RemoveEntry(entry); WriterOptions writerOptions = new ZipWriterOptions(CompressionType.Deflate); @@ -308,17 +349,24 @@ namespace SharpCompress.Test.Zip [Fact] public void Zip_Removal_Poly() { - string scratchPath = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.noEmptyDirs.zip"); - - using (ZipArchive vfs = (ZipArchive)ArchiveFactory.Open(scratchPath)) { - var e = vfs.Entries.First(v => v.Key.EndsWith("jpg", StringComparison.OrdinalIgnoreCase)); + var e = vfs.Entries.First( + v => v.Key.EndsWith("jpg", StringComparison.OrdinalIgnoreCase) + ); vfs.RemoveEntry(e); - Assert.Null(vfs.Entries.FirstOrDefault(v => v.Key.EndsWith("jpg", StringComparison.OrdinalIgnoreCase))); - Assert.Null(((IArchive)vfs).Entries.FirstOrDefault(v => v.Key.EndsWith("jpg", StringComparison.OrdinalIgnoreCase))); + Assert.Null( + vfs.Entries.FirstOrDefault( + v => v.Key.EndsWith("jpg", StringComparison.OrdinalIgnoreCase) + ) + ); + Assert.Null( + ((IArchive)vfs).Entries.FirstOrDefault( + v => v.Key.EndsWith("jpg", StringComparison.OrdinalIgnoreCase) + ) + ); } } @@ -355,15 +403,27 @@ namespace SharpCompress.Test.Zip [Fact] public void Zip_Create_New() { - foreach (var file in Directory.EnumerateFiles(ORIGINAL_FILES_PATH, "*.*", SearchOption.AllDirectories)) + foreach ( + var file in Directory.EnumerateFiles( + ORIGINAL_FILES_PATH, + "*.*", + SearchOption.AllDirectories + ) + ) { var newFileName = file.Substring(ORIGINAL_FILES_PATH.Length); - if (newFileName.StartsWith(Path.DirectorySeparatorChar.ToString(), StringComparison.OrdinalIgnoreCase)) + if ( + newFileName.StartsWith( + Path.DirectorySeparatorChar.ToString(), + StringComparison.OrdinalIgnoreCase + ) + ) { newFileName = newFileName.Substring(1); } newFileName = Path.Combine(SCRATCH_FILES_PATH, newFileName); - var newDir = Path.GetDirectoryName(newFileName) ?? throw new ArgumentNullException(); + var newDir = + Path.GetDirectoryName(newFileName) ?? throw new ArgumentNullException(); if (!Directory.Exists(newDir)) { Directory.CreateDirectory(newDir); @@ -411,15 +471,27 @@ namespace SharpCompress.Test.Zip [Fact] public void Zip_Create_New_Add_Remove() { - foreach (var file in Directory.EnumerateFiles(ORIGINAL_FILES_PATH, "*.*", SearchOption.AllDirectories)) + foreach ( + var file in Directory.EnumerateFiles( + ORIGINAL_FILES_PATH, + "*.*", + SearchOption.AllDirectories + ) + ) { var newFileName = file.Substring(ORIGINAL_FILES_PATH.Length); - if (newFileName.StartsWith(Path.DirectorySeparatorChar.ToString(), StringComparison.OrdinalIgnoreCase)) + if ( + newFileName.StartsWith( + Path.DirectorySeparatorChar.ToString(), + StringComparison.OrdinalIgnoreCase + ) + ) { newFileName = newFileName.Substring(1); } newFileName = Path.Combine(SCRATCH_FILES_PATH, newFileName); - var newDir = Path.GetDirectoryName(newFileName) ?? throw new ArgumentNullException(); + var newDir = + Path.GetDirectoryName(newFileName) ?? throw new ArgumentNullException(); if (!Directory.Exists(newDir)) { Directory.CreateDirectory(newDir); @@ -431,8 +503,16 @@ namespace SharpCompress.Test.Zip using (var archive = ZipArchive.Create()) { archive.AddAllFromDirectory(SCRATCH_FILES_PATH); - archive.RemoveEntry(archive.Entries.Single(x => x.Key.EndsWith("jpg", StringComparison.OrdinalIgnoreCase))); - Assert.Null(archive.Entries.FirstOrDefault(x => x.Key.EndsWith("jpg", StringComparison.OrdinalIgnoreCase))); + archive.RemoveEntry( + archive.Entries.Single( + x => x.Key.EndsWith("jpg", StringComparison.OrdinalIgnoreCase) + ) + ); + Assert.Null( + archive.Entries.FirstOrDefault( + x => x.Key.EndsWith("jpg", StringComparison.OrdinalIgnoreCase) + ) + ); } Directory.Delete(SCRATCH_FILES_PATH, true); } @@ -440,18 +520,19 @@ namespace SharpCompress.Test.Zip [Fact] public void Zip_Deflate_WinzipAES_Read() { - using (var reader = ZipArchive.Open(Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.WinzipAES.zip"), new ReaderOptions() - { - Password = "test" - })) + using ( + var reader = ZipArchive.Open( + Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.WinzipAES.zip"), + new ReaderOptions() { Password = "test" } + ) + ) { foreach (var entry in reader.Entries.Where(x => !x.IsDirectory)) { - entry.WriteToDirectory(SCRATCH_FILES_PATH, new ExtractionOptions() - { - ExtractFullPath = true, - Overwrite = true - }); + entry.WriteToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } + ); } } VerifyFiles(); @@ -460,10 +541,12 @@ namespace SharpCompress.Test.Zip [Fact] public void Zip_Deflate_WinzipAES_MultiOpenEntryStream() { - using (var reader = ZipArchive.Open(Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.WinzipAES2.zip"), new ReaderOptions() - { - Password = "test" - })) + using ( + var reader = ZipArchive.Open( + Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.WinzipAES2.zip"), + new ReaderOptions() { Password = "test" } + ) + ) { foreach (var entry in reader.Entries.Where(x => !x.IsDirectory)) { @@ -478,15 +561,18 @@ namespace SharpCompress.Test.Zip [Fact] public void Zip_Read_Volume_Comment() { - using (var reader = ZipArchive.Open(Path.Combine(TEST_ARCHIVES_PATH, "Zip.zip64.zip"), new ReaderOptions() - { - Password = "test" - })) + using ( + var reader = ZipArchive.Open( + Path.Combine(TEST_ARCHIVES_PATH, "Zip.zip64.zip"), + new ReaderOptions() { Password = "test" } + ) + ) { var isComplete = reader.IsComplete; Assert.Equal(1, reader.Volumes.Count); - string expectedComment = "Encoding:utf-8 || Compression:Deflate levelDefault || Encrypt:None || ZIP64:Always\r\nCreated at 2017-Jan-23 14:10:43 || DotNetZip Tool v1.9.1.8\r\nTest zip64 archive"; + string expectedComment = + "Encoding:utf-8 || Compression:Deflate levelDefault || Encrypt:None || ZIP64:Always\r\nCreated at 2017-Jan-23 14:10:43 || DotNetZip Tool v1.9.1.8\r\nTest zip64 archive"; Assert.Equal(expectedComment, reader.Volumes.First().Comment); } } @@ -494,18 +580,19 @@ namespace SharpCompress.Test.Zip [Fact] public void Zip_BZip2_Pkware_Read() { - using (var reader = ZipArchive.Open(Path.Combine(TEST_ARCHIVES_PATH, "Zip.bzip2.pkware.zip"), new ReaderOptions() - { - Password = "test" - })) + using ( + var reader = ZipArchive.Open( + Path.Combine(TEST_ARCHIVES_PATH, "Zip.bzip2.pkware.zip"), + new ReaderOptions() { Password = "test" } + ) + ) { foreach (var entry in reader.Entries.Where(x => !x.IsDirectory)) { - entry.WriteToDirectory(SCRATCH_FILES_PATH, new ExtractionOptions() - { - ExtractFullPath = true, - Overwrite = true - }); + entry.WriteToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } + ); } } VerifyFiles(); @@ -560,7 +647,12 @@ namespace SharpCompress.Test.Zip using (FileStream fileStream = File.Open(zipFile, FileMode.Open)) { - using (IArchive archive = ArchiveFactory.Open(fileStream, new ReaderOptions { Password = "12345678" })) + using ( + IArchive archive = ArchiveFactory.Open( + fileStream, + new ReaderOptions { Password = "12345678" } + ) + ) { var entries = archive.Entries.Where(entry => !entry.IsDirectory); foreach (IArchiveEntry entry in entries) @@ -592,11 +684,10 @@ namespace SharpCompress.Test.Zip { foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) { - entry.WriteToDirectory(SCRATCH_FILES_PATH, new ExtractionOptions() - { - ExtractFullPath = true, - Overwrite = true - }); + entry.WriteToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } + ); } } }); @@ -612,7 +703,13 @@ namespace SharpCompress.Test.Zip { MemoryStream stream = new NonSeekableMemoryStream(); - using (IWriter zipWriter = WriterFactory.Open(stream, ArchiveType.Zip, CompressionType.Deflate)) + using ( + IWriter zipWriter = WriterFactory.Open( + stream, + ArchiveType.Zip, + CompressionType.Deflate + ) + ) { zipWriter.Write("foo.txt", new MemoryStream(Array.Empty())); zipWriter.Write("foo2.txt", new MemoryStream(new byte[10])); @@ -738,7 +835,14 @@ namespace SharpCompress.Test.Zip [Fact] public void Zip_Uncompressed_Skip_All() { - var keys = new string[] { "Folder/File1.txt", "Folder/File2.rtf", "Folder2/File1.txt", "Folder2/File2.txt", "DEADBEEF" }; + var keys = new string[] + { + "Folder/File1.txt", + "Folder/File2.rtf", + "Folder2/File1.txt", + "Folder2/File2.txt", + "DEADBEEF" + }; var zipPath = Path.Combine(TEST_ARCHIVES_PATH, "Zip.uncompressed.zip"); using (var stream = File.Open(zipPath, FileMode.Open, FileAccess.Read)) { @@ -761,26 +865,32 @@ namespace SharpCompress.Test.Zip var zipPath = Path.Combine(TEST_ARCHIVES_PATH, "Zip.UnicodePathExtra.zip"); using (var stream = File.Open(zipPath, FileMode.Open, FileAccess.Read)) { - IArchive archive = ArchiveFactory.Open(stream, new ReaderOptions - { - ArchiveEncoding = new ArchiveEncoding + IArchive archive = ArchiveFactory.Open( + stream, + new ReaderOptions { - Default = Encoding.GetEncoding("shift_jis"), + ArchiveEncoding = new ArchiveEncoding + { + Default = Encoding.GetEncoding("shift_jis"), + } } - }); + ); IReader reader = archive.ExtractAllEntries(); reader.MoveToNextEntry(); Assert.Equal("궖귛궖귙귪궖귗귪궖귙_wav.frq", reader.Entry.Key); } using (var stream = File.Open(zipPath, FileMode.Open, FileAccess.Read)) { - IArchive archive = ArchiveFactory.Open(stream, new ReaderOptions - { - ArchiveEncoding = new ArchiveEncoding + IArchive archive = ArchiveFactory.Open( + stream, + new ReaderOptions { - Forced = Encoding.GetEncoding("shift_jis"), + ArchiveEncoding = new ArchiveEncoding + { + Forced = Encoding.GetEncoding("shift_jis"), + } } - }); + ); IReader reader = archive.ExtractAllEntries(); reader.MoveToNextEntry(); Assert.Equal("きょきゅんきゃんきゅ_wav.frq", reader.Entry.Key); diff --git a/tests/SharpCompress.Test/Zip/ZipReaderTests.cs b/tests/SharpCompress.Test/Zip/ZipReaderTests.cs index 65ae9326..446c0e82 100644 --- a/tests/SharpCompress.Test/Zip/ZipReaderTests.cs +++ b/tests/SharpCompress.Test/Zip/ZipReaderTests.cs @@ -56,25 +56,33 @@ namespace SharpCompress.Test.Zip { Read("Zip.bzip2.dd.zip", CompressionType.BZip2); } + [Fact] public void Zip_BZip2_Read() { Read("Zip.bzip2.zip", CompressionType.BZip2); } + [Fact] public void Zip_Deflate_Streamed2_Read() { Read("Zip.deflate.dd-.zip", CompressionType.Deflate); } + [Fact] public void Zip_Deflate_Streamed_Read() { Read("Zip.deflate.dd.zip", CompressionType.Deflate); } + [Fact] public void Zip_Deflate_Streamed_Skip() { - using (Stream stream = new ForwardOnlyStream(File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.dd.zip")))) + using ( + Stream stream = new ForwardOnlyStream( + File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.dd.zip")) + ) + ) using (IReader reader = ReaderFactory.Open(stream)) { int x = 0; @@ -85,22 +93,22 @@ namespace SharpCompress.Test.Zip x++; if (x % 2 == 0) { - reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, - new ExtractionOptions() - { - ExtractFullPath = true, - Overwrite = true - }); + reader.WriteEntryToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } + ); } } } } } + [Fact] public void Zip_Deflate_Read() { Read("Zip.deflate.zip", CompressionType.Deflate); } + [Fact] public void Zip_Deflate64_Read() { @@ -112,16 +120,19 @@ namespace SharpCompress.Test.Zip { Read("Zip.lzma.dd.zip", CompressionType.LZMA); } + [Fact] public void Zip_LZMA_Read() { Read("Zip.lzma.zip", CompressionType.LZMA); } + [Fact] public void Zip_PPMd_Streamed_Read() { Read("Zip.ppmd.dd.zip", CompressionType.PPMd); } + [Fact] public void Zip_PPMd_Read() { @@ -143,22 +154,22 @@ namespace SharpCompress.Test.Zip [Fact] public void Zip_BZip2_PkwareEncryption_Read() { - using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Zip.bzip2.pkware.zip"))) - using (var reader = ZipReader.Open(stream, new ReaderOptions() - { - Password = "test" - })) + using ( + Stream stream = File.OpenRead( + Path.Combine(TEST_ARCHIVES_PATH, "Zip.bzip2.pkware.zip") + ) + ) + using (var reader = ZipReader.Open(stream, new ReaderOptions() { Password = "test" })) { while (reader.MoveToNextEntry()) { if (!reader.Entry.IsDirectory) { Assert.Equal(CompressionType.BZip2, reader.Entry.CompressionType); - reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, new ExtractionOptions() - { - ExtractFullPath = true, - Overwrite = true - }); + reader.WriteEntryToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } + ); } } } @@ -168,7 +179,11 @@ namespace SharpCompress.Test.Zip [Fact] public void Zip_Reader_Disposal_Test() { - using (TestStream stream = new TestStream(File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.dd.zip")))) + using ( + TestStream stream = new TestStream( + File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.dd.zip")) + ) + ) { using (var reader = ReaderFactory.Open(stream)) { @@ -176,12 +191,10 @@ namespace SharpCompress.Test.Zip { if (!reader.Entry.IsDirectory) { - reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, - new ExtractionOptions() - { - ExtractFullPath = true, - Overwrite = true - }); + reader.WriteEntryToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } + ); } } } @@ -192,19 +205,21 @@ namespace SharpCompress.Test.Zip [Fact] public void Zip_Reader_Disposal_Test2() { - using (TestStream stream = new TestStream(File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.dd.zip")))) + using ( + TestStream stream = new TestStream( + File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.dd.zip")) + ) + ) { var reader = ReaderFactory.Open(stream); while (reader.MoveToNextEntry()) { if (!reader.Entry.IsDirectory) { - reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, - new ExtractionOptions() - { - ExtractFullPath = true, - Overwrite = true - }); + reader.WriteEntryToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } + ); } } Assert.False(stream.IsDisposed); @@ -215,54 +230,51 @@ namespace SharpCompress.Test.Zip public void Zip_LZMA_WinzipAES_Read() { Assert.Throws(() => - { - using ( - Stream stream = - File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, - "Zip.lzma.WinzipAES.zip"))) - using (var reader = ZipReader.Open(stream, new ReaderOptions() - { - Password = "test" - })) - { - while (reader.MoveToNextEntry()) - { - if (!reader.Entry.IsDirectory) - { - Assert.Equal(CompressionType.Unknown, reader.Entry.CompressionType); - reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, - new ExtractionOptions() - { - ExtractFullPath = true, - Overwrite = true - }); - } - } - } - VerifyFiles(); - }); + { + using ( + Stream stream = File.OpenRead( + Path.Combine(TEST_ARCHIVES_PATH, "Zip.lzma.WinzipAES.zip") + ) + ) + using ( + var reader = ZipReader.Open(stream, new ReaderOptions() { Password = "test" }) + ) + { + while (reader.MoveToNextEntry()) + { + if (!reader.Entry.IsDirectory) + { + Assert.Equal(CompressionType.Unknown, reader.Entry.CompressionType); + reader.WriteEntryToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } + ); + } + } + } + VerifyFiles(); + }); } [Fact] public void Zip_Deflate_WinzipAES_Read() { - using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.WinzipAES.zip"))) - using (var reader = ZipReader.Open(stream, new ReaderOptions() - { - Password = "test" - })) + using ( + Stream stream = File.OpenRead( + Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.WinzipAES.zip") + ) + ) + using (var reader = ZipReader.Open(stream, new ReaderOptions() { Password = "test" })) { while (reader.MoveToNextEntry()) { if (!reader.Entry.IsDirectory) { Assert.Equal(CompressionType.Unknown, reader.Entry.CompressionType); - reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, - new ExtractionOptions() - { - ExtractFullPath = true, - Overwrite = true - }); + reader.WriteEntryToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } + ); } } } @@ -274,22 +286,17 @@ namespace SharpCompress.Test.Zip { int count = 0; using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "zipcrypto.zip"))) - using (var reader = ZipReader.Open(stream, new ReaderOptions() - { - Password = "test" - })) + using (var reader = ZipReader.Open(stream, new ReaderOptions() { Password = "test" })) { while (reader.MoveToNextEntry()) { if (!reader.Entry.IsDirectory) { Assert.Equal(CompressionType.None, reader.Entry.CompressionType); - reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, - new ExtractionOptions() - { - ExtractFullPath = true, - Overwrite = true - }); + reader.WriteEntryToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } + ); count++; } } @@ -310,7 +317,13 @@ namespace SharpCompress.Test.Zip { Stream stream = new TestStream(memory, read: true, write: true, seek: false); - using (IWriter zipWriter = WriterFactory.Open(stream, ArchiveType.Zip, CompressionType.Deflate)) + using ( + IWriter zipWriter = WriterFactory.Open( + stream, + ArchiveType.Zip, + CompressionType.Deflate + ) + ) { zipWriter.Write(expected[0].Item1, new MemoryStream(expected[0].Item2)); zipWriter.Write(expected[1].Item1, new MemoryStream(expected[1].Item2)); @@ -347,9 +360,22 @@ namespace SharpCompress.Test.Zip [Fact] public void Zip_None_Issue86_Streamed_Read() { - var keys = new string[] { "Empty1", "Empty2", "Dir1/", "Dir2/", "Fake1", "Fake2", "Internal.zip" }; + var keys = new string[] + { + "Empty1", + "Empty2", + "Dir1/", + "Dir2/", + "Fake1", + "Fake2", + "Internal.zip" + }; - using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Zip.none.issue86.zip"))) + using ( + Stream stream = File.OpenRead( + Path.Combine(TEST_ARCHIVES_PATH, "Zip.none.issue86.zip") + ) + ) using (var reader = ZipReader.Open(stream)) { foreach (var key in keys) @@ -376,7 +402,7 @@ namespace SharpCompress.Test.Zip using (var fileStream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "test_477.zip"))) using (var reader = ZipReader.Open(fileStream)) { - foreach( var key in keys) + foreach (var key in keys) { reader.MoveToNextEntry(); @@ -384,14 +410,16 @@ namespace SharpCompress.Test.Zip } } } + [Fact] public void Issue_685() { var count = 0; - using (var fileStream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Issue_685.zip"))) + using ( + var fileStream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Issue_685.zip")) + ) using (var reader = ZipReader.Open(fileStream)) { - while (reader.MoveToNextEntry()) { count++; @@ -433,6 +461,5 @@ namespace SharpCompress.Test.Zip Assert.Equal(4, x); } } - } } diff --git a/tests/SharpCompress.Test/Zip/ZipWriterTests.cs b/tests/SharpCompress.Test/Zip/ZipWriterTests.cs index 8d546cec..28e90f51 100644 --- a/tests/SharpCompress.Test/Zip/ZipWriterTests.cs +++ b/tests/SharpCompress.Test/Zip/ZipWriterTests.cs @@ -7,47 +7,74 @@ namespace SharpCompress.Test.Zip { public class ZipWriterTests : WriterTests { - public ZipWriterTests() - : base(ArchiveType.Zip) - { - } - + public ZipWriterTests() : base(ArchiveType.Zip) { } [Fact] public void Zip_Deflate_Write() { - Write(CompressionType.Deflate, "Zip.deflate.noEmptyDirs.zip", "Zip.deflate.noEmptyDirs.zip", Encoding.UTF8); + Write( + CompressionType.Deflate, + "Zip.deflate.noEmptyDirs.zip", + "Zip.deflate.noEmptyDirs.zip", + Encoding.UTF8 + ); } [Fact] public void Zip_BZip2_Write() { - Write(CompressionType.BZip2, "Zip.bzip2.noEmptyDirs.zip", "Zip.bzip2.noEmptyDirs.zip", Encoding.UTF8); + Write( + CompressionType.BZip2, + "Zip.bzip2.noEmptyDirs.zip", + "Zip.bzip2.noEmptyDirs.zip", + Encoding.UTF8 + ); } [Fact] public void Zip_None_Write() { - Write(CompressionType.None, "Zip.none.noEmptyDirs.zip", "Zip.none.noEmptyDirs.zip", Encoding.UTF8); + Write( + CompressionType.None, + "Zip.none.noEmptyDirs.zip", + "Zip.none.noEmptyDirs.zip", + Encoding.UTF8 + ); } [Fact] public void Zip_LZMA_Write() { - Write(CompressionType.LZMA, "Zip.lzma.noEmptyDirs.zip", "Zip.lzma.noEmptyDirs.zip", Encoding.UTF8); + Write( + CompressionType.LZMA, + "Zip.lzma.noEmptyDirs.zip", + "Zip.lzma.noEmptyDirs.zip", + Encoding.UTF8 + ); } [Fact] public void Zip_PPMd_Write() { - Write(CompressionType.PPMd, "Zip.ppmd.noEmptyDirs.zip", "Zip.ppmd.noEmptyDirs.zip", Encoding.UTF8); + Write( + CompressionType.PPMd, + "Zip.ppmd.noEmptyDirs.zip", + "Zip.ppmd.noEmptyDirs.zip", + Encoding.UTF8 + ); } - [Fact] public void Zip_Rar_Write() { - Assert.Throws(() => Write(CompressionType.Rar, "Zip.ppmd.noEmptyDirs.zip", "Zip.ppmd.noEmptyDirs.zip")); + Assert.Throws( + () => + Write( + CompressionType.Rar, + "Zip.ppmd.noEmptyDirs.zip", + "Zip.ppmd.noEmptyDirs.zip" + ) + ); } } } From 959bbdcf1b83ff616280eaa17ecb08da3df4521e Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Tue, 20 Dec 2022 15:06:44 +0000 Subject: [PATCH 5/7] big clean up --- build/Program.cs | 2 +- src/SharpCompress/Algorithms/Adler32.cs | 763 ++- src/SharpCompress/Archives/AbstractArchive.cs | 303 +- .../Archives/AbstractWritableArchive.cs | 356 +- src/SharpCompress/Archives/ArchiveFactory.cs | 364 +- .../Archives/GZip/GZipArchive.cs | 393 +- .../Archives/GZip/GZipArchiveEntry.cs | 51 +- .../Archives/GZip/GZipWritableArchiveEntry.cs | 115 +- src/SharpCompress/Archives/IArchive.cs | 69 +- src/SharpCompress/Archives/IArchiveEntry.cs | 35 +- .../Archives/IArchiveEntryExtensions.cs | 127 +- .../Archives/IArchiveExtensions.cs | 29 +- .../Archives/IArchiveExtractionListener.cs | 15 +- src/SharpCompress/Archives/IArchiveFactory.cs | 57 +- .../Archives/IMultiArchiveFactory.cs | 62 +- .../Archives/IWritableArchive.cs | 35 +- .../Archives/IWritableArchiveEntry.cs | 11 +- .../Archives/IWritableArchiveExtensions.cs | 155 +- .../Archives/IWriteableArchiveFactory.cs | 37 +- .../Archives/Rar/FileInfoRarArchiveVolume.cs | 65 +- .../Archives/Rar/FileInfoRarFilePart.cs | 33 +- .../Archives/Rar/RarArchive.Extensions.cs | 33 +- src/SharpCompress/Archives/Rar/RarArchive.cs | 343 +- .../Archives/Rar/RarArchiveEntry.cs | 138 +- .../Archives/Rar/RarArchiveEntryFactory.cs | 83 +- .../Archives/Rar/SeekableFilePart.cs | 57 +- .../Archives/Rar/StreamRarArchiveVolume.cs | 37 +- .../Archives/SevenZip/SevenZipArchive.cs | 481 +- .../Archives/SevenZip/SevenZipArchiveEntry.cs | 41 +- src/SharpCompress/Archives/Tar/TarArchive.cs | 421 +- .../Archives/Tar/TarArchiveEntry.cs | 47 +- .../Archives/Tar/TarWritableArchiveEntry.cs | 115 +- src/SharpCompress/Archives/Zip/ZipArchive.cs | 576 ++- .../Archives/Zip/ZipArchiveEntry.cs | 43 +- .../Archives/Zip/ZipWritableArchiveEntry.cs | 119 +- src/SharpCompress/AssemblyInfo.cs | 2 +- src/SharpCompress/Common/ArchiveEncoding.cs | 119 +- src/SharpCompress/Common/ArchiveException.cs | 11 +- .../Common/ArchiveExtractionEventArgs.cs | 17 +- src/SharpCompress/Common/ArchiveType.cs | 17 +- .../Common/CompressedBytesReadEventArgs.cs | 41 +- src/SharpCompress/Common/CompressionType.cs | 33 +- .../Common/CryptographicException.cs | 11 +- src/SharpCompress/Common/Entry.cs | 133 +- src/SharpCompress/Common/EntryStream.cs | 151 +- .../Common/ExtractionException.cs | 13 +- src/SharpCompress/Common/ExtractionMethods.cs | 2 +- src/SharpCompress/Common/ExtractionOptions.cs | 73 +- src/SharpCompress/Common/FilePart.cs | 29 +- .../FilePartExtractionBeginEventArgs.cs | 47 +- src/SharpCompress/Common/FlagUtility.cs | 179 +- src/SharpCompress/Common/GZip/GZipEntry.cs | 53 +- src/SharpCompress/Common/GZip/GZipFilePart.cs | 217 +- src/SharpCompress/Common/GZip/GZipVolume.cs | 27 +- src/SharpCompress/Common/IEntry.Extensions.cs | 67 +- src/SharpCompress/Common/IEntry.cs | 42 +- .../Common/IExtractionListener.cs | 11 +- src/SharpCompress/Common/IVolume.cs | 13 +- .../Common/IncompleteArchiveException.cs | 9 +- .../Common/InvalidFormatException.cs | 13 +- .../Common/MultiVolumeExtractionException.cs | 15 +- .../MultipartStreamRequiredException.cs | 9 +- src/SharpCompress/Common/OptionsBase.cs | 19 +- .../Common/PasswordProtectedException.cs | 15 +- .../Common/Rar/Headers/AVHeader.cs | 49 +- .../Common/Rar/Headers/ArchiveCryptHeader.cs | 88 +- .../Common/Rar/Headers/ArchiveHeader.cs | 125 +- .../Common/Rar/Headers/CommentHeader.cs | 47 +- .../Common/Rar/Headers/EndArchiveHeader.cs | 59 +- .../Common/Rar/Headers/FileHeader.cs | 895 ++-- .../Common/Rar/Headers/FileNameDecoder.cs | 149 +- src/SharpCompress/Common/Rar/Headers/Flags.cs | 293 +- .../Common/Rar/Headers/IRarHeader.cs | 9 +- .../Common/Rar/Headers/MarkHeader.cs | 195 +- .../Common/Rar/Headers/NewSubHeaderType.cs | 83 +- .../Common/Rar/Headers/ProtectHeader.cs | 47 +- .../Common/Rar/Headers/RarHeader.cs | 253 +- .../Common/Rar/Headers/RarHeaderFactory.cs | 337 +- .../Common/Rar/Headers/SignHeader.cs | 43 +- .../Common/Rar/RarCrcBinaryReader.cs | 67 +- .../Common/Rar/RarCryptoBinaryReader.cs | 201 +- .../Common/Rar/RarCryptoWrapper.cs | 151 +- src/SharpCompress/Common/Rar/RarEntry.cs | 135 +- src/SharpCompress/Common/Rar/RarFilePart.cs | 33 +- src/SharpCompress/Common/Rar/RarRijndael.cs | 209 +- src/SharpCompress/Common/Rar/RarVolume.cs | 308 +- .../Common/ReaderExtractionEventArgs.cs | 23 +- .../Common/SevenZip/ArchiveDatabase.cs | 329 +- .../Common/SevenZip/ArchiveReader.cs | 3092 ++++++------ .../Common/SevenZip/CBindPair.cs | 11 +- .../Common/SevenZip/CCoderInfo.cs | 17 +- .../Common/SevenZip/CFileItem.cs | 55 +- src/SharpCompress/Common/SevenZip/CFolder.cs | 301 +- .../Common/SevenZip/CMethodId.cs | 95 +- .../Common/SevenZip/CStreamSwitch.cs | 95 +- .../Common/SevenZip/DataReader.cs | 355 +- .../Common/SevenZip/SevenZipEntry.cs | 79 +- .../Common/SevenZip/SevenZipFilePart.cs | 206 +- .../Common/SevenZip/SevenZipVolume.cs | 11 +- .../Common/Tar/Headers/EntryType.cs | 33 +- .../Common/Tar/Headers/TarHeader.cs | 593 +-- src/SharpCompress/Common/Tar/TarEntry.cs | 119 +- src/SharpCompress/Common/Tar/TarFilePart.cs | 50 +- .../Common/Tar/TarHeaderFactory.cs | 95 +- .../Common/Tar/TarReadOnlySubStream.cs | 2 +- src/SharpCompress/Common/Tar/TarVolume.cs | 11 +- src/SharpCompress/Common/Volume.cs | 81 +- .../Common/Zip/Headers/DirectoryEndHeader.cs | 73 +- .../Zip/Headers/DirectoryEntryHeader.cs | 181 +- .../Common/Zip/Headers/HeaderFlags.cs | 27 +- .../Common/Zip/Headers/IgnoreHeader.cs | 13 +- .../Common/Zip/Headers/LocalEntryHeader.cs | 125 +- .../Headers/LocalEntryHeaderExtraFactory.cs | 303 +- .../Common/Zip/Headers/SplitHeader.cs | 19 +- .../Zip/Headers/Zip64DirectoryEndHeader.cs | 89 +- .../Headers/Zip64DirectoryEndLocatorHeader.cs | 31 +- .../Common/Zip/Headers/ZipFileEntry.cs | 197 +- .../Common/Zip/Headers/ZipHeader.cs | 27 +- .../Common/Zip/Headers/ZipHeaderType.cs | 21 +- .../Zip/PkwareTraditionalCryptoStream.cs | 173 +- .../Zip/PkwareTraditionalEncryptionData.cs | 215 +- .../Common/Zip/SeekableZipFilePart.cs | 95 +- .../Common/Zip/SeekableZipHeaderFactory.cs | 250 +- .../Common/Zip/StreamingZipFilePart.cs | 161 +- .../Common/Zip/StreamingZipHeaderFactory.cs | 189 +- .../Common/Zip/WinzipAesCryptoStream.cs | 335 +- .../Common/Zip/WinzipAesEncryptionData.cs | 117 +- .../Common/Zip/WinzipAesKeySize.cs | 13 +- .../Common/Zip/ZipCompressionMethod.cs | 21 +- src/SharpCompress/Common/Zip/ZipEntry.cs | 143 +- src/SharpCompress/Common/Zip/ZipFilePart.cs | 351 +- .../Common/Zip/ZipHeaderFactory.cs | 357 +- src/SharpCompress/Common/Zip/ZipVolume.cs | 15 +- src/SharpCompress/Compressors/ADC/ADCBase.cs | 319 +- .../Compressors/ADC/ADCStream.cs | 271 +- .../Compressors/BZip2/BZip2Constants.cs | 1071 +++-- .../Compressors/BZip2/BZip2Stream.cs | 201 +- .../Compressors/BZip2/CBZip2InputStream.cs | 1962 ++++---- .../Compressors/BZip2/CBZip2OutputStream.cs | 3553 +++++++------- src/SharpCompress/Compressors/BZip2/CRC.cs | 609 ++- .../Compressors/CompressionMode.cs | 11 +- .../Compressors/Deflate/CRC32.cs | 429 +- .../Compressors/Deflate/DeflateManager.cs | 3824 +++++++-------- .../Compressors/Deflate/DeflateStream.cs | 697 ++- .../Compressors/Deflate/FlushType.cs | 75 +- .../Compressors/Deflate/GZipStream.cs | 888 ++-- .../Compressors/Deflate/InfTree.cs | 4211 ++++++++--------- .../Compressors/Deflate/Inflate.cs | 3538 +++++++------- src/SharpCompress/Compressors/Deflate/Tree.cs | 2265 +++++---- src/SharpCompress/Compressors/Deflate/Zlib.cs | 1837 ++++--- .../Compressors/Deflate/ZlibCodec.cs | 1319 +++--- .../Compressors/Deflate/ZlibConstants.cs | 91 +- .../Compressors/Deflate/ZlibStream.cs | 625 ++- .../Compressors/Deflate64/BlockType.cs | 13 +- .../Compressors/Deflate64/DeflateInput.cs | 73 +- .../Deflate64/FastEncoderStatus.cs | 1917 ++++---- .../Compressors/Deflate64/HuffmanTree.cs | 587 ++- .../Compressors/Deflate64/InflaterManaged.cs | 1523 +++--- .../Compressors/Deflate64/InflaterState.cs | 59 +- .../Compressors/Deflate64/InputBuffer.cs | 311 +- .../Compressors/Deflate64/Match.cs | 21 +- .../Compressors/Deflate64/MatchState.cs | 13 +- .../Compressors/Deflate64/OutputWindow.cs | 249 +- .../Compressors/Filters/BCJ2Filter.cs | 379 +- .../Compressors/Filters/BCJFilter.cs | 225 +- .../Compressors/Filters/BranchExecFilter.cs | 577 +-- .../Compressors/Filters/Filter.cs | 261 +- .../Compressors/LZMA/Bcj2DecoderStream.cs | 443 +- .../Compressors/LZMA/BitVector.cs | 175 +- src/SharpCompress/Compressors/LZMA/CRC.cs | 147 +- .../Compressors/LZMA/DecoderStream.cs | 429 +- src/SharpCompress/Compressors/LZMA/ICoder.cs | 327 +- .../Compressors/LZMA/LZ/LzBinTree.cs | 705 ++- .../Compressors/LZMA/LZ/LzInWindow.cs | 324 +- .../Compressors/LZMA/LZ/LzOutWindow.cs | 361 +- .../Compressors/LZMA/LZipStream.cs | 413 +- src/SharpCompress/Compressors/LZMA/Log.cs | 143 +- .../Compressors/LZMA/LzmaBase.cs | 175 +- .../Compressors/LZMA/LzmaDecoder.cs | 923 ++-- .../Compressors/LZMA/LzmaEncoder.cs | 3447 +++++++------- .../Compressors/LZMA/LzmaEncoderProperties.cs | 79 +- .../Compressors/LZMA/LzmaStream.cs | 587 ++- .../Compressors/LZMA/RangeCoder/RangeCoder.cs | 438 +- .../LZMA/RangeCoder/RangeCoderBit.cs | 243 +- .../LZMA/RangeCoder/RangeCoderBitTree.cs | 299 +- .../Compressors/LZMA/Registry.cs | 90 +- .../LZMA/Utilites/CrcBuilderStream.cs | 145 +- .../LZMA/Utilites/CrcCheckStream.cs | 185 +- .../LZMA/Utilites/IPasswordProvider.cs | 9 +- .../Compressors/LZMA/Utilites/Utils.cs | 145 +- .../Compressors/PPMd/H/FreqData.cs | 103 +- .../Compressors/PPMd/H/ModelPPM.cs | 1786 ++++--- .../Compressors/PPMd/H/PPMContext.cs | 1148 +++-- .../Compressors/PPMd/H/Pointer.cs | 33 +- .../Compressors/PPMd/H/RangeCoder.cs | 290 +- .../Compressors/PPMd/H/RarMemBlock.cs | 217 +- .../Compressors/PPMd/H/RarNode.cs | 75 +- .../Compressors/PPMd/H/SEE2Context.cs | 156 +- src/SharpCompress/Compressors/PPMd/H/State.cs | 147 +- .../Compressors/PPMd/H/StateRef.cs | 128 +- .../Compressors/PPMd/H/SubAllocator.cs | 853 ++-- .../Compressors/PPMd/I1/Allocator.cs | 935 ++-- .../Compressors/PPMd/I1/Coder.cs | 193 +- .../Compressors/PPMd/I1/MemoryNode.cs | 484 +- .../Compressors/PPMd/I1/Model.cs | 1749 ++++--- .../PPMd/I1/ModelRestorationMethod.cs | 33 +- .../Compressors/PPMd/I1/Pointer.cs | 706 ++- .../Compressors/PPMd/I1/PpmContext.cs | 1572 +++--- .../Compressors/PPMd/I1/PpmState.cs | 388 +- .../Compressors/PPMd/I1/See2Context.cs | 81 +- .../Compressors/PPMd/PpmdProperties.cs | 125 +- .../Compressors/PPMd/PpmdStream.cs | 213 +- .../Compressors/PPMd/PpmdVersion.cs | 13 +- .../Compressors/Rar/IRarUnpack.cs | 23 +- .../Rar/MultiVolumeReadOnlyStream.cs | 285 +- src/SharpCompress/Compressors/Rar/RarCRC.cs | 61 +- .../Compressors/Rar/RarCrcStream.cs | 71 +- .../Compressors/Rar/RarStream.cs | 227 +- .../Rar/UnpackV1/Decode/AudioVariables.cs | 43 +- .../Rar/UnpackV1/Decode/BitDecode.cs | 9 +- .../Rar/UnpackV1/Decode/CodeType.cs | 25 +- .../Compressors/Rar/UnpackV1/Decode/Decode.cs | 53 +- .../Rar/UnpackV1/Decode/DistDecode.cs | 9 +- .../Rar/UnpackV1/Decode/FilterType.cs | 29 +- .../Rar/UnpackV1/Decode/LitDecode.cs | 9 +- .../Rar/UnpackV1/Decode/LowDistDecode.cs | 9 +- .../Rar/UnpackV1/Decode/MultDecode.cs | 9 +- .../Rar/UnpackV1/Decode/PackDef.cs | 79 +- .../Rar/UnpackV1/Decode/RepDecode.cs | 9 +- .../Rar/UnpackV1/PPM/BlockTypes.cs | 11 +- .../Compressors/Rar/UnpackV1/Unpack.cs | 2252 +++++---- .../Compressors/Rar/UnpackV1/Unpack15.cs | 1451 +++--- .../Compressors/Rar/UnpackV1/Unpack20.cs | 1167 +++-- .../Compressors/Rar/UnpackV1/Unpack50.cs | 1781 ++++--- .../Compressors/Rar/UnpackV1/UnpackFilter.cs | 69 +- .../Compressors/Rar/UnpackV1/UnpackInline.cs | 51 +- .../Compressors/Rar/UnpackV1/UnpackUtility.cs | 363 +- .../Rar/UnpackV2017/BitInput.getbits_cpp.cs | 85 +- .../Rar/UnpackV2017/BitInput.getbits_hpp.cs | 115 +- .../FragmentedWindow.unpack50frag_cpp.cs | 280 +- .../Rar/UnpackV2017/PackDef.compress_hpp.cs | 89 +- .../Compressors/Rar/UnpackV2017/Unpack.cs | 207 +- .../Rar/UnpackV2017/Unpack.rawint_hpp.cs | 219 +- .../Rar/UnpackV2017/Unpack.unpack15_cpp.cs | 1267 ++--- .../Rar/UnpackV2017/Unpack.unpack20_cpp.cs | 1142 +++-- .../Rar/UnpackV2017/Unpack.unpack30_cpp.cs | 6 +- .../Rar/UnpackV2017/Unpack.unpack50_cpp.cs | 1633 ++++--- .../Rar/UnpackV2017/Unpack.unpack_cpp.cs | 699 ++- .../UnpackV2017/Unpack.unpackinline_cpp.cs | 318 +- .../Compressors/Rar/UnpackV2017/unpack_hpp.cs | 660 ++- .../Compressors/Rar/VM/BitInput.cs | 183 +- src/SharpCompress/Compressors/Rar/VM/RarVM.cs | 3104 ++++++------ .../Compressors/Rar/VM/VMCmdFlags.cs | 113 +- .../Compressors/Rar/VM/VMCommands.cs | 117 +- .../Compressors/Rar/VM/VMFlags.cs | 15 +- .../Compressors/Rar/VM/VMOpType.cs | 15 +- .../Compressors/Rar/VM/VMPreparedCommand.cs | 25 +- .../Compressors/Rar/VM/VMPreparedOperand.cs | 15 +- .../Compressors/Rar/VM/VMPreparedProgram.cs | 25 +- .../Rar/VM/VMStandardFilterSignature.cs | 27 +- .../Compressors/Rar/VM/VMStandardFilters.cs | 23 +- .../Compressors/Xz/BinaryUtils.cs | 95 +- src/SharpCompress/Compressors/Xz/CheckType.cs | 15 +- src/SharpCompress/Compressors/Xz/Crc32.cs | 107 +- src/SharpCompress/Compressors/Xz/Crc64.cs | 98 +- .../Compressors/Xz/Filters/ArmFilter.cs | 86 +- .../Compressors/Xz/Filters/ArmThumbFilter.cs | 86 +- .../Compressors/Xz/Filters/BlockFilter.cs | 119 +- .../Compressors/Xz/Filters/IA64Filter.cs | 86 +- .../Compressors/Xz/Filters/Lzma2Filter.cs | 103 +- .../Compressors/Xz/Filters/PowerPCFilter.cs | 86 +- .../Compressors/Xz/Filters/SparcFilter.cs | 86 +- .../Compressors/Xz/Filters/X86Filter.cs | 90 +- .../Compressors/Xz/MultiByteIntegers.cs | 67 +- .../Compressors/Xz/ReadOnlyStream.cs | 67 +- src/SharpCompress/Compressors/Xz/XZBlock.cs | 331 +- src/SharpCompress/Compressors/Xz/XZFooter.cs | 73 +- src/SharpCompress/Compressors/Xz/XZHeader.cs | 85 +- src/SharpCompress/Compressors/Xz/XZIndex.cs | 143 +- .../Xz/XZIndexMarkerReachedException.cs | 9 +- .../Compressors/Xz/XZIndexRecord.cs | 31 +- .../Compressors/Xz/XZReadOnlyStream.cs | 17 +- src/SharpCompress/Compressors/Xz/XZStream.cs | 235 +- src/SharpCompress/Crypto/Crc32Stream.cs | 223 +- src/SharpCompress/Crypto/CryptoException.cs | 15 +- .../Crypto/DataLengthException.cs | 33 +- src/SharpCompress/Crypto/IBlockCipher.cs | 51 +- src/SharpCompress/Crypto/ICipherParameters.cs | 7 +- src/SharpCompress/Crypto/KeyParameter.cs | 63 +- src/SharpCompress/Crypto/RijndaelEngine.cs | 3706 ++++++++------- src/SharpCompress/Factories/Factory.cs | 156 +- src/SharpCompress/Factories/GZipFactory.cs | 235 +- src/SharpCompress/Factories/IFactory.cs | 81 +- src/SharpCompress/Factories/RarFactory.cs | 152 +- .../Factories/SevenZipFactory.cs | 146 +- src/SharpCompress/Factories/TarFactory.cs | 328 +- src/SharpCompress/Factories/ZipFactory.cs | 223 +- src/SharpCompress/IO/BufferedSubStream.cs | 133 +- .../IO/CountingWritableSubStream.cs | 87 +- src/SharpCompress/IO/ListeningStream.cs | 151 +- src/SharpCompress/IO/MarkingBinaryReader.cs | 375 +- src/SharpCompress/IO/NonDisposingStream.cs | 129 +- src/SharpCompress/IO/ReadOnlySubStream.cs | 133 +- src/SharpCompress/IO/RewindableStream.cs | 255 +- src/SharpCompress/IO/SourceStream.cs | 431 +- src/SharpCompress/IO/StreamingMode.cs | 11 +- src/SharpCompress/Lazy.cs | 35 +- src/SharpCompress/LazyReadOnlyCollection.cs | 249 +- .../Polyfills/StreamExtensions.cs | 55 +- .../Polyfills/StringExtensions.cs | 21 +- src/SharpCompress/ReadOnlyCollection.cs | 77 +- src/SharpCompress/Readers/AbstractReader.cs | 497 +- src/SharpCompress/Readers/GZip/GZipReader.cs | 49 +- src/SharpCompress/Readers/IReader.cs | 53 +- .../Readers/IReaderExtensions.cs | 131 +- .../Readers/IReaderExtractionListener.cs | 11 +- src/SharpCompress/Readers/IReaderFactory.cs | 26 +- .../Readers/Rar/MultiVolumeRarReader.cs | 185 +- .../Readers/Rar/NonSeekableStreamFilePart.cs | 23 +- src/SharpCompress/Readers/Rar/RarReader.cs | 127 +- .../Readers/Rar/RarReaderEntry.cs | 51 +- .../Readers/Rar/RarReaderVolume.cs | 25 +- .../Readers/Rar/SingleVolumeRarReader.cs | 41 +- src/SharpCompress/Readers/ReaderFactory.cs | 53 +- src/SharpCompress/Readers/ReaderOptions.cs | 21 +- src/SharpCompress/Readers/ReaderProgress.cs | 31 +- src/SharpCompress/Readers/Tar/TarReader.cs | 2 +- src/SharpCompress/Readers/Zip/ZipReader.cs | 93 +- src/SharpCompress/Utility.cs | 772 +-- src/SharpCompress/Writers/AbstractWriter.cs | 81 +- src/SharpCompress/Writers/GZip/GZipWriter.cs | 69 +- .../Writers/GZip/GZipWriterOptions.cs | 28 +- src/SharpCompress/Writers/IWriter.cs | 13 +- .../Writers/IWriterExtensions.cs | 105 +- src/SharpCompress/Writers/IWriterFactory.cs | 14 +- src/SharpCompress/Writers/Tar/TarWriter.cs | 205 +- .../Writers/Tar/TarWriterOptions.cs | 31 +- src/SharpCompress/Writers/WriterFactory.cs | 31 +- src/SharpCompress/Writers/WriterOptions.cs | 23 +- .../Writers/Zip/ZipCentralDirectoryEntry.cs | 297 +- src/SharpCompress/Writers/Zip/ZipWriter.cs | 1033 ++-- .../Writers/Zip/ZipWriterEntryOptions.cs | 37 +- .../Writers/Zip/ZipWriterOptions.cs | 60 +- tests/SharpCompress.Test/ADCTest.cs | 239 +- tests/SharpCompress.Test/ArchiveTests.cs | 451 +- .../Filters/BranchExecTests.cs | 2453 +++++----- .../GZip/GZipArchiveTests.cs | 197 +- .../GZip/GZipReaderTests.cs | 51 +- .../GZip/GZipWriterTests.cs | 147 +- .../Mocks/FlushOnDisposeStream.cs | 115 +- .../Mocks/ForwardOnlyStream.cs | 95 +- tests/SharpCompress.Test/Mocks/TestStream.cs | 103 +- .../SharpCompress.Test/Rar/RarArchiveTests.cs | 1321 +++--- .../Rar/RarHeaderFactoryTest.cs | 107 +- .../SharpCompress.Test/Rar/RarReaderTests.cs | 719 ++- tests/SharpCompress.Test/ReaderTests.cs | 117 +- .../SevenZip/SevenZipArchiveTests.cs | 273 +- .../Streams/LzmaStreamTests.cs | 1035 ++-- .../Streams/RewindableStreamTest.cs | 153 +- .../Streams/ZlibBaseStreamTests.cs | 181 +- .../SharpCompress.Test/Tar/TarArchiveTests.cs | 2 +- .../SharpCompress.Test/Tar/TarReaderTests.cs | 2 +- .../SharpCompress.Test/Tar/TarWriterTests.cs | 143 +- tests/SharpCompress.Test/TestBase.cs | 405 +- tests/SharpCompress.Test/WriterTests.cs | 91 +- tests/SharpCompress.Test/Xz/Crc32Tests.cs | 41 +- tests/SharpCompress.Test/Xz/Crc64Tests.cs | 41 +- .../SharpCompress.Test/Xz/Filters/BCJTests.cs | 125 +- .../Xz/Filters/Lzma2Tests.cs | 2 +- tests/SharpCompress.Test/Xz/XZBlockTests.cs | 169 +- tests/SharpCompress.Test/Xz/XZHeaderTests.cs | 2 +- tests/SharpCompress.Test/Xz/XZIndexTests.cs | 2 +- tests/SharpCompress.Test/Xz/XZStreamTests.cs | 2 +- tests/SharpCompress.Test/Xz/XZTestsBase.cs | 2287 +++++---- tests/SharpCompress.Test/Zip/Zip64Tests.cs | 378 +- .../SharpCompress.Test/Zip/ZipArchiveTests.cs | 2 +- .../SharpCompress.Test/Zip/ZipReaderTests.cs | 720 ++- .../SharpCompress.Test/Zip/ZipWriterTests.cs | 131 +- 378 files changed, 59744 insertions(+), 60562 deletions(-) diff --git a/build/Program.cs b/build/Program.cs index 358082aa..000051dd 100644 --- a/build/Program.cs +++ b/build/Program.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.Runtime.InteropServices; diff --git a/src/SharpCompress/Algorithms/Adler32.cs b/src/SharpCompress/Algorithms/Adler32.cs index 0d4de7fa..e32893ac 100644 --- a/src/SharpCompress/Algorithms/Adler32.cs +++ b/src/SharpCompress/Algorithms/Adler32.cs @@ -15,101 +15,289 @@ using System.Runtime.Intrinsics.X86; #endif #pragma warning disable IDE0007 // Use implicit type -namespace SharpCompress.Algorithms +namespace SharpCompress.Algorithms; + +/// +/// Calculates the 32 bit Adler checksum of a given buffer according to +/// RFC 1950. ZLIB Compressed Data Format Specification version 3.3) +/// +internal static class Adler32 // From https://github.com/SixLabors/ImageSharp/blob/main/src/ImageSharp/Compression/Zlib/Adler32.cs { /// - /// Calculates the 32 bit Adler checksum of a given buffer according to - /// RFC 1950. ZLIB Compressed Data Format Specification version 3.3) + /// Global inlining options. Helps temporarily disable inlining for better profiler output. /// - internal static class Adler32 // From https://github.com/SixLabors/ImageSharp/blob/main/src/ImageSharp/Compression/Zlib/Adler32.cs + private static class InliningOptions // From https://github.com/SixLabors/ImageSharp/blob/main/src/ImageSharp/Common/Helpers/InliningOptions.cs { /// - /// Global inlining options. Helps temporarily disable inlining for better profiler output. + /// regardless of the build conditions. /// - private static class InliningOptions // From https://github.com/SixLabors/ImageSharp/blob/main/src/ImageSharp/Common/Helpers/InliningOptions.cs - { - /// - /// regardless of the build conditions. - /// - public const MethodImplOptions AlwaysInline = MethodImplOptions.AggressiveInlining; + public const MethodImplOptions AlwaysInline = MethodImplOptions.AggressiveInlining; #if PROFILING - public const MethodImplOptions HotPath = MethodImplOptions.NoInlining; - public const MethodImplOptions ShortMethod = MethodImplOptions.NoInlining; + public const MethodImplOptions HotPath = MethodImplOptions.NoInlining; + public const MethodImplOptions ShortMethod = MethodImplOptions.NoInlining; #else #if SUPPORTS_HOTPATH - public const MethodImplOptions HotPath = MethodImplOptions.AggressiveOptimization; + public const MethodImplOptions HotPath = MethodImplOptions.AggressiveOptimization; #else - public const MethodImplOptions HotPath = MethodImplOptions.AggressiveInlining; + public const MethodImplOptions HotPath = MethodImplOptions.AggressiveInlining; #endif - public const MethodImplOptions ShortMethod = MethodImplOptions.AggressiveInlining; + public const MethodImplOptions ShortMethod = MethodImplOptions.AggressiveInlining; #endif - public const MethodImplOptions ColdPath = MethodImplOptions.NoInlining; - } + public const MethodImplOptions ColdPath = MethodImplOptions.NoInlining; + } #if SUPPORTS_RUNTIME_INTRINSICS + /// + /// Provides optimized static methods for trigonometric, logarithmic, + /// and other common mathematical functions. + /// + private static class Numerics // From https://github.com/SixLabors/ImageSharp/blob/main/src/ImageSharp/Common/Helpers/Numerics.cs + { /// - /// Provides optimized static methods for trigonometric, logarithmic, - /// and other common mathematical functions. + /// Reduces elements of the vector into one sum. /// - private static class Numerics // From https://github.com/SixLabors/ImageSharp/blob/main/src/ImageSharp/Common/Helpers/Numerics.cs + /// The accumulator to reduce. + /// The sum of all elements. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int ReduceSum(Vector256 accumulator) { - /// - /// Reduces elements of the vector into one sum. - /// - /// The accumulator to reduce. - /// The sum of all elements. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int ReduceSum(Vector256 accumulator) - { - // Add upper lane to lower lane. - Vector128 vsum = Sse2.Add(accumulator.GetLower(), accumulator.GetUpper()); + // Add upper lane to lower lane. + Vector128 vsum = Sse2.Add(accumulator.GetLower(), accumulator.GetUpper()); - // Add odd to even. - vsum = Sse2.Add(vsum, Sse2.Shuffle(vsum, 0b_11_11_01_01)); + // Add odd to even. + vsum = Sse2.Add(vsum, Sse2.Shuffle(vsum, 0b_11_11_01_01)); - // Add high to low. - vsum = Sse2.Add(vsum, Sse2.Shuffle(vsum, 0b_11_10_11_10)); + // Add high to low. + vsum = Sse2.Add(vsum, Sse2.Shuffle(vsum, 0b_11_10_11_10)); - return Sse2.ConvertToInt32(vsum); - } - - /// - /// Reduces even elements of the vector into one sum. - /// - /// The accumulator to reduce. - /// The sum of even elements. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int EvenReduceSum(Vector256 accumulator) - { - Vector128 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 - return Sse2.ConvertToInt32(vsum); - } + return Sse2.ConvertToInt32(vsum); } -#endif /// - /// The default initial seed value of a Adler32 checksum calculation. + /// Reduces even elements of the vector into one sum. /// - public const uint SeedValue = 1U; + /// The accumulator to reduce. + /// The sum of even elements. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int EvenReduceSum(Vector256 accumulator) + { + Vector128 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 - // Largest prime smaller than 65536 - private const uint BASE = 65521; + // Vector128.ToScalar() isn't optimized pre-net5.0 https://github.com/dotnet/runtime/pull/37882 + return Sse2.ConvertToInt32(vsum); + } + } +#endif - // NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 - private const uint NMAX = 5552; + /// + /// The default initial seed value of a Adler32 checksum calculation. + /// + public const uint SeedValue = 1U; + + // Largest prime smaller than 65536 + private const uint BASE = 65521; + + // NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 + private const uint NMAX = 5552; #if SUPPORTS_RUNTIME_INTRINSICS - private const int MinBufferSize = 64; + private const int MinBufferSize = 64; - private const int BlockSize = 1 << 5; + private const int BlockSize = 1 << 5; - // The C# compiler emits this as a compile-time constant embedded in the PE file. - private static ReadOnlySpan Tap1Tap2 => - new byte[] + // The C# compiler emits this as a compile-time constant embedded in the PE file. + private static ReadOnlySpan Tap1Tap2 => + new byte[] + { + 32, + 31, + 30, + 29, + 28, + 27, + 26, + 25, + 24, + 23, + 22, + 21, + 20, + 19, + 18, + 17, // tap1 + 16, + 15, + 14, + 13, + 12, + 11, + 10, + 9, + 8, + 7, + 6, + 5, + 4, + 3, + 2, + 1 // tap2 + }; +#endif + + /// + /// Calculates the Adler32 checksum with the bytes taken from the span. + /// + /// The readonly span of bytes. + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public static uint Calculate(ReadOnlySpan buffer) => Calculate(SeedValue, buffer); + + /// + /// Calculates the Adler32 checksum with the bytes taken from the span and seed. + /// + /// The input Adler32 value. + /// The readonly span of bytes. + /// The . + [MethodImpl(InliningOptions.HotPath | InliningOptions.ShortMethod)] + public static uint Calculate(uint adler, ReadOnlySpan buffer) + { + if (buffer.IsEmpty) + { + return adler; + } + +#if SUPPORTS_RUNTIME_INTRINSICS + if (Avx2.IsSupported && buffer.Length >= MinBufferSize) + { + return CalculateAvx2(adler, buffer); + } + + if (Ssse3.IsSupported && buffer.Length >= MinBufferSize) + { + return CalculateSse(adler, buffer); + } + + return CalculateScalar(adler, buffer); +#else + return CalculateScalar(adler, buffer); +#endif + } + + // Based on https://github.com/chromium/chromium/blob/master/third_party/zlib/adler32_simd.c +#if SUPPORTS_RUNTIME_INTRINSICS + [MethodImpl(InliningOptions.HotPath | InliningOptions.ShortMethod)] + private static unsafe uint CalculateSse(uint adler, ReadOnlySpan buffer) + { + uint s1 = adler & 0xFFFF; + uint s2 = (adler >> 16) & 0xFFFF; + + // Process the data in blocks. + uint length = (uint)buffer.Length; + uint blocks = length / BlockSize; + length -= blocks * BlockSize; + + fixed (byte* bufferPtr = &MemoryMarshal.GetReference(buffer)) + { + fixed (byte* tapPtr = &MemoryMarshal.GetReference(Tap1Tap2)) { + byte* 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 ones = Vector128.Create((short)1); + + while (blocks > 0) + { + uint n = NMAX / BlockSize; /* The NMAX constraint. */ + if (n > blocks) + { + n = blocks; + } + + blocks -= n; + + // 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; + + do + { + // Load 32 input bytes. + Vector128 bytes1 = Sse3.LoadDquVector128(localBufferPtr); + Vector128 bytes2 = Sse3.LoadDquVector128(localBufferPtr + 0x10); + + // Add previous block byte sum to v_ps. + v_ps = Sse2.Add(v_ps, v_s1); + + // 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); + 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); + v_s2 = Sse2.Add(v_s2, Sse2.MultiplyAddAdjacent(mad2, ones).AsUInt32()); + + localBufferPtr += BlockSize; + } while (--n > 0); + + v_s2 = Sse2.Add(v_s2, Sse2.ShiftLeftLogical(v_ps, 5)); + + // Sum epi32 ints v_s1(s2) and accumulate in s1(s2). + const byte S2301 = 0b1011_0001; // A B C D -> B A D C + const byte S1032 = 0b0100_1110; // A B C D -> C D A B + + v_s1 = Sse2.Add(v_s1, Sse2.Shuffle(v_s1, S1032)); + + s1 += v_s1.ToScalar(); + + v_s2 = Sse2.Add(v_s2, Sse2.Shuffle(v_s2, S2301)); + v_s2 = Sse2.Add(v_s2, Sse2.Shuffle(v_s2, S1032)); + + s2 = v_s2.ToScalar(); + + // Reduce. + s1 %= BASE; + s2 %= BASE; + } + + if (length > 0) + { + HandleLeftOver(localBufferPtr, length, ref s1, ref s2); + } + + return s1 | (s2 << 16); + } + } + } + + // Based on: https://github.com/zlib-ng/zlib-ng/blob/develop/arch/x86/adler32_avx2.c + [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; + + fixed (byte* bufferPtr = &MemoryMarshal.GetReference(buffer)) + { + byte* localBufferPtr = bufferPtr; + + Vector256 zero = Vector256.Zero; + var dot3v = Vector256.Create((short)1); + var dot2v = Vector256.Create( 32, 31, 30, @@ -125,7 +313,7 @@ namespace SharpCompress.Algorithms 20, 19, 18, - 17, // tap1 + 17, 16, 15, 14, @@ -141,353 +329,164 @@ namespace SharpCompress.Algorithms 4, 3, 2, - 1 // tap2 - }; -#endif + 1 + ); - /// - /// Calculates the Adler32 checksum with the bytes taken from the span. - /// - /// The readonly span of bytes. - /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public static uint Calculate(ReadOnlySpan buffer) => Calculate(SeedValue, buffer); + // Process n blocks of data. At most NMAX data bytes can be + // processed before s2 must be reduced modulo BASE. + var vs1 = Vector256.CreateScalar(s1); + var vs2 = Vector256.CreateScalar(s2); - /// - /// Calculates the Adler32 checksum with the bytes taken from the span and seed. - /// - /// The input Adler32 value. - /// The readonly span of bytes. - /// The . - [MethodImpl(InliningOptions.HotPath | InliningOptions.ShortMethod)] - public static uint Calculate(uint adler, ReadOnlySpan buffer) - { - if (buffer.IsEmpty) + while (length >= 32) { - return adler; - } + int k = length < NMAX ? (int)length : (int)NMAX; + k -= k % 32; + length -= (uint)k; -#if SUPPORTS_RUNTIME_INTRINSICS - if (Avx2.IsSupported && buffer.Length >= MinBufferSize) - { - return CalculateAvx2(adler, buffer); - } + Vector256 vs10 = vs1; + Vector256 vs3 = Vector256.Zero; - if (Ssse3.IsSupported && buffer.Length >= MinBufferSize) - { - return CalculateSse(adler, buffer); - } - - return CalculateScalar(adler, buffer); -#else - return CalculateScalar(adler, buffer); -#endif - } - - // Based on https://github.com/chromium/chromium/blob/master/third_party/zlib/adler32_simd.c -#if SUPPORTS_RUNTIME_INTRINSICS - [MethodImpl(InliningOptions.HotPath | InliningOptions.ShortMethod)] - private static unsafe uint CalculateSse(uint adler, ReadOnlySpan buffer) - { - uint s1 = adler & 0xFFFF; - uint s2 = (adler >> 16) & 0xFFFF; - - // Process the data in blocks. - uint length = (uint)buffer.Length; - uint blocks = length / BlockSize; - length -= blocks * BlockSize; - - fixed (byte* bufferPtr = &MemoryMarshal.GetReference(buffer)) - { - fixed (byte* tapPtr = &MemoryMarshal.GetReference(Tap1Tap2)) + while (k >= 32) { - byte* localBufferPtr = bufferPtr; + // Load 32 input bytes. + Vector256 block = Avx.LoadVector256(localBufferPtr); - // _mm_setr_epi8 on x86 - Vector128 tap1 = Sse2.LoadVector128((sbyte*)tapPtr); - Vector128 tap2 = Sse2.LoadVector128((sbyte*)(tapPtr + 0x10)); - Vector128 zero = Vector128.Zero; - var ones = Vector128.Create((short)1); + // Sum of abs diff, resulting in 2 x int32's + Vector256 vs1sad = Avx2.SumAbsoluteDifferences(block, zero); - while (blocks > 0) - { - uint n = NMAX / BlockSize; /* The NMAX constraint. */ - if (n > blocks) - { - n = blocks; - } + vs1 = Avx2.Add(vs1, vs1sad.AsUInt32()); + vs3 = Avx2.Add(vs3, vs10); - blocks -= n; + // sum 32 uint8s to 16 shorts. + Vector256 vshortsum2 = Avx2.MultiplyAddAdjacent(block, dot2v); - // 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; + // sum 16 shorts to 8 uint32s. + Vector256 vsum2 = Avx2.MultiplyAddAdjacent(vshortsum2, dot3v); - do - { - // Load 32 input bytes. - Vector128 bytes1 = Sse3.LoadDquVector128(localBufferPtr); - Vector128 bytes2 = Sse3.LoadDquVector128(localBufferPtr + 0x10); + vs2 = Avx2.Add(vsum2.AsUInt32(), vs2); + vs10 = vs1; - // Add previous block byte sum to v_ps. - v_ps = Sse2.Add(v_ps, v_s1); - - // 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); - 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); - v_s2 = Sse2.Add(v_s2, Sse2.MultiplyAddAdjacent(mad2, ones).AsUInt32()); - - localBufferPtr += BlockSize; - } while (--n > 0); - - v_s2 = Sse2.Add(v_s2, Sse2.ShiftLeftLogical(v_ps, 5)); - - // Sum epi32 ints v_s1(s2) and accumulate in s1(s2). - const byte S2301 = 0b1011_0001; // A B C D -> B A D C - const byte S1032 = 0b0100_1110; // A B C D -> C D A B - - v_s1 = Sse2.Add(v_s1, Sse2.Shuffle(v_s1, S1032)); - - s1 += v_s1.ToScalar(); - - v_s2 = Sse2.Add(v_s2, Sse2.Shuffle(v_s2, S2301)); - v_s2 = Sse2.Add(v_s2, Sse2.Shuffle(v_s2, S1032)); - - s2 = v_s2.ToScalar(); - - // Reduce. - s1 %= BASE; - s2 %= BASE; - } - - if (length > 0) - { - HandleLeftOver(localBufferPtr, length, ref s1, ref s2); - } - - return s1 | (s2 << 16); + localBufferPtr += BlockSize; + k -= 32; } + + // Defer the multiplication with 32 to outside of the loop. + vs3 = Avx2.ShiftLeftLogical(vs3, 5); + vs2 = Avx2.Add(vs2, vs3); + + s1 = (uint)Numerics.EvenReduceSum(vs1.AsInt32()); + s2 = (uint)Numerics.ReduceSum(vs2.AsInt32()); + + s1 %= BASE; + s2 %= BASE; + + vs1 = Vector256.CreateScalar(s1); + vs2 = Vector256.CreateScalar(s2); } + + if (length > 0) + { + HandleLeftOver(localBufferPtr, length, ref s1, ref s2); + } + + return s1 | (s2 << 16); + } + } + + private static unsafe void HandleLeftOver( + byte* localBufferPtr, + uint length, + ref uint s1, + ref uint s2 + ) + { + if (length >= 16) + { + s2 += s1 += localBufferPtr[0]; + s2 += s1 += localBufferPtr[1]; + s2 += s1 += localBufferPtr[2]; + s2 += s1 += localBufferPtr[3]; + s2 += s1 += localBufferPtr[4]; + s2 += s1 += localBufferPtr[5]; + s2 += s1 += localBufferPtr[6]; + s2 += s1 += localBufferPtr[7]; + s2 += s1 += localBufferPtr[8]; + s2 += s1 += localBufferPtr[9]; + s2 += s1 += localBufferPtr[10]; + s2 += s1 += localBufferPtr[11]; + s2 += s1 += localBufferPtr[12]; + s2 += s1 += localBufferPtr[13]; + s2 += s1 += localBufferPtr[14]; + s2 += s1 += localBufferPtr[15]; + + localBufferPtr += 16; + length -= 16; } - // Based on: https://github.com/zlib-ng/zlib-ng/blob/develop/arch/x86/adler32_avx2.c - [MethodImpl(InliningOptions.HotPath | InliningOptions.ShortMethod)] - public static unsafe uint CalculateAvx2(uint adler, ReadOnlySpan buffer) + while (length-- > 0) { - uint s1 = adler & 0xFFFF; - uint s2 = (adler >> 16) & 0xFFFF; + s2 += s1 += *localBufferPtr++; + } + + if (s1 >= BASE) + { + s1 -= BASE; + } + + s2 %= BASE; + } +#endif + + [MethodImpl(InliningOptions.HotPath | InliningOptions.ShortMethod)] + private static unsafe uint CalculateScalar(uint adler, ReadOnlySpan buffer) + { + uint s1 = adler & 0xFFFF; + uint s2 = (adler >> 16) & 0xFFFF; + uint k; + + fixed (byte* bufferPtr = buffer) + { + var localBufferPtr = bufferPtr; uint length = (uint)buffer.Length; - fixed (byte* bufferPtr = &MemoryMarshal.GetReference(buffer)) + while (length > 0) { - byte* localBufferPtr = bufferPtr; + k = length < NMAX ? length : NMAX; + length -= k; - Vector256 zero = Vector256.Zero; - var dot3v = Vector256.Create((short)1); - var dot2v = Vector256.Create( - 32, - 31, - 30, - 29, - 28, - 27, - 26, - 25, - 24, - 23, - 22, - 21, - 20, - 19, - 18, - 17, - 16, - 15, - 14, - 13, - 12, - 11, - 10, - 9, - 8, - 7, - 6, - 5, - 4, - 3, - 2, - 1 - ); - - // Process n blocks of data. At most NMAX data bytes can be - // processed before s2 must be reduced modulo BASE. - var vs1 = Vector256.CreateScalar(s1); - var vs2 = Vector256.CreateScalar(s2); - - while (length >= 32) + while (k >= 16) { - int k = length < NMAX ? (int)length : (int)NMAX; - k -= k % 32; - length -= (uint)k; + s2 += s1 += localBufferPtr[0]; + s2 += s1 += localBufferPtr[1]; + s2 += s1 += localBufferPtr[2]; + s2 += s1 += localBufferPtr[3]; + s2 += s1 += localBufferPtr[4]; + s2 += s1 += localBufferPtr[5]; + s2 += s1 += localBufferPtr[6]; + s2 += s1 += localBufferPtr[7]; + s2 += s1 += localBufferPtr[8]; + s2 += s1 += localBufferPtr[9]; + s2 += s1 += localBufferPtr[10]; + s2 += s1 += localBufferPtr[11]; + s2 += s1 += localBufferPtr[12]; + s2 += s1 += localBufferPtr[13]; + s2 += s1 += localBufferPtr[14]; + s2 += s1 += localBufferPtr[15]; - Vector256 vs10 = vs1; - Vector256 vs3 = Vector256.Zero; - - while (k >= 32) - { - // Load 32 input bytes. - Vector256 block = Avx.LoadVector256(localBufferPtr); - - // Sum of abs diff, resulting in 2 x int32's - Vector256 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); - - // sum 16 shorts to 8 uint32s. - Vector256 vsum2 = Avx2.MultiplyAddAdjacent(vshortsum2, dot3v); - - vs2 = Avx2.Add(vsum2.AsUInt32(), vs2); - vs10 = vs1; - - localBufferPtr += BlockSize; - k -= 32; - } - - // Defer the multiplication with 32 to outside of the loop. - vs3 = Avx2.ShiftLeftLogical(vs3, 5); - vs2 = Avx2.Add(vs2, vs3); - - s1 = (uint)Numerics.EvenReduceSum(vs1.AsInt32()); - s2 = (uint)Numerics.ReduceSum(vs2.AsInt32()); - - s1 %= BASE; - s2 %= BASE; - - vs1 = Vector256.CreateScalar(s1); - vs2 = Vector256.CreateScalar(s2); + localBufferPtr += 16; + k -= 16; } - if (length > 0) + while (k-- > 0) { - HandleLeftOver(localBufferPtr, length, ref s1, ref s2); + s2 += s1 += *localBufferPtr++; } - return s1 | (s2 << 16); - } - } - - private static unsafe void HandleLeftOver( - byte* localBufferPtr, - uint length, - ref uint s1, - ref uint s2 - ) - { - if (length >= 16) - { - s2 += s1 += localBufferPtr[0]; - s2 += s1 += localBufferPtr[1]; - s2 += s1 += localBufferPtr[2]; - s2 += s1 += localBufferPtr[3]; - s2 += s1 += localBufferPtr[4]; - s2 += s1 += localBufferPtr[5]; - s2 += s1 += localBufferPtr[6]; - s2 += s1 += localBufferPtr[7]; - s2 += s1 += localBufferPtr[8]; - s2 += s1 += localBufferPtr[9]; - s2 += s1 += localBufferPtr[10]; - s2 += s1 += localBufferPtr[11]; - s2 += s1 += localBufferPtr[12]; - s2 += s1 += localBufferPtr[13]; - s2 += s1 += localBufferPtr[14]; - s2 += s1 += localBufferPtr[15]; - - localBufferPtr += 16; - length -= 16; + s1 %= BASE; + s2 %= BASE; } - while (length-- > 0) - { - s2 += s1 += *localBufferPtr++; - } - - if (s1 >= BASE) - { - s1 -= BASE; - } - - s2 %= BASE; - } -#endif - - [MethodImpl(InliningOptions.HotPath | InliningOptions.ShortMethod)] - private static unsafe uint CalculateScalar(uint adler, ReadOnlySpan buffer) - { - uint s1 = adler & 0xFFFF; - uint s2 = (adler >> 16) & 0xFFFF; - uint k; - - fixed (byte* bufferPtr = buffer) - { - var localBufferPtr = bufferPtr; - uint length = (uint)buffer.Length; - - while (length > 0) - { - k = length < NMAX ? length : NMAX; - length -= k; - - while (k >= 16) - { - s2 += s1 += localBufferPtr[0]; - s2 += s1 += localBufferPtr[1]; - s2 += s1 += localBufferPtr[2]; - s2 += s1 += localBufferPtr[3]; - s2 += s1 += localBufferPtr[4]; - s2 += s1 += localBufferPtr[5]; - s2 += s1 += localBufferPtr[6]; - s2 += s1 += localBufferPtr[7]; - s2 += s1 += localBufferPtr[8]; - s2 += s1 += localBufferPtr[9]; - s2 += s1 += localBufferPtr[10]; - s2 += s1 += localBufferPtr[11]; - s2 += s1 += localBufferPtr[12]; - s2 += s1 += localBufferPtr[13]; - s2 += s1 += localBufferPtr[14]; - s2 += s1 += localBufferPtr[15]; - - localBufferPtr += 16; - k -= 16; - } - - while (k-- > 0) - { - s2 += s1 += *localBufferPtr++; - } - - s1 %= BASE; - s2 %= BASE; - } - - return (s2 << 16) | s1; - } + return (s2 << 16) | s1; } } } diff --git a/src/SharpCompress/Archives/AbstractArchive.cs b/src/SharpCompress/Archives/AbstractArchive.cs index 16b07864..d747189e 100644 --- a/src/SharpCompress/Archives/AbstractArchive.cs +++ b/src/SharpCompress/Archives/AbstractArchive.cs @@ -6,180 +6,179 @@ using SharpCompress.Common; using SharpCompress.IO; using SharpCompress.Readers; -namespace SharpCompress.Archives +namespace SharpCompress.Archives; + +public abstract class AbstractArchive : IArchive, IArchiveExtractionListener + where TEntry : IArchiveEntry + where TVolume : IVolume { - public abstract class AbstractArchive : IArchive, IArchiveExtractionListener - where TEntry : IArchiveEntry - where TVolume : IVolume + private readonly LazyReadOnlyCollection lazyVolumes; + private readonly LazyReadOnlyCollection lazyEntries; + + 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) { - private readonly LazyReadOnlyCollection lazyVolumes; - private readonly LazyReadOnlyCollection lazyEntries; - - 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) - { - Type = type; - ReaderOptions = srcStream.ReaderOptions; - SrcStream = srcStream; - lazyVolumes = new LazyReadOnlyCollection(LoadVolumes(SrcStream)); - lazyEntries = new LazyReadOnlyCollection(LoadEntries(Volumes)); - } + Type = type; + ReaderOptions = srcStream.ReaderOptions; + SrcStream = srcStream; + lazyVolumes = new LazyReadOnlyCollection(LoadVolumes(SrcStream)); + lazyEntries = new LazyReadOnlyCollection(LoadEntries(Volumes)); + } #nullable disable - internal AbstractArchive(ArchiveType type) - { - Type = type; - lazyVolumes = new LazyReadOnlyCollection(Enumerable.Empty()); - lazyEntries = new LazyReadOnlyCollection(Enumerable.Empty()); - } + internal AbstractArchive(ArchiveType type) + { + Type = type; + lazyVolumes = new LazyReadOnlyCollection(Enumerable.Empty()); + lazyEntries = new LazyReadOnlyCollection(Enumerable.Empty()); + } #nullable enable - public ArchiveType Type { get; } + public ArchiveType Type { get; } - void IArchiveExtractionListener.FireEntryExtractionBegin(IArchiveEntry entry) + void IArchiveExtractionListener.FireEntryExtractionBegin(IArchiveEntry entry) + { + EntryExtractionBegin?.Invoke( + this, + new ArchiveExtractionEventArgs(entry) + ); + } + + void IArchiveExtractionListener.FireEntryExtractionEnd(IArchiveEntry entry) + { + EntryExtractionEnd?.Invoke(this, new ArchiveExtractionEventArgs(entry)); + } + + private static Stream CheckStreams(Stream stream) + { + if (!stream.CanSeek || !stream.CanRead) { - EntryExtractionBegin?.Invoke( - this, - new ArchiveExtractionEventArgs(entry) - ); + throw new ArgumentException("Archive streams must be Readable and Seekable"); } + return stream; + } - void IArchiveExtractionListener.FireEntryExtractionEnd(IArchiveEntry entry) + /// + /// Returns an ReadOnlyCollection of all the RarArchiveEntries across the one or many parts of the RarArchive. + /// + 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; + + /// + /// The total size of the files compressed in the archive. + /// + public virtual long TotalSize => + Entries.Aggregate(0L, (total, cf) => total + cf.CompressedSize); + + /// + /// The total size of the files as uncompressed in the archive. + /// + public virtual long TotalUncompressSize => + Entries.Aggregate(0L, (total, cf) => total + cf.Size); + + protected abstract IEnumerable LoadVolumes(SourceStream srcStream); + protected abstract IEnumerable LoadEntries(IEnumerable volumes); + + IEnumerable IArchive.Entries => Entries.Cast(); + + IEnumerable IArchive.Volumes => lazyVolumes.Cast(); + + public virtual void Dispose() + { + if (!disposed) { - EntryExtractionEnd?.Invoke(this, new ArchiveExtractionEventArgs(entry)); + lazyVolumes.ForEach(v => v.Dispose()); + lazyEntries.GetLoaded().Cast().ForEach(x => x.Close()); + SrcStream?.Dispose(); + + disposed = true; } + } - private static Stream CheckStreams(Stream stream) - { - if (!stream.CanSeek || !stream.CanRead) - { - throw new ArgumentException("Archive streams must be Readable and Seekable"); - } - return stream; - } + void IArchiveExtractionListener.EnsureEntriesLoaded() + { + lazyEntries.EnsureFullyLoaded(); + lazyVolumes.EnsureFullyLoaded(); + } - /// - /// Returns an ReadOnlyCollection of all the RarArchiveEntries across the one or many parts of the RarArchive. - /// - public virtual ICollection Entries => lazyEntries; + void IExtractionListener.FireCompressedBytesRead( + long currentPartCompressedBytes, + long compressedReadBytes + ) + { + CompressedBytesRead?.Invoke( + this, + new CompressedBytesReadEventArgs( + currentFilePartCompressedBytesRead: currentPartCompressedBytes, + compressedBytesRead: compressedReadBytes + ) + ); + } - /// - /// Returns an ReadOnlyCollection of all the RarArchiveVolumes across the one or many parts of the RarArchive. - /// - public ICollection Volumes => lazyVolumes; + void IExtractionListener.FireFilePartExtractionBegin( + string name, + long size, + long compressedSize + ) + { + FilePartExtractionBegin?.Invoke( + this, + new FilePartExtractionBeginEventArgs( + compressedSize: compressedSize, + size: size, + name: name + ) + ); + } - /// - /// The total size of the files compressed in the archive. - /// - public virtual long TotalSize => - Entries.Aggregate(0L, (total, cf) => total + cf.CompressedSize); + /// + /// Use this method to extract all entries in an archive in order. + /// This is primarily for SOLID Rar Archives or 7Zip Archives as they need to be + /// extracted sequentially for the best performance. + /// + /// This method will load all entry information from the archive. + /// + /// WARNING: this will reuse the underlying stream for the archive. Errors may + /// occur if this is used at the same time as other extraction methods on this instance. + /// + /// + public IReader ExtractAllEntries() + { + ((IArchiveExtractionListener)this).EnsureEntriesLoaded(); + return CreateReaderForSolidExtraction(); + } - /// - /// The total size of the files as uncompressed in the archive. - /// - public virtual long TotalUncompressSize => - Entries.Aggregate(0L, (total, cf) => total + cf.Size); + protected abstract IReader CreateReaderForSolidExtraction(); - protected abstract IEnumerable LoadVolumes(SourceStream srcStream); - protected abstract IEnumerable LoadEntries(IEnumerable volumes); + /// + /// Archive is SOLID (this means the Archive saved bytes by reusing information which helps for archives containing many small files). + /// + public virtual bool IsSolid => false; - IEnumerable IArchive.Entries => Entries.Cast(); - - IEnumerable IArchive.Volumes => lazyVolumes.Cast(); - - public virtual void Dispose() - { - if (!disposed) - { - lazyVolumes.ForEach(v => v.Dispose()); - lazyEntries.GetLoaded().Cast().ForEach(x => x.Close()); - if (SrcStream != null) - SrcStream.Dispose(); - disposed = true; - } - } - - void IArchiveExtractionListener.EnsureEntriesLoaded() - { - lazyEntries.EnsureFullyLoaded(); - lazyVolumes.EnsureFullyLoaded(); - } - - void IExtractionListener.FireCompressedBytesRead( - long currentPartCompressedBytes, - long compressedReadBytes - ) - { - CompressedBytesRead?.Invoke( - this, - new CompressedBytesReadEventArgs( - currentFilePartCompressedBytesRead: currentPartCompressedBytes, - compressedBytesRead: compressedReadBytes - ) - ); - } - - void IExtractionListener.FireFilePartExtractionBegin( - string name, - long size, - long compressedSize - ) - { - FilePartExtractionBegin?.Invoke( - this, - new FilePartExtractionBeginEventArgs( - compressedSize: compressedSize, - size: size, - name: name - ) - ); - } - - /// - /// Use this method to extract all entries in an archive in order. - /// This is primarily for SOLID Rar Archives or 7Zip Archives as they need to be - /// extracted sequentially for the best performance. - /// - /// This method will load all entry information from the archive. - /// - /// WARNING: this will reuse the underlying stream for the archive. Errors may - /// occur if this is used at the same time as other extraction methods on this instance. - /// - /// - public IReader ExtractAllEntries() + /// + /// The archive can find all the parts of the archive needed to fully extract the archive. This forces the parsing of the entire archive. + /// + public bool IsComplete + { + get { ((IArchiveExtractionListener)this).EnsureEntriesLoaded(); - return CreateReaderForSolidExtraction(); - } - - protected abstract IReader CreateReaderForSolidExtraction(); - - /// - /// Archive is SOLID (this means the Archive saved bytes by reusing information which helps for archives containing many small files). - /// - public virtual bool IsSolid => false; - - /// - /// The archive can find all the parts of the archive needed to fully extract the archive. This forces the parsing of the entire archive. - /// - public bool IsComplete - { - get - { - ((IArchiveExtractionListener)this).EnsureEntriesLoaded(); - return Entries.All(x => x.IsComplete); - } + return Entries.All(x => x.IsComplete); } } } diff --git a/src/SharpCompress/Archives/AbstractWritableArchive.cs b/src/SharpCompress/Archives/AbstractWritableArchive.cs index fc877cbd..146c8338 100644 --- a/src/SharpCompress/Archives/AbstractWritableArchive.cs +++ b/src/SharpCompress/Archives/AbstractWritableArchive.cs @@ -4,193 +4,191 @@ using System.IO; using System.Linq; using SharpCompress.Common; using SharpCompress.IO; -using SharpCompress.Readers; using SharpCompress.Writers; -namespace SharpCompress.Archives +namespace SharpCompress.Archives; + +public abstract class AbstractWritableArchive + : AbstractArchive, + IWritableArchive + where TEntry : IArchiveEntry + where TVolume : IVolume { - public abstract class AbstractWritableArchive - : AbstractArchive, - IWritableArchive - where TEntry : IArchiveEntry - where TVolume : IVolume + private class RebuildPauseDisposable : IDisposable { - private class RebuildPauseDisposable : IDisposable + private readonly AbstractWritableArchive archive; + + public RebuildPauseDisposable(AbstractWritableArchive archive) { - private readonly AbstractWritableArchive archive; - - public RebuildPauseDisposable(AbstractWritableArchive archive) - { - this.archive = archive; - archive.pauseRebuilding = true; - } - - public void Dispose() - { - archive.pauseRebuilding = false; - archive.RebuildModifiedCollection(); - } + this.archive = archive; + archive.pauseRebuilding = true; } - private readonly List newEntries = new List(); - private readonly List removedEntries = new List(); - - private readonly List modifiedEntries = new List(); - private bool hasModifications; - private bool pauseRebuilding; - - internal AbstractWritableArchive(ArchiveType type) : base(type) { } - - internal AbstractWritableArchive(ArchiveType type, SourceStream srcStream) - : base(type, srcStream) { } - - public override ICollection Entries + public void Dispose() { - get - { - if (hasModifications) - { - return modifiedEntries; - } - return base.Entries; - } - } - - public IDisposable PauseEntryRebuilding() - { - return new RebuildPauseDisposable(this); - } - - private void RebuildModifiedCollection() - { - if (pauseRebuilding) - { - return; - } - hasModifications = true; - newEntries.RemoveAll(v => removedEntries.Contains(v)); - modifiedEntries.Clear(); - modifiedEntries.AddRange(OldEntries.Concat(newEntries)); - } - - private IEnumerable OldEntries - { - get { return base.Entries.Where(x => !removedEntries.Contains(x)); } - } - - public void RemoveEntry(TEntry entry) - { - if (!removedEntries.Contains(entry)) - { - removedEntries.Add(entry); - RebuildModifiedCollection(); - } - } - - void IWritableArchive.RemoveEntry(IArchiveEntry entry) - { - RemoveEntry((TEntry)entry); - } - - public TEntry AddEntry(string key, Stream source, long size = 0, DateTime? modified = null) - { - return AddEntry(key, source, false, size, modified); - } - - IArchiveEntry IWritableArchive.AddEntry( - string key, - Stream source, - bool closeStream, - long size, - DateTime? modified - ) - { - return AddEntry(key, source, closeStream, size, modified); - } - - public TEntry AddEntry( - string key, - Stream source, - bool closeStream, - long size = 0, - DateTime? modified = null - ) - { - if (key.Length > 0 && key[0] is '/' or '\\') - { - key = key.Substring(1); - } - if (DoesKeyMatchExisting(key)) - { - throw new ArchiveException("Cannot add entry with duplicate key: " + key); - } - var entry = CreateEntry(key, source, size, modified, closeStream); - newEntries.Add(entry); - RebuildModifiedCollection(); - return entry; - } - - private bool DoesKeyMatchExisting(string key) - { - foreach (var path in Entries.Select(x => x.Key)) - { - var p = path.Replace('/', '\\'); - if (p.Length > 0 && p[0] == '\\') - { - p = p.Substring(1); - } - return string.Equals(p, key, StringComparison.OrdinalIgnoreCase); - } - return false; - } - - public void SaveTo(Stream stream, WriterOptions options) - { - //reset streams of new entries - newEntries - .Cast() - .ForEach(x => x.Stream.Seek(0, SeekOrigin.Begin)); - SaveTo(stream, options, OldEntries, newEntries); - } - - protected TEntry CreateEntry( - string key, - Stream source, - long size, - DateTime? modified, - bool closeStream - ) - { - if (!source.CanRead || !source.CanSeek) - { - throw new ArgumentException( - "Streams must be readable and seekable to use the Writing Archive API" - ); - } - return CreateEntryInternal(key, source, size, modified, closeStream); - } - - protected abstract TEntry CreateEntryInternal( - string key, - Stream source, - long size, - DateTime? modified, - bool closeStream - ); - - protected abstract void SaveTo( - Stream stream, - WriterOptions options, - IEnumerable oldEntries, - IEnumerable newEntries - ); - - public override void Dispose() - { - base.Dispose(); - newEntries.Cast().ForEach(x => x.Close()); - removedEntries.Cast().ForEach(x => x.Close()); - modifiedEntries.Cast().ForEach(x => x.Close()); + archive.pauseRebuilding = false; + archive.RebuildModifiedCollection(); } } + + private readonly List newEntries = new List(); + private readonly List removedEntries = new List(); + + private readonly List modifiedEntries = new List(); + private bool hasModifications; + private bool pauseRebuilding; + + internal AbstractWritableArchive(ArchiveType type) : base(type) { } + + internal AbstractWritableArchive(ArchiveType type, SourceStream srcStream) + : base(type, srcStream) { } + + public override ICollection Entries + { + get + { + if (hasModifications) + { + return modifiedEntries; + } + return base.Entries; + } + } + + public IDisposable PauseEntryRebuilding() + { + return new RebuildPauseDisposable(this); + } + + private void RebuildModifiedCollection() + { + if (pauseRebuilding) + { + return; + } + hasModifications = true; + newEntries.RemoveAll(v => removedEntries.Contains(v)); + modifiedEntries.Clear(); + modifiedEntries.AddRange(OldEntries.Concat(newEntries)); + } + + private IEnumerable OldEntries + { + get { return base.Entries.Where(x => !removedEntries.Contains(x)); } + } + + public void RemoveEntry(TEntry entry) + { + if (!removedEntries.Contains(entry)) + { + removedEntries.Add(entry); + RebuildModifiedCollection(); + } + } + + void IWritableArchive.RemoveEntry(IArchiveEntry entry) + { + RemoveEntry((TEntry)entry); + } + + public TEntry AddEntry(string key, Stream source, long size = 0, DateTime? modified = null) + { + return AddEntry(key, source, false, size, modified); + } + + IArchiveEntry IWritableArchive.AddEntry( + string key, + Stream source, + bool closeStream, + long size, + DateTime? modified + ) + { + return AddEntry(key, source, closeStream, size, modified); + } + + public TEntry AddEntry( + string key, + Stream source, + bool closeStream, + long size = 0, + DateTime? modified = null + ) + { + if (key.Length > 0 && key[0] is '/' or '\\') + { + key = key.Substring(1); + } + if (DoesKeyMatchExisting(key)) + { + throw new ArchiveException("Cannot add entry with duplicate key: " + key); + } + var entry = CreateEntry(key, source, size, modified, closeStream); + newEntries.Add(entry); + RebuildModifiedCollection(); + return entry; + } + + private bool DoesKeyMatchExisting(string key) + { + foreach (var path in Entries.Select(x => x.Key)) + { + var p = path.Replace('/', '\\'); + if (p.Length > 0 && p[0] == '\\') + { + p = p.Substring(1); + } + return string.Equals(p, key, StringComparison.OrdinalIgnoreCase); + } + return false; + } + + public void SaveTo(Stream stream, WriterOptions options) + { + //reset streams of new entries + newEntries + .Cast() + .ForEach(x => x.Stream.Seek(0, SeekOrigin.Begin)); + SaveTo(stream, options, OldEntries, newEntries); + } + + protected TEntry CreateEntry( + string key, + Stream source, + long size, + DateTime? modified, + bool closeStream + ) + { + if (!source.CanRead || !source.CanSeek) + { + throw new ArgumentException( + "Streams must be readable and seekable to use the Writing Archive API" + ); + } + return CreateEntryInternal(key, source, size, modified, closeStream); + } + + protected abstract TEntry CreateEntryInternal( + string key, + Stream source, + long size, + DateTime? modified, + bool closeStream + ); + + protected abstract void SaveTo( + Stream stream, + WriterOptions options, + IEnumerable oldEntries, + IEnumerable newEntries + ); + + public override void Dispose() + { + base.Dispose(); + newEntries.Cast().ForEach(x => x.Close()); + removedEntries.Cast().ForEach(x => x.Close()); + modifiedEntries.Cast().ForEach(x => x.Close()); + } } diff --git a/src/SharpCompress/Archives/ArchiveFactory.cs b/src/SharpCompress/Archives/ArchiveFactory.cs index f5c5cdee..a246bad9 100644 --- a/src/SharpCompress/Archives/ArchiveFactory.cs +++ b/src/SharpCompress/Archives/ArchiveFactory.cs @@ -2,234 +2,238 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; -using SharpCompress.Archives.GZip; -using SharpCompress.Archives.Rar; -using SharpCompress.Archives.SevenZip; -using SharpCompress.Archives.Tar; -using SharpCompress.Archives.Zip; using SharpCompress.Common; using SharpCompress.Factories; -using SharpCompress.IO; using SharpCompress.Readers; -namespace SharpCompress.Archives +namespace SharpCompress.Archives; + +public static class ArchiveFactory { - public static class ArchiveFactory + /// + /// Opens an Archive for random access + /// + /// + /// + /// + public static IArchive Open(Stream stream, ReaderOptions? readerOptions = null) { - /// - /// Opens an Archive for random access - /// - /// - /// - /// - public static IArchive Open(Stream stream, ReaderOptions? readerOptions = null) - { - readerOptions ??= new ReaderOptions(); + readerOptions ??= new ReaderOptions(); - return FindFactory(stream).Open(stream, readerOptions); + return FindFactory(stream).Open(stream, readerOptions); + } + + public static IWritableArchive Create(ArchiveType type) + { + var factory = Factory.Factories + .OfType() +.FirstOrDefault(item => item.KnownArchiveType == type); + + if (factory != null) + { + return factory.CreateWriteableArchive(); } - public static IWritableArchive Create(ArchiveType type) + throw new NotSupportedException("Cannot create Archives of type: " + type); + } + + /// + /// Constructor expects a filepath to an existing file. + /// + /// + /// + public static IArchive Open(string filePath, ReaderOptions? options = null) + { + filePath.CheckNotNullOrEmpty(nameof(filePath)); + return Open(new FileInfo(filePath), options); + } + + /// + /// Constructor with a FileInfo object to an existing file. + /// + /// + /// + public static IArchive Open(FileInfo fileInfo, ReaderOptions? options = null) + { + options ??= new ReaderOptions { LeaveStreamOpen = false }; + + return FindFactory(fileInfo).Open(fileInfo, options); + } + + /// + /// Constructor with IEnumerable FileInfo objects, multi and split support. + /// + /// + /// + public static IArchive Open(IEnumerable fileInfos, ReaderOptions? options = null) + { + fileInfos.CheckNotNull(nameof(fileInfos)); + var filesArray = fileInfos.ToArray(); + if (filesArray.Length == 0) { - var factory = Factories.Factory.Factories - .OfType() - .Where(item => item.KnownArchiveType == type) - .FirstOrDefault(); - - if (factory != null) - return factory.CreateWriteableArchive(); - - throw new NotSupportedException("Cannot create Archives of type: " + type); + throw new InvalidOperationException("No files to open"); } - /// - /// Constructor expects a filepath to an existing file. - /// - /// - /// - public static IArchive Open(string filePath, ReaderOptions? options = null) + var fileInfo = filesArray[0]; + if (filesArray.Length == 1) { - filePath.CheckNotNullOrEmpty(nameof(filePath)); - return Open(new FileInfo(filePath), options); + return Open(fileInfo, options); } - /// - /// Constructor with a FileInfo object to an existing file. - /// - /// - /// - public static IArchive Open(FileInfo fileInfo, ReaderOptions? options = null) - { - options ??= new ReaderOptions { LeaveStreamOpen = false }; + fileInfo.CheckNotNull(nameof(fileInfo)); + options ??= new ReaderOptions { LeaveStreamOpen = false }; - return FindFactory(fileInfo).Open(fileInfo, options); + return FindFactory(fileInfo).Open(filesArray, options); + } + + /// + /// Constructor with IEnumerable FileInfo objects, multi and split support. + /// + /// + /// + public static IArchive Open(IEnumerable streams, ReaderOptions? options = null) + { + streams.CheckNotNull(nameof(streams)); + var streamsArray = streams.ToArray(); + if (streamsArray.Length == 0) + { + throw new InvalidOperationException("No streams"); } - /// - /// Constructor with IEnumerable FileInfo objects, multi and split support. - /// - /// - /// - public static IArchive Open(IEnumerable fileInfos, ReaderOptions? options = null) + var firstStream = streamsArray[0]; + if (streamsArray.Length == 1) { - fileInfos.CheckNotNull(nameof(fileInfos)); - FileInfo[] filesArray = fileInfos.ToArray(); - if (filesArray.Length == 0) - throw new InvalidOperationException("No files to open"); - FileInfo fileInfo = filesArray[0]; - if (filesArray.Length == 1) - return Open(fileInfo, options); - - fileInfo.CheckNotNull(nameof(fileInfo)); - options ??= new ReaderOptions { LeaveStreamOpen = false }; - - return FindFactory(fileInfo).Open(filesArray, options); + return Open(firstStream, options); } - /// - /// Constructor with IEnumerable FileInfo objects, multi and split support. - /// - /// - /// - public static IArchive Open(IEnumerable streams, ReaderOptions? options = null) + firstStream.CheckNotNull(nameof(firstStream)); + options ??= new ReaderOptions(); + + return FindFactory(firstStream).Open(streamsArray, options); + } + + /// + /// Extract to specific directory, retaining filename + /// + public static void WriteToDirectory( + string sourceArchive, + string destinationDirectory, + ExtractionOptions? options = null + ) + { + using var archive = Open(sourceArchive); + foreach (var entry in archive.Entries) { - streams.CheckNotNull(nameof(streams)); - Stream[] streamsArray = streams.ToArray(); - if (streamsArray.Length == 0) - throw new InvalidOperationException("No streams"); - Stream firstStream = streamsArray[0]; - if (streamsArray.Length == 1) - return Open(firstStream, options); + entry.WriteToDirectory(destinationDirectory, options); + } + } - firstStream.CheckNotNull(nameof(firstStream)); - options ??= new ReaderOptions(); + private static T FindFactory(FileInfo finfo) where T : IFactory + { + finfo.CheckNotNull(nameof(finfo)); + using Stream stream = finfo.OpenRead(); + return FindFactory(stream); + } - return FindFactory(firstStream).Open(streamsArray, options); + private static T FindFactory(Stream stream) where T : IFactory + { + stream.CheckNotNull(nameof(stream)); + if (!stream.CanRead || !stream.CanSeek) + { + throw new ArgumentException("Stream should be readable and seekable"); } - /// - /// Extract to specific directory, retaining filename - /// - public static void WriteToDirectory( - string sourceArchive, - string destinationDirectory, - ExtractionOptions? options = null - ) + var factories = Factory.Factories.OfType(); + + var startPosition = stream.Position; + + foreach (var factory in factories) { - using IArchive archive = Open(sourceArchive); - foreach (IArchiveEntry entry in archive.Entries) - { - entry.WriteToDirectory(destinationDirectory, options); - } - } + stream.Seek(startPosition, SeekOrigin.Begin); - private static T FindFactory(FileInfo finfo) where T : IFactory - { - finfo.CheckNotNull(nameof(finfo)); - using (Stream stream = finfo.OpenRead()) - { - return FindFactory(stream); - } - } - - private static T FindFactory(Stream stream) where T : IFactory - { - stream.CheckNotNull(nameof(stream)); - if (!stream.CanRead || !stream.CanSeek) - { - throw new ArgumentException("Stream should be readable and seekable"); - } - - var factories = Factories.Factory.Factories.OfType(); - - long startPosition = stream.Position; - - foreach (var factory in factories) + if (factory.IsArchive(stream)) { stream.Seek(startPosition, SeekOrigin.Begin); - if (factory.IsArchive(stream)) - { - stream.Seek(startPosition, SeekOrigin.Begin); - - return factory; - } + return factory; } - - var extensions = string.Join(", ", factories.Select(item => item.Name)); - - throw new InvalidOperationException( - $"Cannot determine compressed stream type. Supported Archive Formats: {extensions}" - ); } - public static bool IsArchive(string filePath, out ArchiveType? type) + var extensions = string.Join(", ", factories.Select(item => item.Name)); + + throw new InvalidOperationException( + $"Cannot determine compressed stream type. Supported Archive Formats: {extensions}" + ); + } + + public static bool IsArchive(string filePath, out ArchiveType? type) + { + filePath.CheckNotNullOrEmpty(nameof(filePath)); + using Stream s = File.OpenRead(filePath); + return IsArchive(s, out type); + } + + private static bool IsArchive(Stream stream, out ArchiveType? type) + { + type = null; + stream.CheckNotNull(nameof(stream)); + + if (!stream.CanRead || !stream.CanSeek) { - filePath.CheckNotNullOrEmpty(nameof(filePath)); - using (Stream s = File.OpenRead(filePath)) - return IsArchive(s, out type); + throw new ArgumentException("Stream should be readable and seekable"); } - private static bool IsArchive(Stream stream, out ArchiveType? type) - { - type = null; - stream.CheckNotNull(nameof(stream)); + var startPosition = stream.Position; - if (!stream.CanRead || !stream.CanSeek) + foreach (var factory in Factory.Factories) + { + stream.Position = startPosition; + + if (factory.IsArchive(stream, null)) { - throw new ArgumentException("Stream should be readable and seekable"); + type = factory.KnownArchiveType; + return true; } - - var startPosition = stream.Position; - - foreach (var factory in Factories.Factory.Factories) - { - stream.Position = startPosition; - - if (factory.IsArchive(stream, null)) - { - type = factory.KnownArchiveType; - return true; - } - } - - return false; } - /// - /// From a passed in archive (zip, rar, 7z, 001), return all parts. - /// - /// - /// - public static IEnumerable GetFileParts(string part1) - { - part1.CheckNotNullOrEmpty(nameof(part1)); - return GetFileParts(new FileInfo(part1)).Select(a => a.FullName); - } + return false; + } - /// - /// From a passed in archive (zip, rar, 7z, 001), return all parts. - /// - /// - /// - public static IEnumerable GetFileParts(FileInfo part1) - { - part1.CheckNotNull(nameof(part1)); - yield return part1; + /// + /// From a passed in archive (zip, rar, 7z, 001), return all parts. + /// + /// + /// + public static IEnumerable GetFileParts(string part1) + { + part1.CheckNotNullOrEmpty(nameof(part1)); + return GetFileParts(new FileInfo(part1)).Select(a => a.FullName); + } - foreach (var factory in Factory.Factories.OfType()) + /// + /// From a passed in archive (zip, rar, 7z, 001), return all parts. + /// + /// + /// + public static IEnumerable GetFileParts(FileInfo part1) + { + part1.CheckNotNull(nameof(part1)); + yield return part1; + + foreach (var factory in Factory.Factories.OfType()) + { + var i = 1; + var part = factory.GetFilePart(i++, part1); + + if (part != null) { - int i = 1; - FileInfo? part = factory.GetFilePart(i++, part1); - - if (part != null) + yield return part; + while ((part = factory.GetFilePart(i++, part1)) != null) //tests split too { yield return part; - while ((part = factory.GetFilePart(i++, part1)) != null) //tests split too - yield return part; - - yield break; } + + yield break; } } } diff --git a/src/SharpCompress/Archives/GZip/GZipArchive.cs b/src/SharpCompress/Archives/GZip/GZipArchive.cs index ed1b6a6b..4100f2f2 100644 --- a/src/SharpCompress/Archives/GZip/GZipArchive.cs +++ b/src/SharpCompress/Archives/GZip/GZipArchive.cs @@ -10,223 +10,216 @@ using SharpCompress.Readers.GZip; using SharpCompress.Writers; using SharpCompress.Writers.GZip; -namespace SharpCompress.Archives.GZip +namespace SharpCompress.Archives.GZip; + +public class GZipArchive : AbstractWritableArchive { - public class GZipArchive : AbstractWritableArchive + /// + /// Constructor expects a filepath to an existing file. + /// + /// + /// + public static GZipArchive Open(string filePath, ReaderOptions? readerOptions = null) { - /// - /// Constructor expects a filepath to an existing file. - /// - /// - /// - public static GZipArchive Open(string filePath, ReaderOptions? readerOptions = null) + filePath.CheckNotNullOrEmpty(nameof(filePath)); + return Open(new FileInfo(filePath), readerOptions ?? new ReaderOptions()); + } + + /// + /// Constructor with a FileInfo object to an existing file. + /// + /// + /// + public static GZipArchive Open(FileInfo fileInfo, ReaderOptions? readerOptions = null) + { + fileInfo.CheckNotNull(nameof(fileInfo)); + return new GZipArchive( + new SourceStream( + fileInfo, + i => ArchiveVolumeFactory.GetFilePart(i, fileInfo), + readerOptions ?? new ReaderOptions() + ) + ); + } + + /// + /// Constructor with all file parts passed in + /// + /// + /// + public static GZipArchive Open( + IEnumerable fileInfos, + ReaderOptions? readerOptions = null + ) + { + fileInfos.CheckNotNull(nameof(fileInfos)); + var files = fileInfos.ToArray(); + return new GZipArchive( + new SourceStream( + files[0], + i => i < files.Length ? files[i] : null, + readerOptions ?? new ReaderOptions() + ) + ); + } + + /// + /// Constructor with all stream parts passed in + /// + /// + /// + public static GZipArchive Open( + IEnumerable streams, + ReaderOptions? readerOptions = null + ) + { + streams.CheckNotNull(nameof(streams)); + var strms = streams.ToArray(); + return new GZipArchive( + new SourceStream( + strms[0], + i => i < strms.Length ? strms[i] : null, + readerOptions ?? new ReaderOptions() + ) + ); + } + + /// + /// Takes a seekable Stream as a source + /// + /// + /// + public static GZipArchive Open(Stream stream, ReaderOptions? readerOptions = null) + { + stream.CheckNotNull(nameof(stream)); + return new GZipArchive( + new SourceStream(stream, i => null, readerOptions ?? new ReaderOptions()) + ); + } + + public static GZipArchive Create() + { + return new GZipArchive(); + } + + /// + /// Constructor with a SourceStream able to handle FileInfo and Streams. + /// + /// + /// + internal GZipArchive(SourceStream srcStream) : base(ArchiveType.Tar, srcStream) { } + + protected override IEnumerable LoadVolumes(SourceStream srcStream) + { + srcStream.LoadAllParts(); + var idx = 0; + return srcStream.Streams.Select(a => new GZipVolume(a, ReaderOptions, idx++)); + } + + public static bool IsGZipFile(string filePath) + { + return IsGZipFile(new FileInfo(filePath)); + } + + public static bool IsGZipFile(FileInfo fileInfo) + { + if (!fileInfo.Exists) { - filePath.CheckNotNullOrEmpty(nameof(filePath)); - return Open(new FileInfo(filePath), readerOptions ?? new ReaderOptions()); + return false; } - /// - /// Constructor with a FileInfo object to an existing file. - /// - /// - /// - public static GZipArchive Open(FileInfo fileInfo, ReaderOptions? readerOptions = null) + using Stream stream = fileInfo.OpenRead(); + return IsGZipFile(stream); + } + + public void SaveTo(string filePath) + { + SaveTo(new FileInfo(filePath)); + } + + public void SaveTo(FileInfo fileInfo) + { + using var stream = fileInfo.Open(FileMode.Create, FileAccess.Write); + SaveTo(stream, new WriterOptions(CompressionType.GZip)); + } + + public static bool IsGZipFile(Stream stream) + { + // read the header on the first read + Span header = stackalloc byte[10]; + + // workitem 8501: handle edge case (decompress empty stream) + if (!stream.ReadFully(header)) { - fileInfo.CheckNotNull(nameof(fileInfo)); - return new GZipArchive( - new SourceStream( - fileInfo, - i => ArchiveVolumeFactory.GetFilePart(i, fileInfo), - readerOptions ?? new ReaderOptions() - ) - ); + return false; } - /// - /// Constructor with all file parts passed in - /// - /// - /// - public static GZipArchive Open( - IEnumerable fileInfos, - ReaderOptions? readerOptions = null - ) + if (header[0] != 0x1F || header[1] != 0x8B || header[2] != 8) { - fileInfos.CheckNotNull(nameof(fileInfos)); - FileInfo[] files = fileInfos.ToArray(); - return new GZipArchive( - new SourceStream( - files[0], - i => i < files.Length ? files[i] : null, - readerOptions ?? new ReaderOptions() - ) - ); + return false; } - /// - /// Constructor with all stream parts passed in - /// - /// - /// - public static GZipArchive Open( - IEnumerable streams, - ReaderOptions? readerOptions = null - ) + return true; + } + + internal GZipArchive() : base(ArchiveType.GZip) { } + + protected override GZipArchiveEntry CreateEntryInternal( + string filePath, + Stream source, + long size, + DateTime? modified, + bool closeStream + ) + { + if (Entries.Any()) { - streams.CheckNotNull(nameof(streams)); - Stream[] strms = streams.ToArray(); - return new GZipArchive( - new SourceStream( - strms[0], - i => i < strms.Length ? strms[i] : null, - readerOptions ?? new ReaderOptions() - ) - ); + throw new InvalidOperationException("Only one entry is allowed in a GZip Archive"); } + return new GZipWritableArchiveEntry( + this, + source, + filePath, + size, + modified, + closeStream + ); + } - /// - /// Takes a seekable Stream as a source - /// - /// - /// - public static GZipArchive Open(Stream stream, ReaderOptions? readerOptions = null) + protected override void SaveTo( + Stream stream, + WriterOptions options, + IEnumerable oldEntries, + IEnumerable newEntries + ) + { + if (Entries.Count > 1) { - stream.CheckNotNull(nameof(stream)); - return new GZipArchive( - new SourceStream(stream, i => null, readerOptions ?? new ReaderOptions()) - ); + throw new InvalidOperationException("Only one entry is allowed in a GZip Archive"); } - - public static GZipArchive Create() + using var writer = new GZipWriter(stream, new GZipWriterOptions(options)); + foreach (var entry in oldEntries.Concat(newEntries).Where(x => !x.IsDirectory)) { - return new GZipArchive(); - } - - /// - /// Constructor with a SourceStream able to handle FileInfo and Streams. - /// - /// - /// - internal GZipArchive(SourceStream srcStream) : base(ArchiveType.Tar, srcStream) { } - - protected override IEnumerable LoadVolumes(SourceStream srcStream) - { - srcStream.LoadAllParts(); - int idx = 0; - return srcStream.Streams.Select(a => new GZipVolume(a, ReaderOptions, idx++)); - } - - public static bool IsGZipFile(string filePath) - { - return IsGZipFile(new FileInfo(filePath)); - } - - public static bool IsGZipFile(FileInfo fileInfo) - { - if (!fileInfo.Exists) - { - return false; - } - - using Stream stream = fileInfo.OpenRead(); - return IsGZipFile(stream); - } - - public void SaveTo(string filePath) - { - SaveTo(new FileInfo(filePath)); - } - - public void SaveTo(FileInfo fileInfo) - { - using (var stream = fileInfo.Open(FileMode.Create, FileAccess.Write)) - { - SaveTo(stream, new WriterOptions(CompressionType.GZip)); - } - } - - public static bool IsGZipFile(Stream stream) - { - // read the header on the first read - Span header = stackalloc byte[10]; - - // workitem 8501: handle edge case (decompress empty stream) - if (!stream.ReadFully(header)) - { - return false; - } - - if (header[0] != 0x1F || header[1] != 0x8B || header[2] != 8) - { - return false; - } - - return true; - } - - internal GZipArchive() : base(ArchiveType.GZip) { } - - protected override GZipArchiveEntry CreateEntryInternal( - string filePath, - Stream source, - long size, - DateTime? modified, - bool closeStream - ) - { - if (Entries.Any()) - { - throw new InvalidOperationException("Only one entry is allowed in a GZip Archive"); - } - return new GZipWritableArchiveEntry( - this, - source, - filePath, - size, - modified, - closeStream - ); - } - - protected override void SaveTo( - Stream stream, - WriterOptions options, - IEnumerable oldEntries, - IEnumerable newEntries - ) - { - if (Entries.Count > 1) - { - throw new InvalidOperationException("Only one entry is allowed in a GZip Archive"); - } - using (var writer = new GZipWriter(stream, new GZipWriterOptions(options))) - { - foreach (var entry in oldEntries.Concat(newEntries).Where(x => !x.IsDirectory)) - { - using (var entryStream = entry.OpenEntryStream()) - { - writer.Write(entry.Key, entryStream, entry.LastModifiedTime); - } - } - } - } - - protected override IEnumerable LoadEntries( - IEnumerable volumes - ) - { - Stream stream = volumes.Single().Stream; - yield return new GZipArchiveEntry( - this, - new GZipFilePart(stream, ReaderOptions.ArchiveEncoding) - ); - } - - protected override IReader CreateReaderForSolidExtraction() - { - var stream = Volumes.Single().Stream; - stream.Position = 0; - return GZipReader.Open(stream); + using var entryStream = entry.OpenEntryStream(); + writer.Write(entry.Key, entryStream, entry.LastModifiedTime); } } + + protected override IEnumerable LoadEntries( + IEnumerable volumes + ) + { + var stream = volumes.Single().Stream; + yield return new GZipArchiveEntry( + this, + new GZipFilePart(stream, ReaderOptions.ArchiveEncoding) + ); + } + + protected override IReader CreateReaderForSolidExtraction() + { + var stream = Volumes.Single().Stream; + stream.Position = 0; + return GZipReader.Open(stream); + } } diff --git a/src/SharpCompress/Archives/GZip/GZipArchiveEntry.cs b/src/SharpCompress/Archives/GZip/GZipArchiveEntry.cs index 23316046..68032131 100644 --- a/src/SharpCompress/Archives/GZip/GZipArchiveEntry.cs +++ b/src/SharpCompress/Archives/GZip/GZipArchiveEntry.cs @@ -1,33 +1,32 @@ -using System.IO; +using System.IO; using System.Linq; using SharpCompress.Common.GZip; -namespace SharpCompress.Archives.GZip +namespace SharpCompress.Archives.GZip; + +public class GZipArchiveEntry : GZipEntry, IArchiveEntry { - public class GZipArchiveEntry : GZipEntry, IArchiveEntry + internal GZipArchiveEntry(GZipArchive archive, GZipFilePart part) : base(part) { - internal GZipArchiveEntry(GZipArchive archive, GZipFilePart part) : base(part) - { - Archive = archive; - } - - public virtual Stream OpenEntryStream() - { - //this is to reset the stream to be read multiple times - var part = (GZipFilePart)Parts.Single(); - if (part.GetRawStream().Position != part.EntryStartPosition) - { - part.GetRawStream().Position = part.EntryStartPosition; - } - return Parts.Single().GetCompressedStream(); - } - - #region IArchiveEntry Members - - public IArchive Archive { get; } - - public bool IsComplete => true; - - #endregion + Archive = archive; } + + public virtual Stream OpenEntryStream() + { + //this is to reset the stream to be read multiple times + var part = (GZipFilePart)Parts.Single(); + if (part.GetRawStream().Position != part.EntryStartPosition) + { + part.GetRawStream().Position = part.EntryStartPosition; + } + return Parts.Single().GetCompressedStream(); + } + + #region IArchiveEntry Members + + public IArchive Archive { get; } + + public bool IsComplete => true; + + #endregion } diff --git a/src/SharpCompress/Archives/GZip/GZipWritableArchiveEntry.cs b/src/SharpCompress/Archives/GZip/GZipWritableArchiveEntry.cs index 4f35f24d..7685ceb1 100644 --- a/src/SharpCompress/Archives/GZip/GZipWritableArchiveEntry.cs +++ b/src/SharpCompress/Archives/GZip/GZipWritableArchiveEntry.cs @@ -6,68 +6,67 @@ using System.IO; using SharpCompress.Common; using SharpCompress.IO; -namespace SharpCompress.Archives.GZip +namespace SharpCompress.Archives.GZip; + +internal sealed class GZipWritableArchiveEntry : GZipArchiveEntry, IWritableArchiveEntry { - internal sealed class GZipWritableArchiveEntry : GZipArchiveEntry, IWritableArchiveEntry + private readonly bool closeStream; + private readonly Stream stream; + + internal GZipWritableArchiveEntry( + GZipArchive archive, + Stream stream, + string path, + long size, + DateTime? lastModified, + bool closeStream + ) : base(archive, null) { - private readonly bool closeStream; - private readonly Stream stream; + this.stream = stream; + Key = path; + Size = size; + LastModifiedTime = lastModified; + this.closeStream = closeStream; + } - internal GZipWritableArchiveEntry( - GZipArchive archive, - Stream stream, - string path, - long size, - DateTime? lastModified, - bool closeStream - ) : base(archive, null) + public override long Crc => 0; + + public override string Key { get; } + + public override long CompressedSize => 0; + + public override long Size { get; } + + public override DateTime? LastModifiedTime { get; } + + public override DateTime? CreatedTime => null; + + public override DateTime? LastAccessedTime => null; + + public override DateTime? ArchivedTime => null; + + public override bool IsEncrypted => false; + + public override bool IsDirectory => false; + + public override bool IsSplitAfter => false; + + internal override IEnumerable Parts => throw new NotImplementedException(); + + Stream IWritableArchiveEntry.Stream => stream; + + public override Stream OpenEntryStream() + { + //ensure new stream is at the start, this could be reset + stream.Seek(0, SeekOrigin.Begin); + return NonDisposingStream.Create(stream); + } + + internal override void Close() + { + if (closeStream) { - this.stream = stream; - Key = path; - Size = size; - LastModifiedTime = lastModified; - this.closeStream = closeStream; - } - - public override long Crc => 0; - - public override string Key { get; } - - public override long CompressedSize => 0; - - public override long Size { get; } - - public override DateTime? LastModifiedTime { get; } - - public override DateTime? CreatedTime => null; - - public override DateTime? LastAccessedTime => null; - - public override DateTime? ArchivedTime => null; - - public override bool IsEncrypted => false; - - public override bool IsDirectory => false; - - public override bool IsSplitAfter => false; - - internal override IEnumerable Parts => throw new NotImplementedException(); - - Stream IWritableArchiveEntry.Stream => stream; - - public override Stream OpenEntryStream() - { - //ensure new stream is at the start, this could be reset - stream.Seek(0, SeekOrigin.Begin); - return NonDisposingStream.Create(stream); - } - - internal override void Close() - { - if (closeStream) - { - stream.Dispose(); - } + stream.Dispose(); } } } diff --git a/src/SharpCompress/Archives/IArchive.cs b/src/SharpCompress/Archives/IArchive.cs index acb2bf11..154529bf 100644 --- a/src/SharpCompress/Archives/IArchive.cs +++ b/src/SharpCompress/Archives/IArchive.cs @@ -1,49 +1,48 @@ -using System; +using System; using System.Collections.Generic; using SharpCompress.Common; using SharpCompress.Readers; -namespace SharpCompress.Archives +namespace SharpCompress.Archives; + +public interface IArchive : IDisposable { - public interface IArchive : IDisposable - { - event EventHandler> EntryExtractionBegin; - event EventHandler> EntryExtractionEnd; + event EventHandler> EntryExtractionBegin; + event EventHandler> EntryExtractionEnd; - event EventHandler CompressedBytesRead; - event EventHandler FilePartExtractionBegin; + event EventHandler CompressedBytesRead; + event EventHandler FilePartExtractionBegin; - IEnumerable Entries { get; } - IEnumerable Volumes { get; } + IEnumerable Entries { get; } + IEnumerable Volumes { get; } - ArchiveType Type { get; } + ArchiveType Type { get; } - /// - /// Use this method to extract all entries in an archive in order. - /// This is primarily for SOLID Rar Archives or 7Zip Archives as they need to be - /// extracted sequentially for the best performance. - /// - IReader ExtractAllEntries(); + /// + /// Use this method to extract all entries in an archive in order. + /// This is primarily for SOLID Rar Archives or 7Zip Archives as they need to be + /// extracted sequentially for the best performance. + /// + IReader ExtractAllEntries(); - /// - /// Archive is SOLID (this means the Archive saved bytes by reusing information which helps for archives containing many small files). - /// Rar Archives can be SOLID while all 7Zip archives are considered SOLID. - /// - bool IsSolid { get; } + /// + /// Archive is SOLID (this means the Archive saved bytes by reusing information which helps for archives containing many small files). + /// Rar Archives can be SOLID while all 7Zip archives are considered SOLID. + /// + bool IsSolid { get; } - /// - /// This checks to see if all the known entries have IsComplete = true - /// - bool IsComplete { get; } + /// + /// This checks to see if all the known entries have IsComplete = true + /// + bool IsComplete { get; } - /// - /// The total size of the files compressed in the archive. - /// - long TotalSize { get; } + /// + /// The total size of the files compressed in the archive. + /// + long TotalSize { get; } - /// - /// The total size of the files as uncompressed in the archive. - /// - long TotalUncompressSize { get; } - } + /// + /// The total size of the files as uncompressed in the archive. + /// + long TotalUncompressSize { get; } } diff --git a/src/SharpCompress/Archives/IArchiveEntry.cs b/src/SharpCompress/Archives/IArchiveEntry.cs index e3351582..708753cb 100644 --- a/src/SharpCompress/Archives/IArchiveEntry.cs +++ b/src/SharpCompress/Archives/IArchiveEntry.cs @@ -1,24 +1,23 @@ -using System.IO; +using System.IO; using SharpCompress.Common; -namespace SharpCompress.Archives +namespace SharpCompress.Archives; + +public interface IArchiveEntry : IEntry { - public interface IArchiveEntry : IEntry - { - /// - /// Opens the current entry as a stream that will decompress as it is read. - /// Read the entire stream or use SkipEntry on EntryStream. - /// - Stream OpenEntryStream(); + /// + /// Opens the current entry as a stream that will decompress as it is read. + /// Read the entire stream or use SkipEntry on EntryStream. + /// + Stream OpenEntryStream(); - /// - /// The archive can find all the parts of the archive needed to extract this entry. - /// - bool IsComplete { get; } + /// + /// The archive can find all the parts of the archive needed to extract this entry. + /// + bool IsComplete { get; } - /// - /// The archive instance this entry belongs to - /// - IArchive Archive { get; } - } + /// + /// The archive instance this entry belongs to + /// + IArchive Archive { get; } } diff --git a/src/SharpCompress/Archives/IArchiveEntryExtensions.cs b/src/SharpCompress/Archives/IArchiveEntryExtensions.cs index d5eac3f9..cd49cef0 100644 --- a/src/SharpCompress/Archives/IArchiveEntryExtensions.cs +++ b/src/SharpCompress/Archives/IArchiveEntryExtensions.cs @@ -1,79 +1,74 @@ -using System.IO; +using System.IO; using SharpCompress.Common; using SharpCompress.IO; -namespace SharpCompress.Archives +namespace SharpCompress.Archives; + +public static class IArchiveEntryExtensions { - public static class IArchiveEntryExtensions + public static void WriteTo(this IArchiveEntry archiveEntry, Stream streamToWriteTo) { - public static void WriteTo(this IArchiveEntry archiveEntry, Stream streamToWriteTo) + if (archiveEntry.IsDirectory) { - if (archiveEntry.IsDirectory) - { - throw new ExtractionException("Entry is a file directory and cannot be extracted."); - } - - var streamListener = (IArchiveExtractionListener)archiveEntry.Archive; - streamListener.EnsureEntriesLoaded(); - streamListener.FireEntryExtractionBegin(archiveEntry); - streamListener.FireFilePartExtractionBegin( - archiveEntry.Key, - archiveEntry.Size, - archiveEntry.CompressedSize - ); - var entryStream = archiveEntry.OpenEntryStream(); - if (entryStream is null) - { - return; - } - using (entryStream) - { - using (Stream s = new ListeningStream(streamListener, entryStream)) - { - s.TransferTo(streamToWriteTo); - } - } - streamListener.FireEntryExtractionEnd(archiveEntry); + throw new ExtractionException("Entry is a file directory and cannot be extracted."); } - /// - /// Extract to specific directory, retaining filename - /// - public static void WriteToDirectory( - this IArchiveEntry entry, - string destinationDirectory, - ExtractionOptions? options = null - ) + var streamListener = (IArchiveExtractionListener)archiveEntry.Archive; + streamListener.EnsureEntriesLoaded(); + streamListener.FireEntryExtractionBegin(archiveEntry); + streamListener.FireFilePartExtractionBegin( + archiveEntry.Key, + archiveEntry.Size, + archiveEntry.CompressedSize + ); + var entryStream = archiveEntry.OpenEntryStream(); + if (entryStream is null) { - ExtractionMethods.WriteEntryToDirectory( - entry, - destinationDirectory, - options, - entry.WriteToFile - ); + return; } + using (entryStream) + { + using Stream s = new ListeningStream(streamListener, entryStream); + s.TransferTo(streamToWriteTo); + } + streamListener.FireEntryExtractionEnd(archiveEntry); + } - /// - /// Extract to specific file - /// - public static void WriteToFile( - this IArchiveEntry entry, - string destinationFileName, - ExtractionOptions? options = null - ) - { - ExtractionMethods.WriteEntryToFile( - entry, - destinationFileName, - options, - (x, fm) => - { - using (FileStream fs = File.Open(destinationFileName, fm)) - { - entry.WriteTo(fs); - } - } - ); - } + /// + /// Extract to specific directory, retaining filename + /// + public static void WriteToDirectory( + this IArchiveEntry entry, + string destinationDirectory, + ExtractionOptions? options = null + ) + { + ExtractionMethods.WriteEntryToDirectory( + entry, + destinationDirectory, + options, + entry.WriteToFile + ); + } + + /// + /// Extract to specific file + /// + public static void WriteToFile( + this IArchiveEntry entry, + string destinationFileName, + ExtractionOptions? options = null + ) + { + ExtractionMethods.WriteEntryToFile( + entry, + destinationFileName, + options, + (x, fm) => + { + using var fs = File.Open(destinationFileName, fm); + entry.WriteTo(fs); + } + ); } } diff --git a/src/SharpCompress/Archives/IArchiveExtensions.cs b/src/SharpCompress/Archives/IArchiveExtensions.cs index c0a9e1dd..14a48dbd 100644 --- a/src/SharpCompress/Archives/IArchiveExtensions.cs +++ b/src/SharpCompress/Archives/IArchiveExtensions.cs @@ -1,23 +1,22 @@ -using System.Linq; +using System.Linq; using SharpCompress.Common; -namespace SharpCompress.Archives +namespace SharpCompress.Archives; + +public static class IArchiveExtensions { - public static class IArchiveExtensions + /// + /// Extract to specific directory, retaining filename + /// + public static void WriteToDirectory( + this IArchive archive, + string destinationDirectory, + ExtractionOptions? options = null + ) { - /// - /// Extract to specific directory, retaining filename - /// - public static void WriteToDirectory( - this IArchive archive, - string destinationDirectory, - ExtractionOptions? options = null - ) + foreach (var entry in archive.Entries.Where(x => !x.IsDirectory)) { - foreach (IArchiveEntry entry in archive.Entries.Where(x => !x.IsDirectory)) - { - entry.WriteToDirectory(destinationDirectory, options); - } + entry.WriteToDirectory(destinationDirectory, options); } } } diff --git a/src/SharpCompress/Archives/IArchiveExtractionListener.cs b/src/SharpCompress/Archives/IArchiveExtractionListener.cs index b352691e..7bc2ef34 100644 --- a/src/SharpCompress/Archives/IArchiveExtractionListener.cs +++ b/src/SharpCompress/Archives/IArchiveExtractionListener.cs @@ -1,11 +1,10 @@ -using SharpCompress.Common; +using SharpCompress.Common; -namespace SharpCompress.Archives +namespace SharpCompress.Archives; + +internal interface IArchiveExtractionListener : IExtractionListener { - internal interface IArchiveExtractionListener : IExtractionListener - { - void EnsureEntriesLoaded(); - void FireEntryExtractionBegin(IArchiveEntry entry); - void FireEntryExtractionEnd(IArchiveEntry entry); - } + void EnsureEntriesLoaded(); + void FireEntryExtractionBegin(IArchiveEntry entry); + void FireEntryExtractionEnd(IArchiveEntry entry); } diff --git a/src/SharpCompress/Archives/IArchiveFactory.cs b/src/SharpCompress/Archives/IArchiveFactory.cs index 6ba64079..370e5c9f 100644 --- a/src/SharpCompress/Archives/IArchiveFactory.cs +++ b/src/SharpCompress/Archives/IArchiveFactory.cs @@ -1,40 +1,35 @@ -using System; -using System.Collections.Generic; using System.IO; - -using SharpCompress.Common; using SharpCompress.Factories; using SharpCompress.Readers; -namespace SharpCompress.Archives +namespace SharpCompress.Archives; + +/// +/// Represents a factory used to identify and open archives. +/// +/// +/// Currently implemented by:
+/// +/// +/// +/// +/// +/// +/// +///
+public interface IArchiveFactory : IFactory { /// - /// Represents a factory used to identify and open archives. + /// Opens an Archive for random access. /// - /// - /// Currently implemented by:
- /// - /// - /// - /// - /// - /// - /// - ///
- public interface IArchiveFactory : IFactory - { - /// - /// Opens an Archive for random access. - /// - /// An open, readable and seekable stream. - /// reading options. - IArchive Open(Stream stream, ReaderOptions? readerOptions = null); + /// An open, readable and seekable stream. + /// reading options. + IArchive Open(Stream stream, ReaderOptions? readerOptions = null); - /// - /// Constructor with a FileInfo object to an existing file. - /// - /// the file to open. - /// reading options. - IArchive Open(System.IO.FileInfo fileInfo, ReaderOptions? readerOptions = null); - } + /// + /// Constructor with a FileInfo object to an existing file. + /// + /// the file to open. + /// reading options. + IArchive Open(FileInfo fileInfo, ReaderOptions? readerOptions = null); } diff --git a/src/SharpCompress/Archives/IMultiArchiveFactory.cs b/src/SharpCompress/Archives/IMultiArchiveFactory.cs index 7610b146..be2eefb8 100644 --- a/src/SharpCompress/Archives/IMultiArchiveFactory.cs +++ b/src/SharpCompress/Archives/IMultiArchiveFactory.cs @@ -1,43 +1,39 @@ -using System; using System.Collections.Generic; using System.IO; - -using SharpCompress.Common; using SharpCompress.Factories; using SharpCompress.Readers; -namespace SharpCompress.Archives +namespace SharpCompress.Archives; + +/// +/// Represents a factory used to identify and open archives. +/// +/// +/// Implemented by:
+/// +/// +/// +/// +/// +/// +/// +///
+public interface IMultiArchiveFactory : IFactory { /// - /// Represents a factory used to identify and open archives. + /// Constructor with IEnumerable FileInfo objects, multi and split support. /// - /// - /// Implemented by:
- /// - /// - /// - /// - /// - /// - /// - ///
- public interface IMultiArchiveFactory : IFactory - { - /// - /// Constructor with IEnumerable FileInfo objects, multi and split support. - /// - /// - /// reading options. - IArchive Open(IReadOnlyList streams, ReaderOptions? readerOptions = null); + /// + /// reading options. + IArchive Open(IReadOnlyList streams, ReaderOptions? readerOptions = null); - /// - /// Constructor with IEnumerable Stream objects, multi and split support. - /// - /// - /// reading options. - IArchive Open( - IReadOnlyList fileInfos, - ReaderOptions? readerOptions = null - ); - } + /// + /// Constructor with IEnumerable Stream objects, multi and split support. + /// + /// + /// reading options. + IArchive Open( + IReadOnlyList fileInfos, + ReaderOptions? readerOptions = null + ); } diff --git a/src/SharpCompress/Archives/IWritableArchive.cs b/src/SharpCompress/Archives/IWritableArchive.cs index 02b76f66..37b84aa0 100644 --- a/src/SharpCompress/Archives/IWritableArchive.cs +++ b/src/SharpCompress/Archives/IWritableArchive.cs @@ -2,26 +2,25 @@ using System; using System.IO; using SharpCompress.Writers; -namespace SharpCompress.Archives +namespace SharpCompress.Archives; + +public interface IWritableArchive : IArchive { - public interface IWritableArchive : IArchive - { - void RemoveEntry(IArchiveEntry entry); + void RemoveEntry(IArchiveEntry entry); - IArchiveEntry AddEntry( - string key, - Stream source, - bool closeStream, - long size = 0, - DateTime? modified = null - ); + IArchiveEntry AddEntry( + string key, + Stream source, + bool closeStream, + long size = 0, + DateTime? modified = null + ); - void SaveTo(Stream stream, WriterOptions options); + void SaveTo(Stream stream, WriterOptions options); - /// - /// Use this to pause entry rebuilding when adding large collections of entries. Dispose when complete. A using statement is recommended. - /// - /// IDisposeable to resume entry rebuilding - IDisposable PauseEntryRebuilding(); - } + /// + /// Use this to pause entry rebuilding when adding large collections of entries. Dispose when complete. A using statement is recommended. + /// + /// IDisposeable to resume entry rebuilding + IDisposable PauseEntryRebuilding(); } diff --git a/src/SharpCompress/Archives/IWritableArchiveEntry.cs b/src/SharpCompress/Archives/IWritableArchiveEntry.cs index f3d5eb26..b4ed22c1 100644 --- a/src/SharpCompress/Archives/IWritableArchiveEntry.cs +++ b/src/SharpCompress/Archives/IWritableArchiveEntry.cs @@ -1,9 +1,8 @@ -using System.IO; +using System.IO; -namespace SharpCompress.Archives +namespace SharpCompress.Archives; + +internal interface IWritableArchiveEntry { - internal interface IWritableArchiveEntry - { - Stream Stream { get; } - } + Stream Stream { get; } } diff --git a/src/SharpCompress/Archives/IWritableArchiveExtensions.cs b/src/SharpCompress/Archives/IWritableArchiveExtensions.cs index 1827e9e8..e534b306 100644 --- a/src/SharpCompress/Archives/IWritableArchiveExtensions.cs +++ b/src/SharpCompress/Archives/IWritableArchiveExtensions.cs @@ -1,94 +1,91 @@ -using System; +using System; using System.IO; using SharpCompress.Writers; -namespace SharpCompress.Archives +namespace SharpCompress.Archives; + +public static class IWritableArchiveExtensions { - public static class IWritableArchiveExtensions + public static void AddEntry( + this IWritableArchive writableArchive, + string entryPath, + string filePath + ) { - public static void AddEntry( - this IWritableArchive writableArchive, - string entryPath, - string filePath - ) + var fileInfo = new FileInfo(filePath); + if (!fileInfo.Exists) { - var fileInfo = new FileInfo(filePath); - if (!fileInfo.Exists) - { - throw new FileNotFoundException("Could not AddEntry: " + filePath); - } - writableArchive.AddEntry( - entryPath, - new FileInfo(filePath).OpenRead(), - true, - fileInfo.Length, - fileInfo.LastWriteTime - ); + throw new FileNotFoundException("Could not AddEntry: " + filePath); } + writableArchive.AddEntry( + entryPath, + new FileInfo(filePath).OpenRead(), + true, + fileInfo.Length, + fileInfo.LastWriteTime + ); + } - public static void SaveTo( - this IWritableArchive writableArchive, - string filePath, - WriterOptions options - ) - { - writableArchive.SaveTo(new FileInfo(filePath), options); - } + public static void SaveTo( + this IWritableArchive writableArchive, + string filePath, + WriterOptions options + ) + { + writableArchive.SaveTo(new FileInfo(filePath), options); + } - public static void SaveTo( - this IWritableArchive writableArchive, - FileInfo fileInfo, - WriterOptions options - ) + public static void SaveTo( + this IWritableArchive writableArchive, + FileInfo fileInfo, + WriterOptions options + ) + { + using var stream = fileInfo.Open(FileMode.Create, FileAccess.Write); + writableArchive.SaveTo(stream, options); + } + + public static void AddAllFromDirectory( + this IWritableArchive writableArchive, + string filePath, + string searchPattern = "*.*", + SearchOption searchOption = SearchOption.AllDirectories + ) + { + using (writableArchive.PauseEntryRebuilding()) { - using (var stream = fileInfo.Open(FileMode.Create, FileAccess.Write)) + foreach ( + var path in Directory.EnumerateFiles(filePath, searchPattern, searchOption) + ) { - writableArchive.SaveTo(stream, options); + var fileInfo = new FileInfo(path); + writableArchive.AddEntry( + path.Substring(filePath.Length), + fileInfo.OpenRead(), + true, + fileInfo.Length, + fileInfo.LastWriteTime + ); } } - - public static void AddAllFromDirectory( - this IWritableArchive writableArchive, - string filePath, - string searchPattern = "*.*", - SearchOption searchOption = SearchOption.AllDirectories - ) - { - using (writableArchive.PauseEntryRebuilding()) - { - foreach ( - var path in Directory.EnumerateFiles(filePath, searchPattern, searchOption) - ) - { - var fileInfo = new FileInfo(path); - writableArchive.AddEntry( - path.Substring(filePath.Length), - fileInfo.OpenRead(), - true, - fileInfo.Length, - fileInfo.LastWriteTime - ); - } - } - } - - public static IArchiveEntry AddEntry( - this IWritableArchive writableArchive, - string key, - FileInfo fileInfo - ) - { - if (!fileInfo.Exists) - { - throw new ArgumentException("FileInfo does not exist."); - } - return writableArchive.AddEntry( - key, - fileInfo.OpenRead(), - true, - fileInfo.Length, - fileInfo.LastWriteTime - ); - } + } + + public static IArchiveEntry AddEntry( + this IWritableArchive writableArchive, + string key, + FileInfo fileInfo + ) + { + if (!fileInfo.Exists) + { + throw new ArgumentException("FileInfo does not exist."); + } + return writableArchive.AddEntry( + key, + fileInfo.OpenRead(), + true, + fileInfo.Length, + fileInfo.LastWriteTime + ); } } diff --git a/src/SharpCompress/Archives/IWriteableArchiveFactory.cs b/src/SharpCompress/Archives/IWriteableArchiveFactory.cs index 59c58134..4fae9f55 100644 --- a/src/SharpCompress/Archives/IWriteableArchiveFactory.cs +++ b/src/SharpCompress/Archives/IWriteableArchiveFactory.cs @@ -1,27 +1,20 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace SharpCompress.Archives; -namespace SharpCompress.Archives +/// +/// Decorator for used to declare an archive format as able to create writeable archives +/// +/// +/// Implemented by:
+/// +/// +/// +/// +/// +public interface IWriteableArchiveFactory : Factories.IFactory { /// - /// Decorator for used to declare an archive format as able to create writeable archives + /// Creates a new, empty archive, ready to be written. /// - /// - /// Implemented by:
- /// - /// - /// - /// - /// - public interface IWriteableArchiveFactory : Factories.IFactory - { - /// - /// Creates a new, empty archive, ready to be written. - /// - /// - IWritableArchive CreateWriteableArchive(); - } + /// + IWritableArchive CreateWriteableArchive(); } diff --git a/src/SharpCompress/Archives/Rar/FileInfoRarArchiveVolume.cs b/src/SharpCompress/Archives/Rar/FileInfoRarArchiveVolume.cs index 78ec29e8..0f1acd3f 100644 --- a/src/SharpCompress/Archives/Rar/FileInfoRarArchiveVolume.cs +++ b/src/SharpCompress/Archives/Rar/FileInfoRarArchiveVolume.cs @@ -6,45 +6,44 @@ using SharpCompress.Common.Rar.Headers; using SharpCompress.IO; using SharpCompress.Readers; -namespace SharpCompress.Archives.Rar +namespace SharpCompress.Archives.Rar; + +/// +/// A rar part based on a FileInfo object +/// +internal class FileInfoRarArchiveVolume : RarVolume { - /// - /// A rar part based on a FileInfo object - /// - internal class FileInfoRarArchiveVolume : RarVolume + internal FileInfoRarArchiveVolume(FileInfo fileInfo, ReaderOptions options, int index = 0) + : base(StreamingMode.Seekable, fileInfo.OpenRead(), FixOptions(options), index) { - internal FileInfoRarArchiveVolume(FileInfo fileInfo, ReaderOptions options, int index = 0) - : base(StreamingMode.Seekable, fileInfo.OpenRead(), FixOptions(options), index) - { - FileInfo = fileInfo; - FileParts = GetVolumeFileParts().ToArray().ToReadOnly(); - } + FileInfo = fileInfo; + FileParts = GetVolumeFileParts().ToArray().ToReadOnly(); + } - private static ReaderOptions FixOptions(ReaderOptions options) - { - //make sure we're closing streams with fileinfo - options.LeaveStreamOpen = false; - return options; - } + private static ReaderOptions FixOptions(ReaderOptions options) + { + //make sure we're closing streams with fileinfo + options.LeaveStreamOpen = false; + return options; + } - internal ReadOnlyCollection FileParts { get; } + internal ReadOnlyCollection FileParts { get; } - internal FileInfo FileInfo { get; } + internal FileInfo FileInfo { get; } - internal override RarFilePart CreateFilePart(MarkHeader markHeader, FileHeader fileHeader) - { - return new FileInfoRarFilePart( - this, - ReaderOptions.Password, - markHeader, - fileHeader, - FileInfo - ); - } + internal override RarFilePart CreateFilePart(MarkHeader markHeader, FileHeader fileHeader) + { + return new FileInfoRarFilePart( + this, + ReaderOptions.Password, + markHeader, + fileHeader, + FileInfo + ); + } - internal override IEnumerable ReadFileParts() - { - return FileParts; - } + internal override IEnumerable ReadFileParts() + { + return FileParts; } } diff --git a/src/SharpCompress/Archives/Rar/FileInfoRarFilePart.cs b/src/SharpCompress/Archives/Rar/FileInfoRarFilePart.cs index 1908c8af..59a21334 100644 --- a/src/SharpCompress/Archives/Rar/FileInfoRarFilePart.cs +++ b/src/SharpCompress/Archives/Rar/FileInfoRarFilePart.cs @@ -1,26 +1,25 @@ using System.IO; using SharpCompress.Common.Rar.Headers; -namespace SharpCompress.Archives.Rar +namespace SharpCompress.Archives.Rar; + +internal sealed class FileInfoRarFilePart : SeekableFilePart { - internal sealed class FileInfoRarFilePart : SeekableFilePart + internal FileInfoRarFilePart( + FileInfoRarArchiveVolume volume, + string? password, + MarkHeader mh, + FileHeader fh, + FileInfo fi + ) : base(mh, fh, volume.Index, volume.Stream, password) { - internal FileInfoRarFilePart( - FileInfoRarArchiveVolume volume, - string? password, - MarkHeader mh, - FileHeader fh, - FileInfo fi - ) : base(mh, fh, volume.Index, volume.Stream, password) - { - FileInfo = fi; - } + FileInfo = fi; + } - internal FileInfo FileInfo { get; } + internal FileInfo FileInfo { get; } - internal override string FilePartName - { - get { return "Rar File: " + FileInfo.FullName + " File Entry: " + FileHeader.FileName; } - } + internal override string FilePartName + { + get { return "Rar File: " + FileInfo.FullName + " File Entry: " + FileHeader.FileName; } } } diff --git a/src/SharpCompress/Archives/Rar/RarArchive.Extensions.cs b/src/SharpCompress/Archives/Rar/RarArchive.Extensions.cs index 41abe3f4..b0edf3f5 100644 --- a/src/SharpCompress/Archives/Rar/RarArchive.Extensions.cs +++ b/src/SharpCompress/Archives/Rar/RarArchive.Extensions.cs @@ -1,23 +1,22 @@ -using System.Linq; +using System.Linq; -namespace SharpCompress.Archives.Rar +namespace SharpCompress.Archives.Rar; + +public static class RarArchiveExtensions { - public static class RarArchiveExtensions + /// + /// RarArchive is the first volume of a multi-part archive. If MultipartVolume is true and IsFirstVolume is false then the first volume file must be missing. + /// + public static bool IsFirstVolume(this RarArchive archive) { - /// - /// RarArchive is the first volume of a multi-part archive. If MultipartVolume is true and IsFirstVolume is false then the first volume file must be missing. - /// - public static bool IsFirstVolume(this RarArchive archive) - { - return archive.Volumes.First().IsFirstVolume; - } + return archive.Volumes.First().IsFirstVolume; + } - /// - /// RarArchive is part of a multi-part archive. - /// - public static bool IsMultipartVolume(this RarArchive archive) - { - return archive.Volumes.First().IsMultiVolume; - } + /// + /// RarArchive is part of a multi-part archive. + /// + public static bool IsMultipartVolume(this RarArchive archive) + { + return archive.Volumes.First().IsMultiVolume; } } diff --git a/src/SharpCompress/Archives/Rar/RarArchive.cs b/src/SharpCompress/Archives/Rar/RarArchive.cs index 67a4d070..dad32f3c 100644 --- a/src/SharpCompress/Archives/Rar/RarArchive.cs +++ b/src/SharpCompress/Archives/Rar/RarArchive.cs @@ -9,179 +9,178 @@ using SharpCompress.IO; using SharpCompress.Readers; using SharpCompress.Readers.Rar; -namespace SharpCompress.Archives.Rar +namespace SharpCompress.Archives.Rar; + +public class RarArchive : AbstractArchive { - 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()); + + /// + /// Constructor with a SourceStream able to handle FileInfo and Streams. + /// + /// + /// + internal RarArchive(SourceStream srcStream) : base(ArchiveType.Rar, srcStream) { } + + protected override IEnumerable LoadEntries(IEnumerable volumes) { - internal Lazy UnpackV2017 { get; } = - new Lazy(() => new SharpCompress.Compressors.Rar.UnpackV2017.Unpack()); - internal Lazy UnpackV1 { get; } = - new Lazy(() => new SharpCompress.Compressors.Rar.UnpackV1.Unpack()); - - /// - /// Constructor with a SourceStream able to handle FileInfo and Streams. - /// - /// - /// - internal RarArchive(SourceStream srcStream) : base(ArchiveType.Rar, srcStream) { } - - protected override IEnumerable LoadEntries(IEnumerable volumes) - { - return RarArchiveEntryFactory.GetEntries(this, volumes, ReaderOptions); - } - - protected override IEnumerable LoadVolumes(SourceStream srcStream) - { - base.SrcStream.LoadAllParts(); //request all streams - Stream[] streams = base.SrcStream.Streams.ToArray(); - int idx = 0; - if (streams.Length > 1 && IsRarFile(streams[1], ReaderOptions)) //test part 2 - true = multipart not split - { - base.SrcStream.IsVolumes = true; - streams[1].Position = 0; - base.SrcStream.Position = 0; - - return srcStream.Streams.Select( - a => new StreamRarArchiveVolume(a, ReaderOptions, idx++) - ); - } - else //split mode or single file - return new StreamRarArchiveVolume(base.SrcStream, ReaderOptions, idx++).AsEnumerable(); - } - - protected override IReader CreateReaderForSolidExtraction() - { - var stream = Volumes.First().Stream; - stream.Position = 0; - return RarReader.Open(stream, ReaderOptions); - } - - public override bool IsSolid => Volumes.First().IsSolidArchive; - - public virtual int MinVersion => Volumes.First().MinVersion; - public virtual int MaxVersion => Volumes.First().MaxVersion; - - #region Creation - /// - /// Constructor with a FileInfo object to an existing file. - /// - /// - /// - public static RarArchive Open(string filePath, ReaderOptions? options = null) - { - filePath.CheckNotNullOrEmpty(nameof(filePath)); - FileInfo fileInfo = new FileInfo(filePath); - return new RarArchive( - new SourceStream( - fileInfo, - i => RarArchiveVolumeFactory.GetFilePart(i, fileInfo), - options ?? new ReaderOptions() - ) - ); - } - - /// - /// Constructor with a FileInfo object to an existing file. - /// - /// - /// - public static RarArchive Open(FileInfo fileInfo, ReaderOptions? options = null) - { - fileInfo.CheckNotNull(nameof(fileInfo)); - return new RarArchive( - new SourceStream( - fileInfo, - i => RarArchiveVolumeFactory.GetFilePart(i, fileInfo), - options ?? new ReaderOptions() - ) - ); - } - - /// - /// Takes a seekable Stream as a source - /// - /// - /// - public static RarArchive Open(Stream stream, ReaderOptions? options = null) - { - stream.CheckNotNull(nameof(stream)); - return new RarArchive( - new SourceStream(stream, i => null, options ?? new ReaderOptions()) - ); - } - - /// - /// Constructor with all file parts passed in - /// - /// - /// - public static RarArchive Open( - IEnumerable fileInfos, - ReaderOptions? readerOptions = null - ) - { - fileInfos.CheckNotNull(nameof(fileInfos)); - FileInfo[] files = fileInfos.ToArray(); - return new RarArchive( - new SourceStream( - files[0], - i => i < files.Length ? files[i] : null, - readerOptions ?? new ReaderOptions() - ) - ); - } - - /// - /// Constructor with all stream parts passed in - /// - /// - /// - public static RarArchive Open( - IEnumerable streams, - ReaderOptions? readerOptions = null - ) - { - streams.CheckNotNull(nameof(streams)); - Stream[] strms = streams.ToArray(); - return new RarArchive( - new SourceStream( - strms[0], - i => i < strms.Length ? strms[i] : null, - readerOptions ?? new ReaderOptions() - ) - ); - } - - public static bool IsRarFile(string filePath) - { - return IsRarFile(new FileInfo(filePath)); - } - - public static bool IsRarFile(FileInfo fileInfo) - { - if (!fileInfo.Exists) - { - return false; - } - using (Stream stream = fileInfo.OpenRead()) - { - return IsRarFile(stream); - } - } - - public static bool IsRarFile(Stream stream, ReaderOptions? options = null) - { - try - { - MarkHeader.Read(stream, true, false); - return true; - } - catch - { - return false; - } - } - - #endregion + return RarArchiveEntryFactory.GetEntries(this, volumes, ReaderOptions); } + + protected override IEnumerable LoadVolumes(SourceStream srcStream) + { + SrcStream.LoadAllParts(); //request all streams + var streams = SrcStream.Streams.ToArray(); + var idx = 0; + if (streams.Length > 1 && IsRarFile(streams[1], ReaderOptions)) //test part 2 - true = multipart not split + { + SrcStream.IsVolumes = true; + streams[1].Position = 0; + SrcStream.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(); + } + } + + protected override IReader CreateReaderForSolidExtraction() + { + var stream = Volumes.First().Stream; + stream.Position = 0; + return RarReader.Open(stream, ReaderOptions); + } + + public override bool IsSolid => Volumes.First().IsSolidArchive; + + public virtual int MinVersion => Volumes.First().MinVersion; + public virtual int MaxVersion => Volumes.First().MaxVersion; + + #region Creation + /// + /// Constructor with a FileInfo object to an existing file. + /// + /// + /// + public static RarArchive Open(string filePath, ReaderOptions? options = null) + { + filePath.CheckNotNullOrEmpty(nameof(filePath)); + var fileInfo = new FileInfo(filePath); + return new RarArchive( + new SourceStream( + fileInfo, + i => RarArchiveVolumeFactory.GetFilePart(i, fileInfo), + options ?? new ReaderOptions() + ) + ); + } + + /// + /// Constructor with a FileInfo object to an existing file. + /// + /// + /// + public static RarArchive Open(FileInfo fileInfo, ReaderOptions? options = null) + { + fileInfo.CheckNotNull(nameof(fileInfo)); + return new RarArchive( + new SourceStream( + fileInfo, + i => RarArchiveVolumeFactory.GetFilePart(i, fileInfo), + options ?? new ReaderOptions() + ) + ); + } + + /// + /// Takes a seekable Stream as a source + /// + /// + /// + public static RarArchive Open(Stream stream, ReaderOptions? options = null) + { + stream.CheckNotNull(nameof(stream)); + return new RarArchive( + new SourceStream(stream, i => null, options ?? new ReaderOptions()) + ); + } + + /// + /// Constructor with all file parts passed in + /// + /// + /// + public static RarArchive Open( + IEnumerable fileInfos, + ReaderOptions? readerOptions = null + ) + { + fileInfos.CheckNotNull(nameof(fileInfos)); + var files = fileInfos.ToArray(); + return new RarArchive( + new SourceStream( + files[0], + i => i < files.Length ? files[i] : null, + readerOptions ?? new ReaderOptions() + ) + ); + } + + /// + /// Constructor with all stream parts passed in + /// + /// + /// + public static RarArchive Open( + IEnumerable streams, + ReaderOptions? readerOptions = null + ) + { + streams.CheckNotNull(nameof(streams)); + var strms = streams.ToArray(); + return new RarArchive( + new SourceStream( + strms[0], + i => i < strms.Length ? strms[i] : null, + readerOptions ?? new ReaderOptions() + ) + ); + } + + public static bool IsRarFile(string filePath) + { + return IsRarFile(new FileInfo(filePath)); + } + + public static bool IsRarFile(FileInfo fileInfo) + { + if (!fileInfo.Exists) + { + return false; + } + using Stream stream = fileInfo.OpenRead(); + return IsRarFile(stream); + } + + public static bool IsRarFile(Stream stream, ReaderOptions? options = null) + { + try + { + MarkHeader.Read(stream, true, false); + return true; + } + catch + { + return false; + } + } + + #endregion } diff --git a/src/SharpCompress/Archives/Rar/RarArchiveEntry.cs b/src/SharpCompress/Archives/Rar/RarArchiveEntry.cs index a5f4d038..5885210a 100644 --- a/src/SharpCompress/Archives/Rar/RarArchiveEntry.cs +++ b/src/SharpCompress/Archives/Rar/RarArchiveEntry.cs @@ -1,4 +1,3 @@ -using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -8,96 +7,95 @@ using SharpCompress.Common.Rar.Headers; using SharpCompress.Compressors.Rar; using SharpCompress.Readers; -namespace SharpCompress.Archives.Rar +namespace SharpCompress.Archives.Rar; + +public class RarArchiveEntry : RarEntry, IArchiveEntry { - public class RarArchiveEntry : RarEntry, IArchiveEntry + private readonly ICollection parts; + private readonly RarArchive archive; + private readonly ReaderOptions readerOptions; + + internal RarArchiveEntry( + RarArchive archive, + IEnumerable parts, + ReaderOptions readerOptions + ) { - private readonly ICollection parts; - private readonly RarArchive archive; - private readonly ReaderOptions readerOptions; + this.parts = parts.ToList(); + this.archive = archive; + this.readerOptions = readerOptions; + IsSolid = FileHeader.IsSolid; + } - internal RarArchiveEntry( - RarArchive archive, - IEnumerable parts, - ReaderOptions readerOptions - ) + public override CompressionType CompressionType => CompressionType.Rar; + + public IArchive Archive => archive; + + internal override IEnumerable Parts => parts.Cast(); + + internal override FileHeader FileHeader => parts.First().FileHeader; + + public override long Crc + { + get { - this.parts = parts.ToList(); - this.archive = archive; - this.readerOptions = readerOptions; - this.IsSolid = this.FileHeader.IsSolid; + CheckIncomplete(); + return parts.Select(fp => fp.FileHeader).Single(fh => !fh.IsSplitAfter).FileCrc; } + } - public override CompressionType CompressionType => CompressionType.Rar; - - public IArchive Archive => archive; - - internal override IEnumerable Parts => parts.Cast(); - - internal override FileHeader FileHeader => parts.First().FileHeader; - - public override long Crc + public override long Size + { + get { - get - { - CheckIncomplete(); - return parts.Select(fp => fp.FileHeader).Single(fh => !fh.IsSplitAfter).FileCrc; - } + CheckIncomplete(); + return parts.First().FileHeader.UncompressedSize; } + } - public override long Size + public override long CompressedSize + { + get { - get - { - CheckIncomplete(); - return parts.First().FileHeader.UncompressedSize; - } + CheckIncomplete(); + return parts.Aggregate(0L, (total, fp) => total + fp.FileHeader.CompressedSize); } + } - public override long CompressedSize + public Stream OpenEntryStream() + { + if (IsRarV3) { - get - { - CheckIncomplete(); - return parts.Aggregate(0L, (total, fp) => total + fp.FileHeader.CompressedSize); - } - } - - public Stream OpenEntryStream() - { - if (IsRarV3) - { - return new RarStream( - archive.UnpackV1.Value, - FileHeader, - new MultiVolumeReadOnlyStream(Parts.Cast(), archive) - ); - } - return new RarStream( - archive.UnpackV2017.Value, + archive.UnpackV1.Value, FileHeader, new MultiVolumeReadOnlyStream(Parts.Cast(), archive) ); } - public bool IsComplete - { - get - { - var headers = parts.Select(x => x.FileHeader); - return !headers.First().IsSplitBefore && !headers.Last().IsSplitAfter; - } - } + return new RarStream( + archive.UnpackV2017.Value, + FileHeader, + new MultiVolumeReadOnlyStream(Parts.Cast(), archive) + ); + } - private void CheckIncomplete() + public bool IsComplete + { + get { - if (!readerOptions.DisableCheckIncomplete && !IsComplete) - { - throw new IncompleteArchiveException( - "ArchiveEntry is incomplete and cannot perform this operation." - ); - } + var headers = parts.Select(x => x.FileHeader); + return !headers.First().IsSplitBefore && !headers.Last().IsSplitAfter; + } + } + + private void CheckIncomplete() + { + if (!readerOptions.DisableCheckIncomplete && !IsComplete) + { + throw new IncompleteArchiveException( + "ArchiveEntry is incomplete and cannot perform this operation." + ); } } } diff --git a/src/SharpCompress/Archives/Rar/RarArchiveEntryFactory.cs b/src/SharpCompress/Archives/Rar/RarArchiveEntryFactory.cs index e345e8d3..ec4ace7c 100644 --- a/src/SharpCompress/Archives/Rar/RarArchiveEntryFactory.cs +++ b/src/SharpCompress/Archives/Rar/RarArchiveEntryFactory.cs @@ -1,53 +1,52 @@ -using System.Collections.Generic; +using System.Collections.Generic; using SharpCompress.Common.Rar; using SharpCompress.Readers; -namespace SharpCompress.Archives.Rar +namespace SharpCompress.Archives.Rar; + +internal static class RarArchiveEntryFactory { - internal static class RarArchiveEntryFactory + private static IEnumerable GetFileParts(IEnumerable parts) { - private static IEnumerable GetFileParts(IEnumerable parts) + foreach (var rarPart in parts) { - foreach (RarVolume rarPart in parts) + foreach (var fp in rarPart.ReadFileParts()) { - foreach (RarFilePart fp in rarPart.ReadFileParts()) - { - yield return fp; - } - } - } - - private static IEnumerable> GetMatchedFileParts( - IEnumerable parts - ) - { - var groupedParts = new List(); - foreach (RarFilePart fp in GetFileParts(parts)) - { - groupedParts.Add(fp); - - if (!fp.FileHeader.IsSplitAfter) - { - yield return groupedParts; - groupedParts = new List(); - } - } - if (groupedParts.Count > 0) - { - yield return groupedParts; - } - } - - internal static IEnumerable GetEntries( - RarArchive archive, - IEnumerable rarParts, - ReaderOptions readerOptions - ) - { - foreach (var groupedParts in GetMatchedFileParts(rarParts)) - { - yield return new RarArchiveEntry(archive, groupedParts, readerOptions); + yield return fp; } } } + + private static IEnumerable> GetMatchedFileParts( + IEnumerable parts + ) + { + var groupedParts = new List(); + foreach (var fp in GetFileParts(parts)) + { + groupedParts.Add(fp); + + if (!fp.FileHeader.IsSplitAfter) + { + yield return groupedParts; + groupedParts = new List(); + } + } + if (groupedParts.Count > 0) + { + yield return groupedParts; + } + } + + internal static IEnumerable GetEntries( + RarArchive archive, + IEnumerable rarParts, + ReaderOptions readerOptions + ) + { + foreach (var groupedParts in GetMatchedFileParts(rarParts)) + { + yield return new RarArchiveEntry(archive, groupedParts, readerOptions); + } + } } diff --git a/src/SharpCompress/Archives/Rar/SeekableFilePart.cs b/src/SharpCompress/Archives/Rar/SeekableFilePart.cs index 601c9788..9f27b674 100644 --- a/src/SharpCompress/Archives/Rar/SeekableFilePart.cs +++ b/src/SharpCompress/Archives/Rar/SeekableFilePart.cs @@ -2,36 +2,35 @@ using System.IO; using SharpCompress.Common.Rar; using SharpCompress.Common.Rar.Headers; -namespace SharpCompress.Archives.Rar +namespace SharpCompress.Archives.Rar; + +internal class SeekableFilePart : RarFilePart { - internal class SeekableFilePart : RarFilePart + private readonly Stream stream; + private readonly string? password; + + internal SeekableFilePart( + MarkHeader mh, + FileHeader fh, + int index, + Stream stream, + string? password + ) : base(mh, fh, index) { - private readonly Stream stream; - private readonly string? password; - - internal SeekableFilePart( - MarkHeader mh, - FileHeader fh, - int index, - Stream stream, - string? password - ) : base(mh, fh, index) - { - this.stream = stream; - this.password = password; - } - - internal override Stream GetCompressedStream() - { - stream.Position = FileHeader.DataStartPosition; - if (FileHeader.R4Salt != null) - { - return new RarCryptoWrapper(stream, password!, FileHeader.R4Salt); - } - return stream; - } - - internal override string FilePartName => - "Unknown Stream - File Entry: " + FileHeader.FileName; + this.stream = stream; + this.password = password; } + + internal override Stream GetCompressedStream() + { + stream.Position = FileHeader.DataStartPosition; + if (FileHeader.R4Salt != null) + { + return new RarCryptoWrapper(stream, password!, FileHeader.R4Salt); + } + 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 ac5dc5de..6d388746 100644 --- a/src/SharpCompress/Archives/Rar/StreamRarArchiveVolume.cs +++ b/src/SharpCompress/Archives/Rar/StreamRarArchiveVolume.cs @@ -5,27 +5,26 @@ using SharpCompress.Common.Rar.Headers; using SharpCompress.IO; using SharpCompress.Readers; -namespace SharpCompress.Archives.Rar +namespace SharpCompress.Archives.Rar; + +internal class StreamRarArchiveVolume : RarVolume { - internal class StreamRarArchiveVolume : RarVolume + internal StreamRarArchiveVolume(Stream stream, ReaderOptions options, int index = 0) + : base(StreamingMode.Seekable, stream, options, index) { } + + internal override IEnumerable ReadFileParts() { - internal StreamRarArchiveVolume(Stream stream, ReaderOptions options, int index = 0) - : base(StreamingMode.Seekable, stream, options, index) { } + return GetVolumeFileParts(); + } - internal override IEnumerable ReadFileParts() - { - return GetVolumeFileParts(); - } - - internal override RarFilePart CreateFilePart(MarkHeader markHeader, FileHeader fileHeader) - { - return new SeekableFilePart( - markHeader, - fileHeader, - this.Index, - Stream, - ReaderOptions.Password - ); - } + internal override RarFilePart CreateFilePart(MarkHeader markHeader, FileHeader fileHeader) + { + return new SeekableFilePart( + markHeader, + fileHeader, + Index, + Stream, + ReaderOptions.Password + ); } } diff --git a/src/SharpCompress/Archives/SevenZip/SevenZipArchive.cs b/src/SharpCompress/Archives/SevenZip/SevenZipArchive.cs index 99c455d7..870de6b2 100644 --- a/src/SharpCompress/Archives/SevenZip/SevenZipArchive.cs +++ b/src/SharpCompress/Archives/SevenZip/SevenZipArchive.cs @@ -10,281 +10,278 @@ using SharpCompress.Compressors.LZMA.Utilites; using SharpCompress.IO; using SharpCompress.Readers; -namespace SharpCompress.Archives.SevenZip +namespace SharpCompress.Archives.SevenZip; + +public class SevenZipArchive : AbstractArchive { - public class SevenZipArchive : AbstractArchive + private ArchiveDatabase database; + + /// + /// Constructor expects a filepath to an existing file. + /// + /// + /// + public static SevenZipArchive Open(string filePath, ReaderOptions readerOptions = null) { - private ArchiveDatabase database; + filePath.CheckNotNullOrEmpty("filePath"); + return Open(new FileInfo(filePath), readerOptions ?? new ReaderOptions()); + } - /// - /// Constructor expects a filepath to an existing file. - /// - /// - /// - public static SevenZipArchive Open(string filePath, ReaderOptions readerOptions = null) + /// + /// Constructor with a FileInfo object to an existing file. + /// + /// + /// + public static SevenZipArchive Open(FileInfo fileInfo, ReaderOptions readerOptions = null) + { + fileInfo.CheckNotNull("fileInfo"); + return new SevenZipArchive( + new SourceStream( + fileInfo, + i => ArchiveVolumeFactory.GetFilePart(i, fileInfo), + readerOptions ?? new ReaderOptions() + ) + ); + } + + /// + /// Constructor with all file parts passed in + /// + /// + /// + public static SevenZipArchive Open( + IEnumerable fileInfos, + ReaderOptions readerOptions = null + ) + { + fileInfos.CheckNotNull(nameof(fileInfos)); + var files = fileInfos.ToArray(); + return new SevenZipArchive( + new SourceStream( + files[0], + i => i < files.Length ? files[i] : null, + readerOptions ?? new ReaderOptions() + ) + ); + } + + /// + /// Constructor with all stream parts passed in + /// + /// + /// + public static SevenZipArchive Open( + IEnumerable streams, + ReaderOptions readerOptions = null + ) + { + streams.CheckNotNull(nameof(streams)); + var strms = streams.ToArray(); + return new SevenZipArchive( + new SourceStream( + strms[0], + i => i < strms.Length ? strms[i] : null, + readerOptions ?? new ReaderOptions() + ) + ); + } + + /// + /// Takes a seekable Stream as a source + /// + /// + /// + public static SevenZipArchive Open(Stream stream, ReaderOptions readerOptions = null) + { + stream.CheckNotNull("stream"); + return new SevenZipArchive( + new SourceStream(stream, i => null, readerOptions ?? new ReaderOptions()) + ); + } + + /// + /// Constructor with a SourceStream able to handle FileInfo and Streams. + /// + /// + /// + internal SevenZipArchive(SourceStream srcStream) : base(ArchiveType.SevenZip, srcStream) { } + + protected override IEnumerable LoadVolumes(SourceStream srcStream) + { + SrcStream.LoadAllParts(); //request all streams + var idx = 0; + return new SevenZipVolume(srcStream, ReaderOptions, idx++).AsEnumerable(); //simple single volume or split, multivolume not supported + } + + public static bool IsSevenZipFile(string filePath) + { + return IsSevenZipFile(new FileInfo(filePath)); + } + + public static bool IsSevenZipFile(FileInfo fileInfo) + { + if (!fileInfo.Exists) { - filePath.CheckNotNullOrEmpty("filePath"); - return Open(new FileInfo(filePath), readerOptions ?? new ReaderOptions()); + return false; } + using Stream stream = fileInfo.OpenRead(); + return IsSevenZipFile(stream); + } - /// - /// Constructor with a FileInfo object to an existing file. - /// - /// - /// - public static SevenZipArchive Open(FileInfo fileInfo, ReaderOptions readerOptions = null) + internal SevenZipArchive() : base(ArchiveType.SevenZip) { } + + protected override IEnumerable LoadEntries( + IEnumerable volumes + ) + { + var stream = volumes.Single().Stream; + LoadFactory(stream); + var entries = new SevenZipArchiveEntry[database._files.Count]; + for (var i = 0; i < database._files.Count; i++) { - fileInfo.CheckNotNull("fileInfo"); - return new SevenZipArchive( - new SourceStream( - fileInfo, - i => ArchiveVolumeFactory.GetFilePart(i, fileInfo), - readerOptions ?? new ReaderOptions() - ) + var file = database._files[i]; + entries[i] = new SevenZipArchiveEntry( + this, + new SevenZipFilePart(stream, database, i, file, ReaderOptions.ArchiveEncoding) ); } - - /// - /// Constructor with all file parts passed in - /// - /// - /// - public static SevenZipArchive Open( - IEnumerable fileInfos, - ReaderOptions readerOptions = null + foreach ( + var group in entries.Where(x => !x.IsDirectory).GroupBy(x => x.FilePart.Folder) ) { - fileInfos.CheckNotNull(nameof(fileInfos)); - FileInfo[] files = fileInfos.ToArray(); - return new SevenZipArchive( - new SourceStream( - files[0], - i => i < files.Length ? files[i] : null, - readerOptions ?? new ReaderOptions() - ) - ); - } - - /// - /// Constructor with all stream parts passed in - /// - /// - /// - public static SevenZipArchive Open( - IEnumerable streams, - ReaderOptions readerOptions = null - ) - { - streams.CheckNotNull(nameof(streams)); - Stream[] strms = streams.ToArray(); - return new SevenZipArchive( - new SourceStream( - strms[0], - i => i < strms.Length ? strms[i] : null, - readerOptions ?? new ReaderOptions() - ) - ); - } - - /// - /// Takes a seekable Stream as a source - /// - /// - /// - public static SevenZipArchive Open(Stream stream, ReaderOptions readerOptions = null) - { - stream.CheckNotNull("stream"); - return new SevenZipArchive( - new SourceStream(stream, i => null, readerOptions ?? new ReaderOptions()) - ); - } - - /// - /// Constructor with a SourceStream able to handle FileInfo and Streams. - /// - /// - /// - internal SevenZipArchive(SourceStream srcStream) : base(ArchiveType.SevenZip, srcStream) { } - - protected override IEnumerable LoadVolumes(SourceStream srcStream) - { - base.SrcStream.LoadAllParts(); //request all streams - int idx = 0; - return new SevenZipVolume(srcStream, ReaderOptions, idx++).AsEnumerable(); //simple single volume or split, multivolume not supported - } - - public static bool IsSevenZipFile(string filePath) - { - return IsSevenZipFile(new FileInfo(filePath)); - } - - public static bool IsSevenZipFile(FileInfo fileInfo) - { - if (!fileInfo.Exists) + var isSolid = false; + foreach (var entry in group) { - return false; - } - using (Stream stream = fileInfo.OpenRead()) - { - return IsSevenZipFile(stream); + entry.IsSolid = isSolid; + isSolid = true; //mark others in this group as solid - same as rar behaviour. } } - internal SevenZipArchive() : base(ArchiveType.SevenZip) { } + return entries; + } - protected override IEnumerable LoadEntries( - IEnumerable volumes - ) + private void LoadFactory(Stream stream) + { + if (database is null) { - var stream = volumes.Single().Stream; - LoadFactory(stream); - var entries = new SevenZipArchiveEntry[database._files.Count]; - for (int i = 0; i < database._files.Count; i++) + stream.Position = 0; + var reader = new ArchiveReader(); + reader.Open(stream); + database = reader.ReadDatabase(new PasswordProvider(ReaderOptions.Password)); + } + } + + public static bool IsSevenZipFile(Stream stream) + { + try + { + return SignatureMatch(stream); + } + catch + { + return false; + } + } + + 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); + } + + protected override IReader CreateReaderForSolidExtraction() + { + return new SevenZipReader(ReaderOptions, this); + } + + public override bool IsSolid + { + get + { + return 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); + } + } + + private sealed class SevenZipReader : AbstractReader + { + 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; + } + + public override SevenZipVolume Volume => archive.Volumes.Single(); + + protected override IEnumerable GetEntries(Stream stream) + { + var entries = archive.Entries.ToList(); + stream.Position = 0; + foreach (var dir in entries.Where(x => x.IsDirectory)) { - var file = database._files[i]; - entries[i] = new SevenZipArchiveEntry( - this, - new SevenZipFilePart(stream, database, i, file, ReaderOptions.ArchiveEncoding) - ); + yield return dir; } foreach ( var group in entries.Where(x => !x.IsDirectory).GroupBy(x => x.FilePart.Folder) ) { - var isSolid = false; + currentFolder = group.Key; + if (group.Key is null) + { + currentStream = Stream.Null; + } + else + { + currentStream = archive.database.GetFolderStream( + stream, + currentFolder, + new PasswordProvider(Options.Password) + ); + } foreach (var entry in group) { - entry.IsSolid = isSolid; - isSolid = true; //mark others in this group as solid - same as rar behaviour. + currentItem = entry.FilePart.Header; + yield return entry; } } - - return entries; } - private void LoadFactory(Stream stream) + protected override EntryStream GetEntryStream() { - if (database is null) - { - stream.Position = 0; - var reader = new ArchiveReader(); - reader.Open(stream); - database = reader.ReadDatabase(new PasswordProvider(ReaderOptions.Password)); - } + return CreateEntryStream(new ReadOnlySubStream(currentStream, currentItem.Size)); + } + } + + private class PasswordProvider : IPasswordProvider + { + private readonly string _password; + + public PasswordProvider(string password) + { + _password = password; } - public static bool IsSevenZipFile(Stream stream) + public string CryptoGetTextPassword() { - try - { - return SignatureMatch(stream); - } - catch - { - return false; - } - } - - private static ReadOnlySpan SIGNATURE => - new byte[] { (byte)'7', (byte)'z', 0xBC, 0xAF, 0x27, 0x1C }; - - private static bool SignatureMatch(Stream stream) - { - BinaryReader reader = new BinaryReader(stream); - ReadOnlySpan signatureBytes = reader.ReadBytes(6); - return signatureBytes.SequenceEqual(SIGNATURE); - } - - protected override IReader CreateReaderForSolidExtraction() - { - return new SevenZipReader(ReaderOptions, this); - } - - public override bool IsSolid - { - get - { - return Entries.Where(x => !x.IsDirectory).GroupBy(x => x.FilePart.Folder).Count() - > 1; - } - } - - public override long TotalSize - { - get - { - int i = Entries.Count; - return database._packSizes.Aggregate(0L, (total, packSize) => total + packSize); - } - } - - private sealed class SevenZipReader : AbstractReader - { - 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; - } - - public override SevenZipVolume Volume => archive.Volumes.Single(); - - protected override IEnumerable GetEntries(Stream stream) - { - List entries = archive.Entries.ToList(); - stream.Position = 0; - foreach (var dir in entries.Where(x => x.IsDirectory)) - { - yield return dir; - } - foreach ( - var group in entries.Where(x => !x.IsDirectory).GroupBy(x => x.FilePart.Folder) - ) - { - currentFolder = group.Key; - if (group.Key is null) - { - currentStream = Stream.Null; - } - else - { - currentStream = archive.database.GetFolderStream( - stream, - currentFolder, - new PasswordProvider(Options.Password) - ); - } - foreach (var entry in group) - { - currentItem = entry.FilePart.Header; - yield return entry; - } - } - } - - protected override EntryStream GetEntryStream() - { - return CreateEntryStream(new ReadOnlySubStream(currentStream, currentItem.Size)); - } - } - - private class PasswordProvider : IPasswordProvider - { - private readonly string _password; - - public PasswordProvider(string password) - { - _password = password; - } - - public string CryptoGetTextPassword() - { - return _password; - } + return _password; } } } diff --git a/src/SharpCompress/Archives/SevenZip/SevenZipArchiveEntry.cs b/src/SharpCompress/Archives/SevenZip/SevenZipArchiveEntry.cs index c276eade..9f8c9654 100644 --- a/src/SharpCompress/Archives/SevenZip/SevenZipArchiveEntry.cs +++ b/src/SharpCompress/Archives/SevenZip/SevenZipArchiveEntry.cs @@ -1,27 +1,26 @@ -using System.IO; +using System.IO; using SharpCompress.Common.SevenZip; -namespace SharpCompress.Archives.SevenZip +namespace SharpCompress.Archives.SevenZip; + +public class SevenZipArchiveEntry : SevenZipEntry, IArchiveEntry { - public class SevenZipArchiveEntry : SevenZipEntry, IArchiveEntry + internal SevenZipArchiveEntry(SevenZipArchive archive, SevenZipFilePart part) : base(part) { - internal SevenZipArchiveEntry(SevenZipArchive archive, SevenZipFilePart part) : base(part) - { - Archive = archive; - } - - public Stream OpenEntryStream() - { - return FilePart.GetCompressedStream(); - } - - public IArchive Archive { get; } - - public bool IsComplete => true; - - /// - /// This is a 7Zip Anti item - /// - public bool IsAnti => FilePart.Header.IsAnti; + Archive = archive; } + + public Stream OpenEntryStream() + { + return FilePart.GetCompressedStream(); + } + + public IArchive Archive { get; } + + public bool IsComplete => true; + + /// + /// This is a 7Zip Anti item + /// + public bool IsAnti => FilePart.Header.IsAnti; } diff --git a/src/SharpCompress/Archives/Tar/TarArchive.cs b/src/SharpCompress/Archives/Tar/TarArchive.cs index 1357660f..2870555c 100644 --- a/src/SharpCompress/Archives/Tar/TarArchive.cs +++ b/src/SharpCompress/Archives/Tar/TarArchive.cs @@ -11,248 +11,239 @@ using SharpCompress.Readers.Tar; using SharpCompress.Writers; using SharpCompress.Writers.Tar; -namespace SharpCompress.Archives.Tar +namespace SharpCompress.Archives.Tar; + +public class TarArchive : AbstractWritableArchive { - public class TarArchive : AbstractWritableArchive + /// + /// Constructor expects a filepath to an existing file. + /// + /// + /// + public static TarArchive Open(string filePath, ReaderOptions? readerOptions = null) { - /// - /// Constructor expects a filepath to an existing file. - /// - /// - /// - public static TarArchive Open(string filePath, ReaderOptions? readerOptions = null) - { - filePath.CheckNotNullOrEmpty(nameof(filePath)); - return Open(new FileInfo(filePath), readerOptions ?? new ReaderOptions()); - } + filePath.CheckNotNullOrEmpty(nameof(filePath)); + return Open(new FileInfo(filePath), readerOptions ?? new ReaderOptions()); + } - /// - /// Constructor with a FileInfo object to an existing file. - /// - /// - /// - public static TarArchive Open(FileInfo fileInfo, ReaderOptions? readerOptions = null) - { - fileInfo.CheckNotNull(nameof(fileInfo)); - return new TarArchive( - new SourceStream( - fileInfo, - i => ArchiveVolumeFactory.GetFilePart(i, fileInfo), - readerOptions ?? new ReaderOptions() - ) - ); - } + /// + /// Constructor with a FileInfo object to an existing file. + /// + /// + /// + public static TarArchive Open(FileInfo fileInfo, ReaderOptions? readerOptions = null) + { + fileInfo.CheckNotNull(nameof(fileInfo)); + return new TarArchive( + new SourceStream( + fileInfo, + i => ArchiveVolumeFactory.GetFilePart(i, fileInfo), + readerOptions ?? new ReaderOptions() + ) + ); + } - /// - /// Constructor with all file parts passed in - /// - /// - /// - public static TarArchive Open( - IEnumerable fileInfos, - ReaderOptions? readerOptions = null - ) - { - fileInfos.CheckNotNull(nameof(fileInfos)); - FileInfo[] files = fileInfos.ToArray(); - return new TarArchive( - new SourceStream( - files[0], - i => i < files.Length ? files[i] : null, - readerOptions ?? new ReaderOptions() - ) - ); - } + /// + /// Constructor with all file parts passed in + /// + /// + /// + public static TarArchive Open( + IEnumerable fileInfos, + ReaderOptions? readerOptions = null + ) + { + fileInfos.CheckNotNull(nameof(fileInfos)); + var files = fileInfos.ToArray(); + return new TarArchive( + new SourceStream( + files[0], + i => i < files.Length ? files[i] : null, + readerOptions ?? new ReaderOptions() + ) + ); + } - /// - /// Constructor with all stream parts passed in - /// - /// - /// - public static TarArchive Open( - IEnumerable streams, - ReaderOptions? readerOptions = null - ) - { - streams.CheckNotNull(nameof(streams)); - Stream[] strms = streams.ToArray(); - return new TarArchive( - new SourceStream( - strms[0], - i => i < strms.Length ? strms[i] : null, - readerOptions ?? new ReaderOptions() - ) - ); - } + /// + /// Constructor with all stream parts passed in + /// + /// + /// + public static TarArchive Open( + IEnumerable streams, + ReaderOptions? readerOptions = null + ) + { + streams.CheckNotNull(nameof(streams)); + var strms = streams.ToArray(); + return new TarArchive( + new SourceStream( + strms[0], + i => i < strms.Length ? strms[i] : null, + readerOptions ?? new ReaderOptions() + ) + ); + } - /// - /// Takes a seekable Stream as a source - /// - /// - /// - public static TarArchive Open(Stream stream, ReaderOptions? readerOptions = null) - { - stream.CheckNotNull(nameof(stream)); - return new TarArchive( - new SourceStream(stream, i => null, readerOptions ?? new ReaderOptions()) - ); - } + /// + /// Takes a seekable Stream as a source + /// + /// + /// + public static TarArchive Open(Stream stream, ReaderOptions? readerOptions = null) + { + stream.CheckNotNull(nameof(stream)); + return new TarArchive( + new SourceStream(stream, i => null, readerOptions ?? new ReaderOptions()) + ); + } - public static bool IsTarFile(string filePath) - { - return IsTarFile(new FileInfo(filePath)); - } + public static bool IsTarFile(string filePath) + { + return IsTarFile(new FileInfo(filePath)); + } - public static bool IsTarFile(FileInfo fileInfo) + public static bool IsTarFile(FileInfo fileInfo) + { + if (!fileInfo.Exists) { - if (!fileInfo.Exists) - { - return false; - } - using (Stream stream = fileInfo.OpenRead()) - { - return IsTarFile(stream); - } - } - - public static bool IsTarFile(Stream stream) - { - try - { - TarHeader tarHeader = new TarHeader(new ArchiveEncoding()); - bool readSucceeded = tarHeader.Read(new BinaryReader(stream)); - bool isEmptyArchive = - tarHeader.Name.Length == 0 - && tarHeader.Size == 0 - && Enum.IsDefined(typeof(EntryType), tarHeader.EntryType); - return readSucceeded || isEmptyArchive; - } - catch { } return false; } + using Stream stream = fileInfo.OpenRead(); + return IsTarFile(stream); + } - protected override IEnumerable LoadVolumes(SourceStream srcStream) + public static bool IsTarFile(Stream stream) + { + try { - base.SrcStream.LoadAllParts(); //request all streams - int idx = 0; - return new TarVolume(srcStream, ReaderOptions, idx++).AsEnumerable(); //simple single volume or split, multivolume not supported + var tarHeader = new TarHeader(new ArchiveEncoding()); + var readSucceeded = tarHeader.Read(new BinaryReader(stream)); + var isEmptyArchive = + tarHeader.Name.Length == 0 + && tarHeader.Size == 0 + && Enum.IsDefined(typeof(EntryType), tarHeader.EntryType); + return readSucceeded || isEmptyArchive; } + catch { } + return false; + } - /// - /// Constructor with a SourceStream able to handle FileInfo and Streams. - /// - /// - /// - internal TarArchive(SourceStream srcStream) : base(ArchiveType.Tar, srcStream) { } + protected override IEnumerable LoadVolumes(SourceStream srcStream) + { + SrcStream.LoadAllParts(); //request all streams + var idx = 0; + return new TarVolume(srcStream, ReaderOptions, idx++).AsEnumerable(); //simple single volume or split, multivolume not supported + } - internal TarArchive() : base(ArchiveType.Tar) { } + /// + /// Constructor with a SourceStream able to handle FileInfo and Streams. + /// + /// + /// + internal TarArchive(SourceStream srcStream) : base(ArchiveType.Tar, srcStream) { } - protected override IEnumerable LoadEntries(IEnumerable volumes) - { - Stream stream = volumes.Single().Stream; - TarHeader? previousHeader = null; - foreach ( - TarHeader? header in TarHeaderFactory.ReadHeader( - StreamingMode.Seekable, - stream, - ReaderOptions.ArchiveEncoding - ) + internal TarArchive() : base(ArchiveType.Tar) { } + + protected override IEnumerable LoadEntries(IEnumerable volumes) + { + var stream = volumes.Single().Stream; + TarHeader? previousHeader = null; + foreach ( + var header in TarHeaderFactory.ReadHeader( + StreamingMode.Seekable, + stream, + ReaderOptions.ArchiveEncoding ) + ) + { + if (header != null) { - if (header != null) + if (header.EntryType == EntryType.LongName) { - if (header.EntryType == EntryType.LongName) + previousHeader = header; + } + else + { + if (previousHeader != null) { - previousHeader = header; - } - else - { - if (previousHeader != null) - { - var entry = new TarArchiveEntry( - this, - new TarFilePart(previousHeader, stream), - CompressionType.None - ); - - var oldStreamPos = stream.Position; - - using (var entryStream = entry.OpenEntryStream()) - { - using (var memoryStream = new MemoryStream()) - { - entryStream.TransferTo(memoryStream); - memoryStream.Position = 0; - var bytes = memoryStream.ToArray(); - - header.Name = ReaderOptions.ArchiveEncoding - .Decode(bytes) - .TrimNulls(); - } - } - - stream.Position = oldStreamPos; - - previousHeader = null; - } - yield return new TarArchiveEntry( + var entry = new TarArchiveEntry( this, - new TarFilePart(header, stream), + new TarFilePart(previousHeader, stream), CompressionType.None ); + + var oldStreamPos = stream.Position; + + using (var entryStream = entry.OpenEntryStream()) + { + using var memoryStream = new MemoryStream(); + entryStream.TransferTo(memoryStream); + memoryStream.Position = 0; + var bytes = memoryStream.ToArray(); + + header.Name = ReaderOptions.ArchiveEncoding + .Decode(bytes) + .TrimNulls(); + } + + stream.Position = oldStreamPos; + + previousHeader = null; } + yield return new TarArchiveEntry( + this, + new TarFilePart(header, stream), + CompressionType.None + ); } } } - - public static TarArchive Create() - { - return new TarArchive(); - } - - protected override TarArchiveEntry CreateEntryInternal( - string filePath, - Stream source, - long size, - DateTime? modified, - bool closeStream - ) - { - return new TarWritableArchiveEntry( - this, - source, - CompressionType.Unknown, - filePath, - size, - modified, - closeStream - ); - } - - protected override void SaveTo( - Stream stream, - WriterOptions options, - IEnumerable oldEntries, - IEnumerable newEntries - ) - { - using (var writer = new TarWriter(stream, new TarWriterOptions(options))) - { - 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); - } - } - } - } - - protected override IReader CreateReaderForSolidExtraction() - { - var stream = Volumes.Single().Stream; - stream.Position = 0; - return TarReader.Open(stream); - } + } + + public static TarArchive Create() + { + return new TarArchive(); + } + + protected override TarArchiveEntry CreateEntryInternal( + string filePath, + Stream source, + long size, + DateTime? modified, + bool closeStream + ) + { + return new TarWritableArchiveEntry( + this, + source, + CompressionType.Unknown, + filePath, + size, + modified, + closeStream + ); + } + + protected override void SaveTo( + Stream stream, + WriterOptions options, + IEnumerable oldEntries, + IEnumerable newEntries + ) + { + using var writer = new TarWriter(stream, new TarWriterOptions(options)); + 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); + } + } + + protected override IReader CreateReaderForSolidExtraction() + { + var stream = Volumes.Single().Stream; + stream.Position = 0; + return TarReader.Open(stream); } } diff --git a/src/SharpCompress/Archives/Tar/TarArchiveEntry.cs b/src/SharpCompress/Archives/Tar/TarArchiveEntry.cs index 99a2498f..d2ac353f 100644 --- a/src/SharpCompress/Archives/Tar/TarArchiveEntry.cs +++ b/src/SharpCompress/Archives/Tar/TarArchiveEntry.cs @@ -1,32 +1,31 @@ -using System.IO; +using System.IO; using System.Linq; using SharpCompress.Common; using SharpCompress.Common.Tar; -namespace SharpCompress.Archives.Tar +namespace SharpCompress.Archives.Tar; + +public class TarArchiveEntry : TarEntry, IArchiveEntry { - public class TarArchiveEntry : TarEntry, IArchiveEntry + internal TarArchiveEntry( + TarArchive archive, + TarFilePart part, + CompressionType compressionType + ) : base(part, compressionType) { - internal TarArchiveEntry( - TarArchive archive, - TarFilePart part, - CompressionType compressionType - ) : base(part, compressionType) - { - Archive = archive; - } - - public virtual Stream OpenEntryStream() - { - return Parts.Single().GetCompressedStream(); - } - - #region IArchiveEntry Members - - public IArchive Archive { get; } - - public bool IsComplete => true; - - #endregion + Archive = archive; } + + public virtual Stream OpenEntryStream() + { + return Parts.Single().GetCompressedStream(); + } + + #region IArchiveEntry Members + + public IArchive Archive { get; } + + public bool IsComplete => true; + + #endregion } diff --git a/src/SharpCompress/Archives/Tar/TarWritableArchiveEntry.cs b/src/SharpCompress/Archives/Tar/TarWritableArchiveEntry.cs index 7c6cfbcb..e110987b 100644 --- a/src/SharpCompress/Archives/Tar/TarWritableArchiveEntry.cs +++ b/src/SharpCompress/Archives/Tar/TarWritableArchiveEntry.cs @@ -6,68 +6,67 @@ using System.IO; using SharpCompress.Common; using SharpCompress.IO; -namespace SharpCompress.Archives.Tar +namespace SharpCompress.Archives.Tar; + +internal sealed class TarWritableArchiveEntry : TarArchiveEntry, IWritableArchiveEntry { - internal sealed class TarWritableArchiveEntry : TarArchiveEntry, IWritableArchiveEntry + private readonly bool closeStream; + private readonly Stream stream; + + internal TarWritableArchiveEntry( + TarArchive archive, + Stream stream, + CompressionType compressionType, + string path, + long size, + DateTime? lastModified, + bool closeStream + ) : base(archive, null, compressionType) { - private readonly bool closeStream; - private readonly Stream stream; + this.stream = stream; + Key = path; + Size = size; + LastModifiedTime = lastModified; + this.closeStream = closeStream; + } - internal TarWritableArchiveEntry( - TarArchive archive, - Stream stream, - CompressionType compressionType, - string path, - long size, - DateTime? lastModified, - bool closeStream - ) : base(archive, null, compressionType) + public override long Crc => 0; + + public override string Key { get; } + + public override long CompressedSize => 0; + + public override long Size { get; } + + public override DateTime? LastModifiedTime { get; } + + public override DateTime? CreatedTime => null; + + public override DateTime? LastAccessedTime => null; + + public override DateTime? ArchivedTime => null; + + public override bool IsEncrypted => false; + + public override bool IsDirectory => false; + + public override bool IsSplitAfter => false; + + internal override IEnumerable Parts => throw new NotImplementedException(); + Stream IWritableArchiveEntry.Stream => stream; + + public override Stream OpenEntryStream() + { + //ensure new stream is at the start, this could be reset + stream.Seek(0, SeekOrigin.Begin); + return NonDisposingStream.Create(stream); + } + + internal override void Close() + { + if (closeStream) { - this.stream = stream; - Key = path; - Size = size; - LastModifiedTime = lastModified; - this.closeStream = closeStream; - } - - public override long Crc => 0; - - public override string Key { get; } - - public override long CompressedSize => 0; - - public override long Size { get; } - - public override DateTime? LastModifiedTime { get; } - - public override DateTime? CreatedTime => null; - - public override DateTime? LastAccessedTime => null; - - public override DateTime? ArchivedTime => null; - - public override bool IsEncrypted => false; - - public override bool IsDirectory => false; - - public override bool IsSplitAfter => false; - - internal override IEnumerable Parts => throw new NotImplementedException(); - Stream IWritableArchiveEntry.Stream => stream; - - public override Stream OpenEntryStream() - { - //ensure new stream is at the start, this could be reset - stream.Seek(0, SeekOrigin.Begin); - return NonDisposingStream.Create(stream); - } - - internal override void Close() - { - if (closeStream) - { - stream.Dispose(); - } + stream.Dispose(); } } } diff --git a/src/SharpCompress/Archives/Zip/ZipArchive.cs b/src/SharpCompress/Archives/Zip/ZipArchive.cs index f5c52863..11b8cd0a 100644 --- a/src/SharpCompress/Archives/Zip/ZipArchive.cs +++ b/src/SharpCompress/Archives/Zip/ZipArchive.cs @@ -12,319 +12,317 @@ using SharpCompress.Readers.Zip; using SharpCompress.Writers; using SharpCompress.Writers.Zip; -namespace SharpCompress.Archives.Zip +namespace SharpCompress.Archives.Zip; + +public class ZipArchive : AbstractWritableArchive { - public class ZipArchive : AbstractWritableArchive - { #nullable disable - private readonly SeekableZipHeaderFactory headerFactory; + private readonly SeekableZipHeaderFactory headerFactory; #nullable enable - /// - /// Gets or sets the compression level applied to files added to the archive, - /// if the compression method is set to deflate - /// - public CompressionLevel DeflateCompressionLevel { get; set; } + /// + /// Gets or sets the compression level applied to files added to the archive, + /// if the compression method is set to deflate + /// + public CompressionLevel DeflateCompressionLevel { get; set; } - /// - /// Constructor with a SourceStream able to handle FileInfo and Streams. - /// - /// - /// - internal ZipArchive(SourceStream srcStream) : base(ArchiveType.Zip, srcStream) + /// + /// Constructor with a SourceStream able to handle FileInfo and Streams. + /// + /// + /// + internal ZipArchive(SourceStream srcStream) : base(ArchiveType.Zip, srcStream) + { + headerFactory = new SeekableZipHeaderFactory( + srcStream.ReaderOptions.Password, + srcStream.ReaderOptions.ArchiveEncoding + ); + } + + /// + /// Constructor expects a filepath to an existing file. + /// + /// + /// + public static ZipArchive Open(string filePath, ReaderOptions? readerOptions = null) + { + filePath.CheckNotNullOrEmpty(nameof(filePath)); + return Open(new FileInfo(filePath), readerOptions ?? new ReaderOptions()); + } + + /// + /// Constructor with a FileInfo object to an existing file. + /// + /// + /// + public static ZipArchive Open(FileInfo fileInfo, ReaderOptions? readerOptions = null) + { + fileInfo.CheckNotNull(nameof(fileInfo)); + return new ZipArchive( + new SourceStream( + fileInfo, + i => ZipArchiveVolumeFactory.GetFilePart(i, fileInfo), + readerOptions ?? new ReaderOptions() + ) + ); + } + + /// + /// Constructor with all file parts passed in + /// + /// + /// + public static ZipArchive Open( + IEnumerable fileInfos, + ReaderOptions? readerOptions = null + ) + { + fileInfos.CheckNotNull(nameof(fileInfos)); + var files = fileInfos.ToArray(); + return new ZipArchive( + new SourceStream( + files[0], + i => i < files.Length ? files[i] : null, + readerOptions ?? new ReaderOptions() + ) + ); + } + + /// + /// Constructor with all stream parts passed in + /// + /// + /// + public static ZipArchive Open( + IEnumerable streams, + ReaderOptions? readerOptions = null + ) + { + streams.CheckNotNull(nameof(streams)); + var strms = streams.ToArray(); + return new ZipArchive( + new SourceStream( + strms[0], + i => i < strms.Length ? strms[i] : null, + readerOptions ?? new ReaderOptions() + ) + ); + } + + /// + /// Takes a seekable Stream as a source + /// + /// + /// + public static ZipArchive Open(Stream stream, ReaderOptions? readerOptions = null) + { + stream.CheckNotNull(nameof(stream)); + return new ZipArchive( + new SourceStream(stream, i => null, readerOptions ?? new ReaderOptions()) + ); + } + + public static bool IsZipFile(string filePath, string? password = null) + { + return IsZipFile(new FileInfo(filePath), password); + } + + public static bool IsZipFile(FileInfo fileInfo, string? password = null) + { + if (!fileInfo.Exists) { - headerFactory = new SeekableZipHeaderFactory( - srcStream.ReaderOptions.Password, - srcStream.ReaderOptions.ArchiveEncoding - ); + return false; } + using Stream stream = fileInfo.OpenRead(); + return IsZipFile(stream, password); + } - /// - /// Constructor expects a filepath to an existing file. - /// - /// - /// - public static ZipArchive Open(string filePath, ReaderOptions? readerOptions = null) + public static bool IsZipFile(Stream stream, string? password = null) + { + var headerFactory = new StreamingZipHeaderFactory( + password, + new ArchiveEncoding() + ); + try { - filePath.CheckNotNullOrEmpty(nameof(filePath)); - return Open(new FileInfo(filePath), readerOptions ?? new ReaderOptions()); - } - - /// - /// Constructor with a FileInfo object to an existing file. - /// - /// - /// - public static ZipArchive Open(FileInfo fileInfo, ReaderOptions? readerOptions = null) - { - fileInfo.CheckNotNull(nameof(fileInfo)); - return new ZipArchive( - new SourceStream( - fileInfo, - i => ZipArchiveVolumeFactory.GetFilePart(i, fileInfo), - readerOptions ?? new ReaderOptions() - ) - ); - } - - /// - /// Constructor with all file parts passed in - /// - /// - /// - public static ZipArchive Open( - IEnumerable fileInfos, - ReaderOptions? readerOptions = null - ) - { - fileInfos.CheckNotNull(nameof(fileInfos)); - FileInfo[] files = fileInfos.ToArray(); - return new ZipArchive( - new SourceStream( - files[0], - i => i < files.Length ? files[i] : null, - readerOptions ?? new ReaderOptions() - ) - ); - } - - /// - /// Constructor with all stream parts passed in - /// - /// - /// - public static ZipArchive Open( - IEnumerable streams, - ReaderOptions? readerOptions = null - ) - { - streams.CheckNotNull(nameof(streams)); - Stream[] strms = streams.ToArray(); - return new ZipArchive( - new SourceStream( - strms[0], - i => i < strms.Length ? strms[i] : null, - readerOptions ?? new ReaderOptions() - ) - ); - } - - /// - /// Takes a seekable Stream as a source - /// - /// - /// - public static ZipArchive Open(Stream stream, ReaderOptions? readerOptions = null) - { - stream.CheckNotNull(nameof(stream)); - return new ZipArchive( - new SourceStream(stream, i => null, readerOptions ?? new ReaderOptions()) - ); - } - - public static bool IsZipFile(string filePath, string? password = null) - { - return IsZipFile(new FileInfo(filePath), password); - } - - public static bool IsZipFile(FileInfo fileInfo, string? password = null) - { - if (!fileInfo.Exists) + var header = headerFactory + .ReadStreamHeader(stream) + .FirstOrDefault(x => x.ZipHeaderType != ZipHeaderType.Split); + if (header is null) { return false; } - using (Stream stream = fileInfo.OpenRead()) - { - return IsZipFile(stream, password); - } + return Enum.IsDefined(typeof(ZipHeaderType), header.ZipHeaderType); } - - public static bool IsZipFile(Stream stream, string? password = null) + catch (CryptographicException) { - StreamingZipHeaderFactory headerFactory = new StreamingZipHeaderFactory( - password, - new ArchiveEncoding() - ); - try + return true; + } + catch + { + return false; + } + } + + public static bool IsZipMulti(Stream stream, string? password = null) + { + var headerFactory = new StreamingZipHeaderFactory( + password, + new ArchiveEncoding() + ); + try + { + var header = headerFactory + .ReadStreamHeader(stream) + .FirstOrDefault(x => x.ZipHeaderType != ZipHeaderType.Split); + if (header is null) { - ZipHeader? header = headerFactory - .ReadStreamHeader(stream) - .FirstOrDefault(x => x.ZipHeaderType != ZipHeaderType.Split); - if (header is null) + if (stream.CanSeek) //could be multipart. Test for central directory - might not be z64 safe + { + var z = new SeekableZipHeaderFactory( + password, + new ArchiveEncoding() + ); + var x = z.ReadSeekableHeader(stream).FirstOrDefault(); + return x?.ZipHeaderType == ZipHeaderType.DirectoryEntry; + } + else { return false; } - return Enum.IsDefined(typeof(ZipHeaderType), header.ZipHeaderType); - } - catch (CryptographicException) - { - return true; - } - catch - { - return false; } + return Enum.IsDefined(typeof(ZipHeaderType), header.ZipHeaderType); } - - public static bool IsZipMulti(Stream stream, string? password = null) + catch (CryptographicException) { - StreamingZipHeaderFactory headerFactory = new StreamingZipHeaderFactory( - password, - new ArchiveEncoding() - ); - try - { - ZipHeader? header = headerFactory - .ReadStreamHeader(stream) - .FirstOrDefault(x => x.ZipHeaderType != ZipHeaderType.Split); - if (header is null) - { - if (stream.CanSeek) //could be multipart. Test for central directory - might not be z64 safe - { - SeekableZipHeaderFactory z = new SeekableZipHeaderFactory( - password, - new ArchiveEncoding() - ); - var x = z.ReadSeekableHeader(stream).FirstOrDefault(); - return x?.ZipHeaderType == ZipHeaderType.DirectoryEntry; - } - else - return false; - } - return Enum.IsDefined(typeof(ZipHeaderType), header.ZipHeaderType); - } - catch (CryptographicException) - { - return true; - } - catch - { - return false; - } + return true; } - - protected override IEnumerable LoadVolumes(SourceStream srcStream) + catch { - base.SrcStream.LoadAllParts(); //request all streams - base.SrcStream.Position = 0; - - List streams = base.SrcStream.Streams.ToList(); - int idx = 0; - if (streams.Count > 1) //test part 2 - true = multipart not split - { - streams[1].Position += 4; //skip the POST_DATA_DESCRIPTOR to prevent an exception - bool isZip = IsZipFile(streams[1], ReaderOptions.Password); - streams[1].Position -= 4; - if (isZip) - { - base.SrcStream.IsVolumes = true; - - var tmp = streams[0]; //arcs as zip, z01 ... swap the zip the end - streams.RemoveAt(0); - streams.Add(tmp); - - //streams[0].Position = 4; //skip the POST_DATA_DESCRIPTOR to prevent an exception - return streams.Select(a => new ZipVolume(a, ReaderOptions, idx++)); - } - } - - //split mode or single file - return new ZipVolume(base.SrcStream, ReaderOptions, idx++).AsEnumerable(); - } - - internal ZipArchive() : base(ArchiveType.Zip) { } - - protected override IEnumerable LoadEntries(IEnumerable volumes) - { - var vols = volumes.ToArray(); - foreach (ZipHeader h in headerFactory.ReadSeekableHeader(vols.Last().Stream)) - { - if (h != null) - { - switch (h.ZipHeaderType) - { - case ZipHeaderType.DirectoryEntry: - - { - DirectoryEntryHeader deh = (DirectoryEntryHeader)h; - Stream s; - if ( - deh.RelativeOffsetOfEntryHeader + deh.CompressedSize - > vols[deh.DiskNumberStart].Stream.Length - ) - { - var v = vols.Skip(deh.DiskNumberStart).ToArray(); - s = new SourceStream( - v[0].Stream, - i => i < v.Length ? v[i].Stream : null, - new ReaderOptions() { LeaveStreamOpen = true } - ); - } - else - s = vols[deh.DiskNumberStart].Stream; - yield return new ZipArchiveEntry( - this, - new SeekableZipFilePart(headerFactory, deh, s) - ); - } - break; - case ZipHeaderType.DirectoryEnd: - { - byte[] bytes = ((DirectoryEndHeader)h).Comment ?? Array.Empty(); - volumes.Last().Comment = ReaderOptions.ArchiveEncoding.Decode(bytes); - yield break; - } - } - } - } - } - - public void SaveTo(Stream stream) - { - SaveTo(stream, new WriterOptions(CompressionType.Deflate)); - } - - protected override void SaveTo( - Stream stream, - WriterOptions options, - IEnumerable oldEntries, - IEnumerable newEntries - ) - { - using (var writer = new ZipWriter(stream, new ZipWriterOptions(options))) - { - foreach (var entry in oldEntries.Concat(newEntries).Where(x => !x.IsDirectory)) - { - using (var entryStream = entry.OpenEntryStream()) - { - writer.Write(entry.Key, entryStream, entry.LastModifiedTime); - } - } - } - } - - protected override ZipArchiveEntry CreateEntryInternal( - string filePath, - Stream source, - long size, - DateTime? modified, - bool closeStream - ) - { - return new ZipWritableArchiveEntry(this, source, filePath, size, modified, closeStream); - } - - public static ZipArchive Create() - { - return new ZipArchive(); - } - - protected override IReader CreateReaderForSolidExtraction() - { - var stream = Volumes.Single().Stream; - stream.Position = 0; - return ZipReader.Open(stream, ReaderOptions); + return false; } } + + protected override IEnumerable LoadVolumes(SourceStream srcStream) + { + SrcStream.LoadAllParts(); //request all streams + SrcStream.Position = 0; + + var streams = SrcStream.Streams.ToList(); + var idx = 0; + 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; + + var tmp = streams[0]; //arcs as zip, z01 ... swap the zip the end + streams.RemoveAt(0); + streams.Add(tmp); + + //streams[0].Position = 4; //skip the POST_DATA_DESCRIPTOR to prevent an exception + return streams.Select(a => new ZipVolume(a, ReaderOptions, idx++)); + } + } + + //split mode or single file + return new ZipVolume(SrcStream, ReaderOptions, idx++).AsEnumerable(); + } + + internal ZipArchive() : base(ArchiveType.Zip) { } + + protected override IEnumerable LoadEntries(IEnumerable volumes) + { + var vols = volumes.ToArray(); + foreach (var h in headerFactory.ReadSeekableHeader(vols.Last().Stream)) + { + if (h != null) + { + switch (h.ZipHeaderType) + { + case ZipHeaderType.DirectoryEntry: + + { + var deh = (DirectoryEntryHeader)h; + Stream s; + if ( + deh.RelativeOffsetOfEntryHeader + deh.CompressedSize + > vols[deh.DiskNumberStart].Stream.Length + ) + { + var v = vols.Skip(deh.DiskNumberStart).ToArray(); + s = new SourceStream( + v[0].Stream, + i => i < v.Length ? v[i].Stream : null, + new ReaderOptions() { LeaveStreamOpen = true } + ); + } + else + { + s = vols[deh.DiskNumberStart].Stream; + } + + yield return new ZipArchiveEntry( + this, + new SeekableZipFilePart(headerFactory, deh, s) + ); + } + break; + case ZipHeaderType.DirectoryEnd: + { + var bytes = ((DirectoryEndHeader)h).Comment ?? Array.Empty(); + volumes.Last().Comment = ReaderOptions.ArchiveEncoding.Decode(bytes); + yield break; + } + } + } + } + } + + public void SaveTo(Stream stream) + { + SaveTo(stream, new WriterOptions(CompressionType.Deflate)); + } + + protected override void SaveTo( + Stream stream, + WriterOptions options, + IEnumerable oldEntries, + IEnumerable newEntries + ) + { + using var writer = new ZipWriter(stream, new ZipWriterOptions(options)); + foreach (var entry in oldEntries.Concat(newEntries).Where(x => !x.IsDirectory)) + { + using var entryStream = entry.OpenEntryStream(); + writer.Write(entry.Key, entryStream, entry.LastModifiedTime); + } + } + + protected override ZipArchiveEntry CreateEntryInternal( + string filePath, + Stream source, + long size, + DateTime? modified, + bool closeStream + ) + { + return new ZipWritableArchiveEntry(this, source, filePath, size, modified, closeStream); + } + + public static ZipArchive Create() + { + return new ZipArchive(); + } + + protected override IReader CreateReaderForSolidExtraction() + { + var stream = Volumes.Single().Stream; + stream.Position = 0; + return ZipReader.Open(stream, ReaderOptions); + } } diff --git a/src/SharpCompress/Archives/Zip/ZipArchiveEntry.cs b/src/SharpCompress/Archives/Zip/ZipArchiveEntry.cs index dd1354fd..5059f61a 100644 --- a/src/SharpCompress/Archives/Zip/ZipArchiveEntry.cs +++ b/src/SharpCompress/Archives/Zip/ZipArchiveEntry.cs @@ -1,29 +1,28 @@ -using System.IO; +using System.IO; using System.Linq; using SharpCompress.Common.Zip; -namespace SharpCompress.Archives.Zip +namespace SharpCompress.Archives.Zip; + +public class ZipArchiveEntry : ZipEntry, IArchiveEntry { - public class ZipArchiveEntry : ZipEntry, IArchiveEntry + internal ZipArchiveEntry(ZipArchive archive, SeekableZipFilePart? part) : base(part) { - internal ZipArchiveEntry(ZipArchive archive, SeekableZipFilePart? part) : base(part) - { - Archive = archive; - } - - public virtual Stream OpenEntryStream() - { - return Parts.Single().GetCompressedStream(); - } - - #region IArchiveEntry Members - - public IArchive Archive { get; } - - public bool IsComplete => true; - - #endregion - - public string? Comment => ((SeekableZipFilePart)Parts.Single()).Comment; + Archive = archive; } + + public virtual Stream OpenEntryStream() + { + return Parts.Single().GetCompressedStream(); + } + + #region IArchiveEntry Members + + public IArchive Archive { get; } + + public bool IsComplete => true; + + #endregion + + public string? Comment => ((SeekableZipFilePart)Parts.Single()).Comment; } diff --git a/src/SharpCompress/Archives/Zip/ZipWritableArchiveEntry.cs b/src/SharpCompress/Archives/Zip/ZipWritableArchiveEntry.cs index ac595792..a13a3dbb 100644 --- a/src/SharpCompress/Archives/Zip/ZipWritableArchiveEntry.cs +++ b/src/SharpCompress/Archives/Zip/ZipWritableArchiveEntry.cs @@ -4,70 +4,69 @@ using System.IO; using SharpCompress.Common; using SharpCompress.IO; -namespace SharpCompress.Archives.Zip +namespace SharpCompress.Archives.Zip; + +internal class ZipWritableArchiveEntry : ZipArchiveEntry, IWritableArchiveEntry { - internal class ZipWritableArchiveEntry : ZipArchiveEntry, IWritableArchiveEntry + private readonly bool closeStream; + private readonly Stream stream; + private bool isDisposed; + + internal ZipWritableArchiveEntry( + ZipArchive archive, + Stream stream, + string path, + long size, + DateTime? lastModified, + bool closeStream + ) : base(archive, null) { - private readonly bool closeStream; - private readonly Stream stream; - private bool isDisposed; + this.stream = stream; + Key = path; + Size = size; + LastModifiedTime = lastModified; + this.closeStream = closeStream; + } - internal ZipWritableArchiveEntry( - ZipArchive archive, - Stream stream, - string path, - long size, - DateTime? lastModified, - bool closeStream - ) : base(archive, null) + public override long Crc => 0; + + public override string Key { get; } + + public override long CompressedSize => 0; + + public override long Size { get; } + + public override DateTime? LastModifiedTime { get; } + + public override DateTime? CreatedTime => null; + + public override DateTime? LastAccessedTime => null; + + public override DateTime? ArchivedTime => null; + + public override bool IsEncrypted => false; + + public override bool IsDirectory => false; + + public override bool IsSplitAfter => false; + + internal override IEnumerable Parts => throw new NotImplementedException(); + + Stream IWritableArchiveEntry.Stream => stream; + + public override Stream OpenEntryStream() + { + //ensure new stream is at the start, this could be reset + stream.Seek(0, SeekOrigin.Begin); + return NonDisposingStream.Create(stream); + } + + internal override void Close() + { + if (closeStream && !isDisposed) { - this.stream = stream; - Key = path; - Size = size; - LastModifiedTime = lastModified; - this.closeStream = closeStream; - } - - public override long Crc => 0; - - public override string Key { get; } - - public override long CompressedSize => 0; - - public override long Size { get; } - - public override DateTime? LastModifiedTime { get; } - - public override DateTime? CreatedTime => null; - - public override DateTime? LastAccessedTime => null; - - public override DateTime? ArchivedTime => null; - - public override bool IsEncrypted => false; - - public override bool IsDirectory => false; - - public override bool IsSplitAfter => false; - - internal override IEnumerable Parts => throw new NotImplementedException(); - - Stream IWritableArchiveEntry.Stream => stream; - - public override Stream OpenEntryStream() - { - //ensure new stream is at the start, this could be reset - stream.Seek(0, SeekOrigin.Begin); - return NonDisposingStream.Create(stream); - } - - internal override void Close() - { - if (closeStream && !isDisposed) - { - stream.Dispose(); - isDisposed = true; - } + stream.Dispose(); + isDisposed = true; } } } diff --git a/src/SharpCompress/AssemblyInfo.cs b/src/SharpCompress/AssemblyInfo.cs index 8c114539..0270020d 100644 --- a/src/SharpCompress/AssemblyInfo.cs +++ b/src/SharpCompress/AssemblyInfo.cs @@ -1,3 +1,3 @@ -using System; +using System; [assembly: CLSCompliant(true)] diff --git a/src/SharpCompress/Common/ArchiveEncoding.cs b/src/SharpCompress/Common/ArchiveEncoding.cs index d50f0930..a5ee35b2 100644 --- a/src/SharpCompress/Common/ArchiveEncoding.cs +++ b/src/SharpCompress/Common/ArchiveEncoding.cs @@ -1,75 +1,74 @@ -using System; +using System; using System.Text; -namespace SharpCompress.Common +namespace SharpCompress.Common; + +public class ArchiveEncoding { - public class ArchiveEncoding + /// + /// Default encoding to use when archive format doesn't specify one. + /// + public Encoding Default { get; set; } + + /// + /// ArchiveEncoding used by encryption schemes which don't comply with RFC 2898. + /// + public Encoding Password { get; set; } + + /// + /// Set this encoding when you want to force it for all encoding operations. + /// + public Encoding? Forced { get; set; } + + /// + /// Set this when you want to use a custom method for all decoding operations. + /// + /// string Func(bytes, index, length) + public Func? CustomDecoder { get; set; } + + public ArchiveEncoding() : this(Encoding.Default, Encoding.Default) { } + + public ArchiveEncoding(Encoding def, Encoding password) { - /// - /// Default encoding to use when archive format doesn't specify one. - /// - public Encoding Default { get; set; } - - /// - /// ArchiveEncoding used by encryption schemes which don't comply with RFC 2898. - /// - public Encoding Password { get; set; } - - /// - /// Set this encoding when you want to force it for all encoding operations. - /// - public Encoding? Forced { get; set; } - - /// - /// Set this when you want to use a custom method for all decoding operations. - /// - /// string Func(bytes, index, length) - public Func? CustomDecoder { get; set; } - - public ArchiveEncoding() : this(Encoding.Default, Encoding.Default) { } - - public ArchiveEncoding(Encoding def, Encoding password) - { - Default = def; - Password = password; - } + Default = def; + Password = password; + } #if !NETFRAMEWORK - static ArchiveEncoding() - { - Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); - } + static ArchiveEncoding() + { + Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); + } #endif - public string Decode(byte[] bytes) - { - return Decode(bytes, 0, bytes.Length); - } + public string Decode(byte[] bytes) + { + return Decode(bytes, 0, bytes.Length); + } - public string Decode(byte[] bytes, int start, int length) - { - return GetDecoder().Invoke(bytes, start, length); - } + public string Decode(byte[] bytes, int start, int length) + { + return GetDecoder().Invoke(bytes, start, length); + } - public string DecodeUTF8(byte[] bytes) - { - return Encoding.UTF8.GetString(bytes, 0, bytes.Length); - } + public string DecodeUTF8(byte[] bytes) + { + return Encoding.UTF8.GetString(bytes, 0, bytes.Length); + } - public byte[] Encode(string str) - { - return GetEncoding().GetBytes(str); - } + public byte[] Encode(string str) + { + return GetEncoding().GetBytes(str); + } - public Encoding GetEncoding() - { - return Forced ?? Default ?? Encoding.UTF8; - } + public Encoding GetEncoding() + { + return Forced ?? Default ?? Encoding.UTF8; + } - public Func GetDecoder() - { - return CustomDecoder - ?? ((bytes, index, count) => GetEncoding().GetString(bytes, index, count)); - } + public Func GetDecoder() + { + return CustomDecoder + ?? ((bytes, index, count) => GetEncoding().GetString(bytes, index, count)); } } diff --git a/src/SharpCompress/Common/ArchiveException.cs b/src/SharpCompress/Common/ArchiveException.cs index 51fe7463..0fc98baa 100644 --- a/src/SharpCompress/Common/ArchiveException.cs +++ b/src/SharpCompress/Common/ArchiveException.cs @@ -1,9 +1,8 @@ -using System; +using System; -namespace SharpCompress.Common +namespace SharpCompress.Common; + +public class ArchiveException : Exception { - public class ArchiveException : Exception - { - public ArchiveException(string message) : base(message) { } - } + public ArchiveException(string message) : base(message) { } } diff --git a/src/SharpCompress/Common/ArchiveExtractionEventArgs.cs b/src/SharpCompress/Common/ArchiveExtractionEventArgs.cs index 0be0383c..74d419a3 100644 --- a/src/SharpCompress/Common/ArchiveExtractionEventArgs.cs +++ b/src/SharpCompress/Common/ArchiveExtractionEventArgs.cs @@ -1,14 +1,13 @@ -using System; +using System; -namespace SharpCompress.Common +namespace SharpCompress.Common; + +public class ArchiveExtractionEventArgs : EventArgs { - public class ArchiveExtractionEventArgs : EventArgs + internal ArchiveExtractionEventArgs(T entry) { - internal ArchiveExtractionEventArgs(T entry) - { - Item = entry; - } - - public T Item { get; } + Item = entry; } + + public T Item { get; } } diff --git a/src/SharpCompress/Common/ArchiveType.cs b/src/SharpCompress/Common/ArchiveType.cs index 1a899398..49b35387 100644 --- a/src/SharpCompress/Common/ArchiveType.cs +++ b/src/SharpCompress/Common/ArchiveType.cs @@ -1,11 +1,10 @@ -namespace SharpCompress.Common +namespace SharpCompress.Common; + +public enum ArchiveType { - public enum ArchiveType - { - Rar, - Zip, - Tar, - SevenZip, - GZip - } + Rar, + Zip, + Tar, + SevenZip, + GZip } diff --git a/src/SharpCompress/Common/CompressedBytesReadEventArgs.cs b/src/SharpCompress/Common/CompressedBytesReadEventArgs.cs index c87a3588..34ca461f 100644 --- a/src/SharpCompress/Common/CompressedBytesReadEventArgs.cs +++ b/src/SharpCompress/Common/CompressedBytesReadEventArgs.cs @@ -1,26 +1,25 @@ -using System; +using System; -namespace SharpCompress.Common +namespace SharpCompress.Common; + +public sealed class CompressedBytesReadEventArgs : EventArgs { - public sealed class CompressedBytesReadEventArgs : EventArgs + public CompressedBytesReadEventArgs( + long compressedBytesRead, + long currentFilePartCompressedBytesRead + ) { - public CompressedBytesReadEventArgs( - long compressedBytesRead, - long currentFilePartCompressedBytesRead - ) - { - CompressedBytesRead = compressedBytesRead; - CurrentFilePartCompressedBytesRead = currentFilePartCompressedBytesRead; - } - - /// - /// Compressed bytes read for the current entry - /// - public long CompressedBytesRead { get; } - - /// - /// Current file part read for Multipart files (e.g. Rar) - /// - public long CurrentFilePartCompressedBytesRead { get; } + CompressedBytesRead = compressedBytesRead; + CurrentFilePartCompressedBytesRead = currentFilePartCompressedBytesRead; } + + /// + /// Compressed bytes read for the current entry + /// + public long CompressedBytesRead { get; } + + /// + /// Current file part read for Multipart files (e.g. Rar) + /// + public long CurrentFilePartCompressedBytesRead { get; } } diff --git a/src/SharpCompress/Common/CompressionType.cs b/src/SharpCompress/Common/CompressionType.cs index 7dfc857c..11263245 100644 --- a/src/SharpCompress/Common/CompressionType.cs +++ b/src/SharpCompress/Common/CompressionType.cs @@ -1,19 +1,18 @@ -namespace SharpCompress.Common +namespace SharpCompress.Common; + +public enum CompressionType { - public enum CompressionType - { - None, - GZip, - BZip2, - PPMd, - Deflate, - Rar, - LZMA, - BCJ, - BCJ2, - LZip, - Xz, - Unknown, - Deflate64 - } + None, + GZip, + BZip2, + PPMd, + Deflate, + Rar, + LZMA, + BCJ, + BCJ2, + LZip, + Xz, + Unknown, + Deflate64 } diff --git a/src/SharpCompress/Common/CryptographicException.cs b/src/SharpCompress/Common/CryptographicException.cs index 3bdfccb5..c20775a8 100644 --- a/src/SharpCompress/Common/CryptographicException.cs +++ b/src/SharpCompress/Common/CryptographicException.cs @@ -1,9 +1,8 @@ -using System; +using System; -namespace SharpCompress.Common +namespace SharpCompress.Common; + +public class CryptographicException : Exception { - public class CryptographicException : Exception - { - public CryptographicException(string message) : base(message) { } - } + public CryptographicException(string message) : base(message) { } } diff --git a/src/SharpCompress/Common/Entry.cs b/src/SharpCompress/Common/Entry.cs index 17ecc31b..85219a43 100644 --- a/src/SharpCompress/Common/Entry.cs +++ b/src/SharpCompress/Common/Entry.cs @@ -2,90 +2,89 @@ using System; using System.Collections.Generic; using System.Linq; -namespace SharpCompress.Common +namespace SharpCompress.Common; + +public abstract class Entry : IEntry { - public abstract class Entry : IEntry - { - /// - /// The File's 32 bit CRC Hash - /// - public abstract long Crc { get; } + /// + /// The File's 32 bit CRC Hash + /// + public abstract long Crc { get; } - /// - /// The string key of the file internal to the Archive. - /// - public abstract string Key { get; } + /// + /// The string key of the file internal to the Archive. + /// + public abstract string Key { get; } - /// - /// The target of a symlink entry internal to the Archive. Will be null if not a symlink. - /// - public abstract string? LinkTarget { get; } + /// + /// The target of a symlink entry internal to the Archive. Will be null if not a symlink. + /// + public abstract string? LinkTarget { get; } - /// - /// The compressed file size - /// - public abstract long CompressedSize { get; } + /// + /// The compressed file size + /// + public abstract long CompressedSize { get; } - /// - /// The compression type - /// - public abstract CompressionType CompressionType { get; } + /// + /// The compression type + /// + public abstract CompressionType CompressionType { get; } - /// - /// The uncompressed file size - /// - public abstract long Size { get; } + /// + /// The uncompressed file size + /// + public abstract long Size { get; } - /// - /// The entry last modified time in the archive, if recorded - /// - public abstract DateTime? LastModifiedTime { get; } + /// + /// The entry last modified time in the archive, if recorded + /// + public abstract DateTime? LastModifiedTime { get; } - /// - /// The entry create time in the archive, if recorded - /// - public abstract DateTime? CreatedTime { get; } + /// + /// The entry create time in the archive, if recorded + /// + public abstract DateTime? CreatedTime { get; } - /// - /// The entry last accessed time in the archive, if recorded - /// - public abstract DateTime? LastAccessedTime { get; } + /// + /// The entry last accessed time in the archive, if recorded + /// + public abstract DateTime? LastAccessedTime { get; } - /// - /// The entry time when archived, if recorded - /// - public abstract DateTime? ArchivedTime { get; } + /// + /// The entry time when archived, if recorded + /// + public abstract DateTime? ArchivedTime { get; } - /// - /// Entry is password protected and encrypted and cannot be extracted. - /// - public abstract bool IsEncrypted { get; } + /// + /// Entry is password protected and encrypted and cannot be extracted. + /// + public abstract bool IsEncrypted { get; } - /// - /// Entry is directory. - /// - public abstract bool IsDirectory { get; } + /// + /// Entry is directory. + /// + public abstract bool IsDirectory { get; } - /// - /// Entry is split among multiple volumes - /// - public abstract bool IsSplitAfter { get; } + /// + /// Entry is split among multiple volumes + /// + public abstract bool IsSplitAfter { get; } - public int VolumeIndexFirst => this.Parts?.FirstOrDefault()?.Index ?? 0; - public int VolumeIndexLast => this.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; - internal abstract IEnumerable Parts { get; } + internal abstract IEnumerable Parts { get; } - public bool IsSolid { get; set; } + public bool IsSolid { get; set; } - internal virtual void Close() { } + internal virtual void Close() { } - /// - /// Entry file attribute. - /// - public virtual int? Attrib => throw new NotImplementedException(); - } + /// + /// Entry file attribute. + /// + public virtual int? Attrib => throw new NotImplementedException(); } diff --git a/src/SharpCompress/Common/EntryStream.cs b/src/SharpCompress/Common/EntryStream.cs index 44d8e235..6dcac04b 100644 --- a/src/SharpCompress/Common/EntryStream.cs +++ b/src/SharpCompress/Common/EntryStream.cs @@ -1,95 +1,94 @@ -using System; +using System; using System.IO; using SharpCompress.Readers; -namespace SharpCompress.Common +namespace SharpCompress.Common; + +public class EntryStream : Stream { - public class EntryStream : Stream + private readonly IReader _reader; + private readonly Stream _stream; + private bool _completed; + private bool _isDisposed; + + internal EntryStream(IReader reader, Stream stream) { - private readonly IReader _reader; - private readonly Stream _stream; - private bool _completed; - private bool _isDisposed; + _reader = reader; + _stream = stream; + } - internal EntryStream(IReader reader, Stream stream) + /// + /// When reading a stream from OpenEntryStream, the stream must be completed so use this to finish reading the entire entry. + /// + public void SkipEntry() + { + this.Skip(); + _completed = true; + } + + protected override void Dispose(bool disposing) + { + if (!(_completed || _reader.Cancelled)) { - _reader = reader; - _stream = stream; + SkipEntry(); } - - /// - /// When reading a stream from OpenEntryStream, the stream must be completed so use this to finish reading the entire entry. - /// - public void SkipEntry() + if (_isDisposed) + { + return; + } + _isDisposed = true; + base.Dispose(disposing); + _stream.Dispose(); + } + + public override bool CanRead => true; + + public override bool CanSeek => false; + + public override bool CanWrite => false; + + public override void Flush() { } + + public override long Length => _stream.Length; + + public override long Position + { + get => throw new NotSupportedException(); + set => throw new NotSupportedException(); + } + + public override int Read(byte[] buffer, int offset, int count) + { + var read = _stream.Read(buffer, offset, count); + if (read <= 0) { - this.Skip(); _completed = true; } + return read; + } - protected override void Dispose(bool disposing) + public override int ReadByte() + { + var value = _stream.ReadByte(); + if (value == -1) { - if (!(_completed || _reader.Cancelled)) - { - SkipEntry(); - } - if (_isDisposed) - { - return; - } - _isDisposed = true; - base.Dispose(disposing); - _stream.Dispose(); + _completed = true; } + return value; + } - public override bool CanRead => true; + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } - public override bool CanSeek => false; + public override void SetLength(long value) + { + throw new NotSupportedException(); + } - public override bool CanWrite => false; - - public override void Flush() { } - - public override long Length => _stream.Length; - - public override long Position - { - get => throw new NotSupportedException(); - set => throw new NotSupportedException(); - } - - public override int Read(byte[] buffer, int offset, int count) - { - int read = _stream.Read(buffer, offset, count); - if (read <= 0) - { - _completed = true; - } - return read; - } - - public override int ReadByte() - { - int value = _stream.ReadByte(); - if (value == -1) - { - _completed = true; - } - return value; - } - - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } - - public override void SetLength(long value) - { - throw new NotSupportedException(); - } - - public override void Write(byte[] buffer, int offset, int count) - { - throw new NotSupportedException(); - } + public override void Write(byte[] buffer, int offset, int count) + { + throw new NotSupportedException(); } } diff --git a/src/SharpCompress/Common/ExtractionException.cs b/src/SharpCompress/Common/ExtractionException.cs index 51f9bc1e..44316b73 100644 --- a/src/SharpCompress/Common/ExtractionException.cs +++ b/src/SharpCompress/Common/ExtractionException.cs @@ -1,11 +1,10 @@ -using System; +using System; -namespace SharpCompress.Common +namespace SharpCompress.Common; + +public class ExtractionException : Exception { - public class ExtractionException : Exception - { - public ExtractionException(string message) : base(message) { } + public ExtractionException(string message) : base(message) { } - public ExtractionException(string message, Exception inner) : base(message, inner) { } - } + public ExtractionException(string message, Exception inner) : base(message, inner) { } } diff --git a/src/SharpCompress/Common/ExtractionMethods.cs b/src/SharpCompress/Common/ExtractionMethods.cs index 7a6cb9db..390a409b 100644 --- a/src/SharpCompress/Common/ExtractionMethods.cs +++ b/src/SharpCompress/Common/ExtractionMethods.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; namespace SharpCompress.Common diff --git a/src/SharpCompress/Common/ExtractionOptions.cs b/src/SharpCompress/Common/ExtractionOptions.cs index 650708cc..18c0f0ac 100644 --- a/src/SharpCompress/Common/ExtractionOptions.cs +++ b/src/SharpCompress/Common/ExtractionOptions.cs @@ -1,41 +1,40 @@ -using System; +using System; -namespace SharpCompress.Common +namespace SharpCompress.Common; + +public class ExtractionOptions { - public class ExtractionOptions + /// + /// overwrite target if it exists + /// + public bool Overwrite { get; set; } + + /// + /// extract with internal directory structure + /// + public bool ExtractFullPath { get; set; } + + /// + /// preserve file time + /// + public bool PreserveFileTime { get; set; } + + /// + /// preserve windows file attributes + /// + public bool PreserveAttributes { get; set; } + + /// + /// Delegate for writing symbolic links to disk. + /// sourcePath is where the symlink is created. + /// targetPath is what the symlink refers to. + /// + public delegate void SymbolicLinkWriterDelegate(string sourcePath, string targetPath); + + public SymbolicLinkWriterDelegate WriteSymbolicLink = (sourcePath, targetPath) => { - /// - /// overwrite target if it exists - /// - public bool Overwrite { get; set; } - - /// - /// extract with internal directory structure - /// - public bool ExtractFullPath { get; set; } - - /// - /// preserve file time - /// - public bool PreserveFileTime { get; set; } - - /// - /// preserve windows file attributes - /// - public bool PreserveAttributes { get; set; } - - /// - /// Delegate for writing symbolic links to disk. - /// sourcePath is where the symlink is created. - /// targetPath is what the symlink refers to. - /// - public delegate void SymbolicLinkWriterDelegate(string sourcePath, string targetPath); - - public SymbolicLinkWriterDelegate WriteSymbolicLink = (sourcePath, targetPath) => - { - Console.WriteLine( - $"Could not write symlink {sourcePath} -> {targetPath}, for more information please see https://github.com/dotnet/runtime/issues/24271" - ); - }; - } + Console.WriteLine( + $"Could not write symlink {sourcePath} -> {targetPath}, for more information please see https://github.com/dotnet/runtime/issues/24271" + ); + }; } diff --git a/src/SharpCompress/Common/FilePart.cs b/src/SharpCompress/Common/FilePart.cs index fad184aa..e196618f 100644 --- a/src/SharpCompress/Common/FilePart.cs +++ b/src/SharpCompress/Common/FilePart.cs @@ -1,21 +1,20 @@ using System.IO; -namespace SharpCompress.Common +namespace SharpCompress.Common; + +public abstract class FilePart { - public abstract class FilePart + protected FilePart(ArchiveEncoding archiveEncoding) { - protected FilePart(ArchiveEncoding archiveEncoding) - { - ArchiveEncoding = archiveEncoding; - } - - internal ArchiveEncoding ArchiveEncoding { get; } - - internal abstract string FilePartName { get; } - public int Index { get; set; } - - internal abstract Stream GetCompressedStream(); - internal abstract Stream? GetRawStream(); - internal bool Skipped { get; set; } + ArchiveEncoding = archiveEncoding; } + + internal ArchiveEncoding ArchiveEncoding { get; } + + internal abstract string FilePartName { get; } + public int Index { get; set; } + + internal abstract Stream GetCompressedStream(); + internal abstract Stream? GetRawStream(); + internal bool Skipped { get; set; } } diff --git a/src/SharpCompress/Common/FilePartExtractionBeginEventArgs.cs b/src/SharpCompress/Common/FilePartExtractionBeginEventArgs.cs index c05ff46e..d5b8328c 100644 --- a/src/SharpCompress/Common/FilePartExtractionBeginEventArgs.cs +++ b/src/SharpCompress/Common/FilePartExtractionBeginEventArgs.cs @@ -1,29 +1,28 @@ -using System; +using System; -namespace SharpCompress.Common +namespace SharpCompress.Common; + +public sealed class FilePartExtractionBeginEventArgs : EventArgs { - public sealed class FilePartExtractionBeginEventArgs : EventArgs + public FilePartExtractionBeginEventArgs(string name, long size, long compressedSize) { - public FilePartExtractionBeginEventArgs(string name, long size, long compressedSize) - { - Name = name; - Size = size; - CompressedSize = compressedSize; - } - - /// - /// File name for the part for the current entry - /// - public string Name { get; } - - /// - /// Uncompressed size of the current entry in the part - /// - public long Size { get; } - - /// - /// Compressed size of the current entry in the part - /// - public long CompressedSize { get; } + Name = name; + Size = size; + CompressedSize = compressedSize; } + + /// + /// File name for the part for the current entry + /// + public string Name { get; } + + /// + /// Uncompressed size of the current entry in the part + /// + public long Size { get; } + + /// + /// Compressed size of the current entry in the part + /// + public long CompressedSize { get; } } diff --git a/src/SharpCompress/Common/FlagUtility.cs b/src/SharpCompress/Common/FlagUtility.cs index 67aa1428..63cad03b 100644 --- a/src/SharpCompress/Common/FlagUtility.cs +++ b/src/SharpCompress/Common/FlagUtility.cs @@ -1,104 +1,103 @@ -using System; +using System; -namespace SharpCompress.Common +namespace SharpCompress.Common; + +internal static class FlagUtility { - internal static class FlagUtility + /// + /// Returns true if the flag is set on the specified bit field. + /// Currently only works with 32-bit bitfields. + /// + /// Enumeration with Flags attribute + /// Flagged variable + /// Flag to test + /// + public static bool HasFlag(long bitField, T flag) where T : struct { - /// - /// Returns true if the flag is set on the specified bit field. - /// Currently only works with 32-bit bitfields. - /// - /// Enumeration with Flags attribute - /// Flagged variable - /// Flag to test - /// - public static bool HasFlag(long bitField, T flag) where T : struct - { - return HasFlag(bitField, flag); - } + return HasFlag(bitField, flag); + } - /// - /// Returns true if the flag is set on the specified bit field. - /// Currently only works with 32-bit bitfields. - /// - /// Enumeration with Flags attribute - /// Flagged variable - /// Flag to test - /// - public static bool HasFlag(ulong bitField, T flag) where T : struct - { - return HasFlag(bitField, flag); - } + /// + /// Returns true if the flag is set on the specified bit field. + /// Currently only works with 32-bit bitfields. + /// + /// Enumeration with Flags attribute + /// Flagged variable + /// Flag to test + /// + public static bool HasFlag(ulong bitField, T flag) where T : struct + { + return HasFlag(bitField, flag); + } - /// - /// Returns true if the flag is set on the specified bit field. - /// Currently only works with 32-bit bitfields. - /// - /// Flagged variable - /// Flag to test - /// - public static bool HasFlag(ulong bitField, ulong flag) - { - return ((bitField & flag) == flag); - } + /// + /// Returns true if the flag is set on the specified bit field. + /// Currently only works with 32-bit bitfields. + /// + /// Flagged variable + /// Flag to test + /// + public static bool HasFlag(ulong bitField, ulong flag) + { + return ((bitField & flag) == flag); + } - public static bool HasFlag(short bitField, short flag) - { - return ((bitField & flag) == flag); - } + public static bool HasFlag(short bitField, short flag) + { + return ((bitField & flag) == flag); + } - /// - /// Returns true if the flag is set on the specified bit field. - /// Currently only works with 32-bit bitfields. - /// - /// Enumeration with Flags attribute - /// Flagged variable - /// Flag to test - /// - public static bool HasFlag(T bitField, T flag) where T : struct - { - return HasFlag(Convert.ToInt64(bitField), Convert.ToInt64(flag)); - } + /// + /// Returns true if the flag is set on the specified bit field. + /// Currently only works with 32-bit bitfields. + /// + /// Enumeration with Flags attribute + /// Flagged variable + /// Flag to test + /// + public static bool HasFlag(T bitField, T flag) where T : struct + { + return HasFlag(Convert.ToInt64(bitField), Convert.ToInt64(flag)); + } - /// - /// Returns true if the flag is set on the specified bit field. - /// Currently only works with 32-bit bitfields. - /// - /// Flagged variable - /// Flag to test - /// - public static bool HasFlag(long bitField, long flag) - { - return ((bitField & flag) == flag); - } + /// + /// Returns true if the flag is set on the specified bit field. + /// Currently only works with 32-bit bitfields. + /// + /// Flagged variable + /// Flag to test + /// + public static bool HasFlag(long bitField, long flag) + { + return ((bitField & flag) == flag); + } - /// - /// Sets a bit-field to either on or off for the specified flag. - /// - /// Flagged variable - /// Flag to change - /// bool - /// The flagged variable with the flag changed - public static long SetFlag(long bitField, long flag, bool on) + /// + /// Sets a bit-field to either on or off for the specified flag. + /// + /// Flagged variable + /// Flag to change + /// bool + /// The flagged variable with the flag changed + public static long SetFlag(long bitField, long flag, bool on) + { + if (on) { - if (on) - { - return bitField | flag; - } - return bitField & (~flag); + return bitField | flag; } + return bitField & (~flag); + } - /// - /// Sets a bit-field to either on or off for the specified flag. - /// - /// Enumeration with Flags attribute - /// Flagged variable - /// Flag to change - /// bool - /// The flagged variable with the flag changed - public static long SetFlag(T bitField, T flag, bool on) where T : struct - { - return SetFlag(Convert.ToInt64(bitField), Convert.ToInt64(flag), on); - } + /// + /// Sets a bit-field to either on or off for the specified flag. + /// + /// Enumeration with Flags attribute + /// Flagged variable + /// Flag to change + /// bool + /// The flagged variable with the flag changed + public static long SetFlag(T bitField, T flag, bool on) where T : struct + { + return SetFlag(Convert.ToInt64(bitField), Convert.ToInt64(flag), on); } } diff --git a/src/SharpCompress/Common/GZip/GZipEntry.cs b/src/SharpCompress/Common/GZip/GZipEntry.cs index 9da986ee..ec16c979 100644 --- a/src/SharpCompress/Common/GZip/GZipEntry.cs +++ b/src/SharpCompress/Common/GZip/GZipEntry.cs @@ -1,49 +1,48 @@ -using System; +using System; using System.Collections.Generic; using System.IO; -namespace SharpCompress.Common.GZip +namespace SharpCompress.Common.GZip; + +public class GZipEntry : Entry { - public class GZipEntry : Entry + private readonly GZipFilePart _filePart; + + internal GZipEntry(GZipFilePart filePart) { - private readonly GZipFilePart _filePart; + _filePart = filePart; + } - internal GZipEntry(GZipFilePart filePart) - { - _filePart = filePart; - } + public override CompressionType CompressionType => CompressionType.GZip; - 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 string? LinkTarget => null; + public override long CompressedSize => 0; - 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; - public override DateTime? CreatedTime => null; + public override DateTime? LastAccessedTime => null; - public override DateTime? LastAccessedTime => null; + public override DateTime? ArchivedTime => null; - public override DateTime? ArchivedTime => null; + public override bool IsEncrypted => false; - public override bool IsEncrypted => false; + public override bool IsDirectory => false; - public override bool IsDirectory => false; + public override bool IsSplitAfter => false; - public override bool IsSplitAfter => false; + internal override IEnumerable Parts => _filePart.AsEnumerable(); - internal override IEnumerable Parts => _filePart.AsEnumerable(); - - internal static IEnumerable GetEntries(Stream stream, OptionsBase options) - { - yield return new GZipEntry(new GZipFilePart(stream, options.ArchiveEncoding)); - } + internal static IEnumerable GetEntries(Stream stream, OptionsBase options) + { + yield return new GZipEntry(new GZipFilePart(stream, options.ArchiveEncoding)); } } diff --git a/src/SharpCompress/Common/GZip/GZipFilePart.cs b/src/SharpCompress/Common/GZip/GZipFilePart.cs index a5062267..e5e969f1 100644 --- a/src/SharpCompress/Common/GZip/GZipFilePart.cs +++ b/src/SharpCompress/Common/GZip/GZipFilePart.cs @@ -6,132 +6,131 @@ using SharpCompress.Common.Tar.Headers; using SharpCompress.Compressors; using SharpCompress.Compressors.Deflate; -namespace SharpCompress.Common.GZip +namespace SharpCompress.Common.GZip; + +internal sealed class GZipFilePart : FilePart { - internal sealed class GZipFilePart : FilePart + private string? _name; + private readonly Stream _stream; + + internal GZipFilePart(Stream stream, ArchiveEncoding archiveEncoding) + : base(archiveEncoding) { - private string? _name; - private readonly Stream _stream; - - internal GZipFilePart(Stream stream, ArchiveEncoding archiveEncoding) - : base(archiveEncoding) + _stream = stream; + ReadAndValidateGzipHeader(); + if (stream.CanSeek) { - _stream = stream; - ReadAndValidateGzipHeader(); - if (stream.CanSeek) - { - long position = stream.Position; - stream.Position = stream.Length - 8; - ReadTrailer(); - stream.Position = position; - } - EntryStartPosition = stream.Position; + var position = stream.Position; + stream.Position = stream.Length - 8; + ReadTrailer(); + stream.Position = position; + } + EntryStartPosition = stream.Position; + } + + internal long EntryStartPosition { get; } + + internal DateTime? DateModified { get; private set; } + internal uint? Crc { get; private set; } + internal uint? UncompressedSize { get; private set; } + + internal override string FilePartName => _name!; + + internal override Stream GetCompressedStream() + { + return new DeflateStream(_stream, CompressionMode.Decompress, CompressionLevel.Default); + } + + internal override Stream GetRawStream() + { + return _stream; + } + + private void ReadTrailer() + { + // Read and potentially verify the GZIP trailer: CRC32 and size mod 2^32 + Span trailer = stackalloc byte[8]; + var n = _stream.Read(trailer); + + Crc = BinaryPrimitives.ReadUInt32LittleEndian(trailer); + UncompressedSize = BinaryPrimitives.ReadUInt32LittleEndian(trailer.Slice(4)); + } + + private void ReadAndValidateGzipHeader() + { + // read the header on the first read + Span header = stackalloc byte[10]; + var n = _stream.Read(header); + + // workitem 8501: handle edge case (decompress empty stream) + if (n == 0) + { + return; } - internal long EntryStartPosition { get; } - - internal DateTime? DateModified { get; private set; } - internal uint? Crc { get; private set; } - internal uint? UncompressedSize { get; private set; } - - internal override string FilePartName => _name!; - - internal override Stream GetCompressedStream() + if (n != 10) { - return new DeflateStream(_stream, CompressionMode.Decompress, CompressionLevel.Default); + throw new ZlibException("Not a valid GZIP stream."); } - internal override Stream GetRawStream() + if (header[0] != 0x1F || header[1] != 0x8B || header[2] != 8) { - return _stream; + throw new ZlibException("Bad GZIP header."); } - private void ReadTrailer() + var timet = BinaryPrimitives.ReadInt32LittleEndian(header.Slice(4)); + DateModified = TarHeader.EPOCH.AddSeconds(timet); + if ((header[3] & 0x04) == 0x04) { - // Read and potentially verify the GZIP trailer: CRC32 and size mod 2^32 - Span trailer = stackalloc byte[8]; - int n = _stream.Read(trailer); + // read and discard extra field + n = _stream.Read(header.Slice(0, 2)); // 2-byte length field - Crc = BinaryPrimitives.ReadUInt32LittleEndian(trailer); - UncompressedSize = BinaryPrimitives.ReadUInt32LittleEndian(trailer.Slice(4)); + var extraLength = (short)(header[0] + (header[1] * 256)); + var extra = new byte[extraLength]; + + if (!_stream.ReadFully(extra)) + { + throw new ZlibException("Unexpected end-of-file reading GZIP header."); + } + n = extraLength; } - - private void ReadAndValidateGzipHeader() + if ((header[3] & 0x08) == 0x08) { - // read the header on the first read - Span header = stackalloc byte[10]; - int n = _stream.Read(header); - - // workitem 8501: handle edge case (decompress empty stream) - if (n == 0) - { - return; - } - - if (n != 10) - { - throw new ZlibException("Not a valid GZIP stream."); - } - - if (header[0] != 0x1F || header[1] != 0x8B || header[2] != 8) - { - throw new ZlibException("Bad GZIP header."); - } - - int timet = BinaryPrimitives.ReadInt32LittleEndian(header.Slice(4)); - DateModified = TarHeader.EPOCH.AddSeconds(timet); - if ((header[3] & 0x04) == 0x04) - { - // read and discard extra field - n = _stream.Read(header.Slice(0, 2)); // 2-byte length field - - short extraLength = (short)(header[0] + header[1] * 256); - byte[] extra = new byte[extraLength]; - - if (!_stream.ReadFully(extra)) - { - throw new ZlibException("Unexpected end-of-file reading GZIP header."); - } - n = extraLength; - } - if ((header[3] & 0x08) == 0x08) - { - _name = ReadZeroTerminatedString(_stream); - } - if ((header[3] & 0x10) == 0x010) - { - ReadZeroTerminatedString(_stream); - } - if ((header[3] & 0x02) == 0x02) - { - _stream.ReadByte(); // CRC16, ignore - } + _name = ReadZeroTerminatedString(_stream); } - - private string ReadZeroTerminatedString(Stream stream) + if ((header[3] & 0x10) == 0x010) { - Span buf1 = stackalloc byte[1]; - var list = new List(); - bool done = false; - do - { - // workitem 7740 - int n = stream.Read(buf1); - if (n != 1) - { - throw new ZlibException("Unexpected EOF reading GZIP header."); - } - if (buf1[0] == 0) - { - done = true; - } - else - { - list.Add(buf1[0]); - } - } while (!done); - byte[] buffer = list.ToArray(); - return ArchiveEncoding.Decode(buffer); + ReadZeroTerminatedString(_stream); + } + if ((header[3] & 0x02) == 0x02) + { + _stream.ReadByte(); // CRC16, ignore } } + + private string ReadZeroTerminatedString(Stream stream) + { + Span buf1 = stackalloc byte[1]; + var list = new List(); + var done = false; + do + { + // workitem 7740 + var n = stream.Read(buf1); + if (n != 1) + { + throw new ZlibException("Unexpected EOF reading GZIP header."); + } + if (buf1[0] == 0) + { + done = true; + } + else + { + list.Add(buf1[0]); + } + } while (!done); + var buffer = list.ToArray(); + return ArchiveEncoding.Decode(buffer); + } } diff --git a/src/SharpCompress/Common/GZip/GZipVolume.cs b/src/SharpCompress/Common/GZip/GZipVolume.cs index 10e0574d..cc2ec364 100644 --- a/src/SharpCompress/Common/GZip/GZipVolume.cs +++ b/src/SharpCompress/Common/GZip/GZipVolume.cs @@ -1,21 +1,20 @@ using System.IO; using SharpCompress.Readers; -namespace SharpCompress.Common.GZip +namespace SharpCompress.Common.GZip; + +public class GZipVolume : Volume { - public class GZipVolume : Volume + public GZipVolume(Stream stream, ReaderOptions options, int index = 0) + : base(stream, options, index) { } + + public GZipVolume(FileInfo fileInfo, ReaderOptions options) + : base(fileInfo.OpenRead(), options) { - public GZipVolume(Stream stream, ReaderOptions options, int index = 0) - : base(stream, options, index) { } - - public GZipVolume(FileInfo fileInfo, ReaderOptions options) - : base(fileInfo.OpenRead(), options) - { - options.LeaveStreamOpen = false; - } - - public override bool IsFirstVolume => true; - - public override bool IsMultiVolume => true; + options.LeaveStreamOpen = false; } + + public override bool IsFirstVolume => true; + + public override bool IsMultiVolume => true; } diff --git a/src/SharpCompress/Common/IEntry.Extensions.cs b/src/SharpCompress/Common/IEntry.Extensions.cs index fdf321bd..7e9b79a3 100644 --- a/src/SharpCompress/Common/IEntry.Extensions.cs +++ b/src/SharpCompress/Common/IEntry.Extensions.cs @@ -1,49 +1,48 @@ -using System.IO; +using System.IO; -namespace SharpCompress.Common +namespace SharpCompress.Common; + +internal static class EntryExtensions { - internal static class EntryExtensions + internal static void PreserveExtractionOptions( + this IEntry entry, + string destinationFileName, + ExtractionOptions options + ) { - internal static void PreserveExtractionOptions( - this IEntry entry, - string destinationFileName, - ExtractionOptions options - ) + if (options.PreserveFileTime || options.PreserveAttributes) { - if (options.PreserveFileTime || options.PreserveAttributes) + var nf = new FileInfo(destinationFileName); + if (!nf.Exists) { - FileInfo nf = new FileInfo(destinationFileName); - if (!nf.Exists) + return; + } + + // update file time to original packed time + if (options.PreserveFileTime) + { + if (entry.CreatedTime.HasValue) { - return; + nf.CreationTime = entry.CreatedTime.Value; } - // update file time to original packed time - if (options.PreserveFileTime) + if (entry.LastModifiedTime.HasValue) { - if (entry.CreatedTime.HasValue) - { - nf.CreationTime = entry.CreatedTime.Value; - } - - if (entry.LastModifiedTime.HasValue) - { - nf.LastWriteTime = entry.LastModifiedTime.Value; - } - - if (entry.LastAccessedTime.HasValue) - { - nf.LastAccessTime = entry.LastAccessedTime.Value; - } + nf.LastWriteTime = entry.LastModifiedTime.Value; } - if (options.PreserveAttributes) + if (entry.LastAccessedTime.HasValue) { - if (entry.Attrib.HasValue) - { - nf.Attributes = (FileAttributes) - System.Enum.ToObject(typeof(FileAttributes), entry.Attrib.Value); - } + nf.LastAccessTime = entry.LastAccessedTime.Value; + } + } + + if (options.PreserveAttributes) + { + if (entry.Attrib.HasValue) + { + nf.Attributes = (FileAttributes) + System.Enum.ToObject(typeof(FileAttributes), entry.Attrib.Value); } } } diff --git a/src/SharpCompress/Common/IEntry.cs b/src/SharpCompress/Common/IEntry.cs index 63e8f9ca..df1fa603 100644 --- a/src/SharpCompress/Common/IEntry.cs +++ b/src/SharpCompress/Common/IEntry.cs @@ -1,26 +1,24 @@ using System; -using System.Collections.Generic; -namespace SharpCompress.Common +namespace SharpCompress.Common; + +public interface IEntry { - public interface IEntry - { - CompressionType CompressionType { get; } - DateTime? ArchivedTime { get; } - long CompressedSize { get; } - long Crc { get; } - DateTime? CreatedTime { get; } - string Key { get; } - string? LinkTarget { get; } - bool IsDirectory { get; } - bool IsEncrypted { get; } - bool IsSplitAfter { get; } - bool IsSolid { get; } - int VolumeIndexFirst { get; } - int VolumeIndexLast { get; } - DateTime? LastAccessedTime { get; } - DateTime? LastModifiedTime { get; } - long Size { get; } - int? Attrib { get; } - } + CompressionType CompressionType { get; } + DateTime? ArchivedTime { get; } + long CompressedSize { get; } + long Crc { get; } + DateTime? CreatedTime { get; } + string Key { get; } + string? LinkTarget { get; } + bool IsDirectory { get; } + bool IsEncrypted { get; } + bool IsSplitAfter { get; } + bool IsSolid { get; } + int VolumeIndexFirst { get; } + int VolumeIndexLast { get; } + DateTime? LastAccessedTime { get; } + DateTime? LastModifiedTime { get; } + long Size { get; } + int? Attrib { get; } } diff --git a/src/SharpCompress/Common/IExtractionListener.cs b/src/SharpCompress/Common/IExtractionListener.cs index 3ec0abfb..e1389810 100644 --- a/src/SharpCompress/Common/IExtractionListener.cs +++ b/src/SharpCompress/Common/IExtractionListener.cs @@ -1,8 +1,7 @@ -namespace SharpCompress.Common +namespace SharpCompress.Common; + +public interface IExtractionListener { - public interface IExtractionListener - { - void FireFilePartExtractionBegin(string name, long size, long compressedSize); - void FireCompressedBytesRead(long currentPartCompressedBytes, long compressedReadBytes); - } + void FireFilePartExtractionBegin(string name, long size, long compressedSize); + void FireCompressedBytesRead(long currentPartCompressedBytes, long compressedReadBytes); } diff --git a/src/SharpCompress/Common/IVolume.cs b/src/SharpCompress/Common/IVolume.cs index b29d6be9..abbc0406 100644 --- a/src/SharpCompress/Common/IVolume.cs +++ b/src/SharpCompress/Common/IVolume.cs @@ -1,11 +1,10 @@ using System; -namespace SharpCompress.Common -{ - public interface IVolume : IDisposable - { - int Index { get; } +namespace SharpCompress.Common; - string FileName { get; } - } +public interface IVolume : IDisposable +{ + int Index { get; } + + string FileName { get; } } diff --git a/src/SharpCompress/Common/IncompleteArchiveException.cs b/src/SharpCompress/Common/IncompleteArchiveException.cs index aca34349..f1ce3641 100644 --- a/src/SharpCompress/Common/IncompleteArchiveException.cs +++ b/src/SharpCompress/Common/IncompleteArchiveException.cs @@ -1,7 +1,6 @@ -namespace SharpCompress.Common +namespace SharpCompress.Common; + +public class IncompleteArchiveException : ArchiveException { - public class IncompleteArchiveException : ArchiveException - { - public IncompleteArchiveException(string message) : base(message) { } - } + public IncompleteArchiveException(string message) : base(message) { } } diff --git a/src/SharpCompress/Common/InvalidFormatException.cs b/src/SharpCompress/Common/InvalidFormatException.cs index ffb16003..b9501369 100644 --- a/src/SharpCompress/Common/InvalidFormatException.cs +++ b/src/SharpCompress/Common/InvalidFormatException.cs @@ -1,11 +1,10 @@ -using System; +using System; -namespace SharpCompress.Common +namespace SharpCompress.Common; + +public class InvalidFormatException : ExtractionException { - public class InvalidFormatException : ExtractionException - { - public InvalidFormatException(string message) : base(message) { } + public InvalidFormatException(string message) : base(message) { } - public InvalidFormatException(string message, Exception inner) : base(message, inner) { } - } + public InvalidFormatException(string message, Exception inner) : base(message, inner) { } } diff --git a/src/SharpCompress/Common/MultiVolumeExtractionException.cs b/src/SharpCompress/Common/MultiVolumeExtractionException.cs index 7e6da358..7e6f14e3 100644 --- a/src/SharpCompress/Common/MultiVolumeExtractionException.cs +++ b/src/SharpCompress/Common/MultiVolumeExtractionException.cs @@ -1,12 +1,11 @@ -using System; +using System; -namespace SharpCompress.Common +namespace SharpCompress.Common; + +public class MultiVolumeExtractionException : ExtractionException { - public class MultiVolumeExtractionException : ExtractionException - { - public MultiVolumeExtractionException(string message) : base(message) { } + public MultiVolumeExtractionException(string message) : base(message) { } - public MultiVolumeExtractionException(string message, Exception inner) - : base(message, inner) { } - } + public MultiVolumeExtractionException(string message, Exception inner) + : base(message, inner) { } } diff --git a/src/SharpCompress/Common/MultipartStreamRequiredException.cs b/src/SharpCompress/Common/MultipartStreamRequiredException.cs index 84b673ef..bbe3ae93 100644 --- a/src/SharpCompress/Common/MultipartStreamRequiredException.cs +++ b/src/SharpCompress/Common/MultipartStreamRequiredException.cs @@ -1,7 +1,6 @@ -namespace SharpCompress.Common +namespace SharpCompress.Common; + +public class MultipartStreamRequiredException : ExtractionException { - public class MultipartStreamRequiredException : ExtractionException - { - public MultipartStreamRequiredException(string message) : base(message) { } - } + public MultipartStreamRequiredException(string message) : base(message) { } } diff --git a/src/SharpCompress/Common/OptionsBase.cs b/src/SharpCompress/Common/OptionsBase.cs index 6591f975..61a6cb55 100644 --- a/src/SharpCompress/Common/OptionsBase.cs +++ b/src/SharpCompress/Common/OptionsBase.cs @@ -1,12 +1,11 @@ -namespace SharpCompress.Common -{ - public class OptionsBase - { - /// - /// SharpCompress will keep the supplied streams open. Default is true. - /// - public bool LeaveStreamOpen { get; set; } = true; +namespace SharpCompress.Common; - public ArchiveEncoding ArchiveEncoding { get; set; } = new ArchiveEncoding(); - } +public class OptionsBase +{ + /// + /// SharpCompress will keep the supplied streams open. Default is true. + /// + public bool LeaveStreamOpen { get; set; } = true; + + public ArchiveEncoding ArchiveEncoding { get; set; } = new ArchiveEncoding(); } diff --git a/src/SharpCompress/Common/PasswordProtectedException.cs b/src/SharpCompress/Common/PasswordProtectedException.cs index ade0a55d..ab5317c2 100644 --- a/src/SharpCompress/Common/PasswordProtectedException.cs +++ b/src/SharpCompress/Common/PasswordProtectedException.cs @@ -1,12 +1,11 @@ -using System; +using System; -namespace SharpCompress.Common +namespace SharpCompress.Common; + +public class PasswordProtectedException : ExtractionException { - public class PasswordProtectedException : ExtractionException - { - public PasswordProtectedException(string message) : base(message) { } + public PasswordProtectedException(string message) : base(message) { } - public PasswordProtectedException(string message, Exception inner) : base(message, inner) - { } - } + public PasswordProtectedException(string message, Exception inner) : base(message, inner) + { } } diff --git a/src/SharpCompress/Common/Rar/Headers/AVHeader.cs b/src/SharpCompress/Common/Rar/Headers/AVHeader.cs index b235e5ce..cd51d80b 100644 --- a/src/SharpCompress/Common/Rar/Headers/AVHeader.cs +++ b/src/SharpCompress/Common/Rar/Headers/AVHeader.cs @@ -1,32 +1,31 @@ -using SharpCompress.IO; +using SharpCompress.IO; -namespace SharpCompress.Common.Rar.Headers +namespace SharpCompress.Common.Rar.Headers; + +internal class AvHeader : RarHeader { - internal class AvHeader : RarHeader + public AvHeader(RarHeader header, RarCrcBinaryReader reader) + : base(header, reader, HeaderType.Av) { - public AvHeader(RarHeader header, RarCrcBinaryReader reader) - : base(header, reader, HeaderType.Av) + if (IsRar5) { - if (IsRar5) - { - throw new InvalidFormatException("unexpected rar5 record"); - } + throw new InvalidFormatException("unexpected rar5 record"); } - - protected override void ReadFinish(MarkingBinaryReader reader) - { - UnpackVersion = reader.ReadByte(); - Method = reader.ReadByte(); - AvVersion = reader.ReadByte(); - AvInfoCrc = reader.ReadInt32(); - } - - internal int AvInfoCrc { get; private set; } - - internal byte UnpackVersion { get; private set; } - - internal byte Method { get; private set; } - - internal byte AvVersion { get; private set; } } + + protected override void ReadFinish(MarkingBinaryReader reader) + { + UnpackVersion = reader.ReadByte(); + Method = reader.ReadByte(); + AvVersion = reader.ReadByte(); + AvInfoCrc = reader.ReadInt32(); + } + + internal int AvInfoCrc { get; private set; } + + internal byte UnpackVersion { get; private set; } + + internal byte Method { get; private set; } + + internal byte AvVersion { get; private set; } } diff --git a/src/SharpCompress/Common/Rar/Headers/ArchiveCryptHeader.cs b/src/SharpCompress/Common/Rar/Headers/ArchiveCryptHeader.cs index 56784c52..64edb8c4 100644 --- a/src/SharpCompress/Common/Rar/Headers/ArchiveCryptHeader.cs +++ b/src/SharpCompress/Common/Rar/Headers/ArchiveCryptHeader.cs @@ -1,57 +1,53 @@ -#nullable disable +#nullable disable using SharpCompress.IO; -namespace SharpCompress.Common.Rar.Headers +namespace SharpCompress.Common.Rar.Headers; + +internal class ArchiveCryptHeader : RarHeader { - 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) { - private const int CRYPT_VERSION = 0; // Supported encryption version. - private const int SIZE_SALT50 = 16; - private const int SIZE_SALT30 = 8; - private const int SIZE_INITV = 16; - private const int SIZE_PSWCHECK = 8; - private const int SIZE_PSWCHECK_CSUM = 4; - private const int CRYPT5_KDF_LG2_COUNT = 15; // LOG2 of PDKDF2 iteration count. - 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) { - 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); + //error? + return; + } + var encryptionFlags = reader.ReadRarVIntUInt32(); + _usePswCheck = FlagUtility.HasFlag( + encryptionFlags, + EncryptionFlagsV5.CHFL_CRYPT_PSWCHECK + ); + _lg2Count = reader.ReadRarVIntByte(1); - //UsePswCheck = HasHeaderFlag(EncryptionFlagsV5.CHFL_CRYPT_PSWCHECK); - if (_lg2Count > CRYPT5_KDF_LG2_COUNT_MAX) - { - //error? - return; - } + //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); - } + _salt = reader.ReadBytes(SIZE_SALT50); + if (_usePswCheck) + { + _pswCheck = reader.ReadBytes(SIZE_PSWCHECK); + _pswCheckCsm = reader.ReadBytes(SIZE_PSWCHECK_CSUM); } } } diff --git a/src/SharpCompress/Common/Rar/Headers/ArchiveHeader.cs b/src/SharpCompress/Common/Rar/Headers/ArchiveHeader.cs index 33bc6e9a..c46ffa84 100644 --- a/src/SharpCompress/Common/Rar/Headers/ArchiveHeader.cs +++ b/src/SharpCompress/Common/Rar/Headers/ArchiveHeader.cs @@ -1,87 +1,62 @@ using SharpCompress.IO; -namespace SharpCompress.Common.Rar.Headers +namespace SharpCompress.Common.Rar.Headers; + +internal sealed class ArchiveHeader : RarHeader { - internal sealed class ArchiveHeader : RarHeader + public ArchiveHeader(RarHeader header, RarCrcBinaryReader reader) + : base(header, reader, HeaderType.Archive) { } + + protected override void ReadFinish(MarkingBinaryReader reader) { - public ArchiveHeader(RarHeader header, RarCrcBinaryReader reader) - : base(header, reader, HeaderType.Archive) { } - - protected override void ReadFinish(MarkingBinaryReader reader) + if (IsRar5) { - if (IsRar5) + Flags = reader.ReadRarVIntUInt16(); + if (HasFlag(ArchiveFlagsV5.HAS_VOLUME_NUMBER)) { - Flags = reader.ReadRarVIntUInt16(); - if (HasFlag(ArchiveFlagsV5.HAS_VOLUME_NUMBER)) - { - VolumeNumber = (int)reader.ReadRarVIntUInt32(); - } - // later: we may have a locator record if we need it - //if (ExtraSize != 0) { - // ReadLocator(reader); - //} + VolumeNumber = (int)reader.ReadRarVIntUInt32(); } - else + // later: we may have a locator record if we need it + //if (ExtraSize != 0) { + // ReadLocator(reader); + //} + } + else + { + Flags = HeaderFlags; + HighPosAv = reader.ReadInt16(); + PosAv = reader.ReadInt32(); + if (HasFlag(ArchiveFlagsV4.ENCRYPT_VER)) { - Flags = HeaderFlags; - HighPosAv = reader.ReadInt16(); - PosAv = reader.ReadInt32(); - if (HasFlag(ArchiveFlagsV4.ENCRYPT_VER)) - { - EncryptionVersion = reader.ReadByte(); - } + EncryptionVersion = reader.ReadByte(); } } - - private void ReadLocator(MarkingBinaryReader reader) - { - var size = reader.ReadRarVIntUInt16(); - var type = reader.ReadRarVIntUInt16(); - if (type != 1) - { - throw new InvalidFormatException("expected locator record"); - } - - var flags = reader.ReadRarVIntUInt16(); - const ushort hasQuickOpenOffset = 0x01; - const ushort hasRecoveryOffset = 0x02; - ulong quickOpenOffset = 0; - if ((flags & hasQuickOpenOffset) == hasQuickOpenOffset) - { - quickOpenOffset = reader.ReadRarVInt(); - } - ulong recoveryOffset = 0; - if ((flags & hasRecoveryOffset) == hasRecoveryOffset) - { - recoveryOffset = reader.ReadRarVInt(); - } - } - - private ushort Flags { get; set; } - - private bool HasFlag(ushort flag) - { - return (Flags & flag) == flag; - } - - internal int? VolumeNumber { get; private set; } - - internal short? HighPosAv { get; private set; } - - internal int? PosAv { get; private set; } - - private byte? EncryptionVersion { get; set; } - - public bool? IsEncrypted => IsRar5 ? (bool?)null : HasFlag(ArchiveFlagsV4.PASSWORD); - - public bool OldNumberingFormat => !IsRar5 && !HasFlag(ArchiveFlagsV4.NEW_NUMBERING); - - public bool IsVolume => HasFlag(IsRar5 ? ArchiveFlagsV5.VOLUME : ArchiveFlagsV4.VOLUME); - - // RAR5: Volume number field is present. True for all volumes except first. - public bool IsFirstVolume => - IsRar5 ? VolumeNumber is null : HasFlag(ArchiveFlagsV4.FIRST_VOLUME); - - public bool IsSolid => HasFlag(IsRar5 ? ArchiveFlagsV5.SOLID : ArchiveFlagsV4.SOLID); } + + private ushort Flags { get; set; } + + private bool HasFlag(ushort flag) + { + return (Flags & flag) == flag; + } + + internal int? VolumeNumber { get; private set; } + + internal short? HighPosAv { get; private set; } + + internal int? PosAv { get; private set; } + + private byte? EncryptionVersion { get; set; } + + public bool? IsEncrypted => IsRar5 ? null : HasFlag(ArchiveFlagsV4.PASSWORD); + + public bool OldNumberingFormat => !IsRar5 && !HasFlag(ArchiveFlagsV4.NEW_NUMBERING); + + public bool IsVolume => HasFlag(IsRar5 ? ArchiveFlagsV5.VOLUME : ArchiveFlagsV4.VOLUME); + + // RAR5: Volume number field is present. True for all volumes except first. + public bool IsFirstVolume => + IsRar5 ? VolumeNumber is null : HasFlag(ArchiveFlagsV4.FIRST_VOLUME); + + public bool IsSolid => HasFlag(IsRar5 ? ArchiveFlagsV5.SOLID : ArchiveFlagsV4.SOLID); } diff --git a/src/SharpCompress/Common/Rar/Headers/CommentHeader.cs b/src/SharpCompress/Common/Rar/Headers/CommentHeader.cs index 1742aabe..54abf9cc 100644 --- a/src/SharpCompress/Common/Rar/Headers/CommentHeader.cs +++ b/src/SharpCompress/Common/Rar/Headers/CommentHeader.cs @@ -1,31 +1,30 @@ -using SharpCompress.IO; +using SharpCompress.IO; -namespace SharpCompress.Common.Rar.Headers +namespace SharpCompress.Common.Rar.Headers; + +internal class CommentHeader : RarHeader { - internal class CommentHeader : RarHeader + protected CommentHeader(RarHeader header, RarCrcBinaryReader reader) + : base(header, reader, HeaderType.Comment) { - protected CommentHeader(RarHeader header, RarCrcBinaryReader reader) - : base(header, reader, HeaderType.Comment) + if (IsRar5) { - if (IsRar5) - { - throw new InvalidFormatException("unexpected rar5 record"); - } + throw new InvalidFormatException("unexpected rar5 record"); } - - protected override void ReadFinish(MarkingBinaryReader reader) - { - UnpSize = reader.ReadInt16(); - UnpVersion = reader.ReadByte(); - UnpMethod = reader.ReadByte(); - CommCrc = reader.ReadInt16(); - } - - internal short UnpSize { get; private set; } - - internal byte UnpVersion { get; private set; } - - internal byte UnpMethod { get; private set; } - internal short CommCrc { get; private set; } } + + protected override void ReadFinish(MarkingBinaryReader reader) + { + UnpSize = reader.ReadInt16(); + UnpVersion = reader.ReadByte(); + UnpMethod = reader.ReadByte(); + CommCrc = reader.ReadInt16(); + } + + internal short UnpSize { get; private set; } + + internal byte UnpVersion { get; private set; } + + internal byte UnpMethod { get; private set; } + internal short CommCrc { get; private set; } } diff --git a/src/SharpCompress/Common/Rar/Headers/EndArchiveHeader.cs b/src/SharpCompress/Common/Rar/Headers/EndArchiveHeader.cs index bff19b76..10c79850 100644 --- a/src/SharpCompress/Common/Rar/Headers/EndArchiveHeader.cs +++ b/src/SharpCompress/Common/Rar/Headers/EndArchiveHeader.cs @@ -1,41 +1,40 @@ -using SharpCompress.IO; +using SharpCompress.IO; -namespace SharpCompress.Common.Rar.Headers +namespace SharpCompress.Common.Rar.Headers; + +internal class EndArchiveHeader : RarHeader { - internal class EndArchiveHeader : RarHeader + public EndArchiveHeader(RarHeader header, RarCrcBinaryReader reader) + : base(header, reader, HeaderType.EndArchive) { } + + protected override void ReadFinish(MarkingBinaryReader reader) { - public EndArchiveHeader(RarHeader header, RarCrcBinaryReader reader) - : base(header, reader, HeaderType.EndArchive) { } - - protected override void ReadFinish(MarkingBinaryReader reader) + if (IsRar5) { - if (IsRar5) + Flags = reader.ReadRarVIntUInt16(); + } + else + { + Flags = HeaderFlags; + if (HasFlag(EndArchiveFlagsV4.DATA_CRC)) { - Flags = reader.ReadRarVIntUInt16(); + ArchiveCrc = reader.ReadInt32(); } - else + if (HasFlag(EndArchiveFlagsV4.VOLUME_NUMBER)) { - Flags = HeaderFlags; - if (HasFlag(EndArchiveFlagsV4.DATA_CRC)) - { - ArchiveCrc = reader.ReadInt32(); - } - if (HasFlag(EndArchiveFlagsV4.VOLUME_NUMBER)) - { - VolumeNumber = reader.ReadInt16(); - } + VolumeNumber = reader.ReadInt16(); } } - - private ushort Flags { get; set; } - - private bool HasFlag(ushort flag) - { - return (Flags & flag) == flag; - } - - internal int? ArchiveCrc { get; private set; } - - internal short? VolumeNumber { get; private set; } } + + private ushort Flags { get; set; } + + private bool HasFlag(ushort flag) + { + return (Flags & flag) == flag; + } + + internal int? ArchiveCrc { get; private set; } + + internal short? VolumeNumber { get; private set; } } diff --git a/src/SharpCompress/Common/Rar/Headers/FileHeader.cs b/src/SharpCompress/Common/Rar/Headers/FileHeader.cs index 8ef40ec5..66a8a78b 100644 --- a/src/SharpCompress/Common/Rar/Headers/FileHeader.cs +++ b/src/SharpCompress/Common/Rar/Headers/FileHeader.cs @@ -1,8 +1,6 @@ #nullable disable #if !Rar2017_64bit -using nint = System.Int32; -using nuint = System.UInt32; using size_t = System.UInt32; #else using nint = System.Int64; @@ -15,458 +13,457 @@ using System; using System.IO; using System.Text; -namespace SharpCompress.Common.Rar.Headers +namespace SharpCompress.Common.Rar.Headers; + +internal class FileHeader : RarHeader { - internal class FileHeader : RarHeader + private uint _fileCrc; + + public FileHeader(RarHeader header, RarCrcBinaryReader reader, HeaderType headerType) + : base(header, reader, headerType) { } + + protected override void ReadFinish(MarkingBinaryReader reader) { - private uint _fileCrc; - - public FileHeader(RarHeader header, RarCrcBinaryReader reader, HeaderType headerType) - : base(header, reader, headerType) { } - - protected override void ReadFinish(MarkingBinaryReader reader) + if (IsRar5) { - if (IsRar5) - { - ReadFromReaderV5(reader); - } - else - { - ReadFromReaderV4(reader); - } + ReadFromReaderV5(reader); } - - private void ReadFromReaderV5(MarkingBinaryReader reader) + else { - Flags = reader.ReadRarVIntUInt16(); - - var lvalue = checked((long)reader.ReadRarVInt()); - - // long.MaxValue causes the unpack code to finish when the input stream is exhausted - UncompressedSize = HasFlag(FileFlagsV5.UNPACKED_SIZE_UNKNOWN) ? long.MaxValue : lvalue; - - FileAttributes = reader.ReadRarVIntUInt32(); - - if (HasFlag(FileFlagsV5.HAS_MOD_TIME)) - { - FileLastModifiedTime = Utility.UnixTimeToDateTime(reader.ReadUInt32()); - } - - if (HasFlag(FileFlagsV5.HAS_CRC32)) - { - FileCrc = reader.ReadUInt32(); - } - - var compressionInfo = reader.ReadRarVIntUInt16(); - - // Lower 6 bits (0x003f mask) contain the version of compression algorithm, resulting in possible 0 - 63 values. Current version is 0. - // "+ 50" to not mix with old RAR format algorithms. For example, - // we may need to use the compression algorithm 15 in the future, - // but it was already used in RAR 1.5 and Unpack needs to distinguish - // them. - CompressionAlgorithm = (byte)((compressionInfo & 0x3f) + 50); - - // 7th bit (0x0040) defines the solid flag. If it is set, RAR continues to use the compression dictionary left after processing preceding files. - // It can be set only for file headers and is never set for service headers. - IsSolid = (compressionInfo & 0x40) == 0x40; - - // Bits 8 - 10 (0x0380 mask) define the compression method. Currently only values 0 - 5 are used. 0 means no compression. - CompressionMethod = (byte)((compressionInfo >> 7) & 0x7); - - // Bits 11 - 14 (0x3c00) define the minimum size of dictionary size required to extract data. Value 0 means 128 KB, 1 - 256 KB, ..., 14 - 2048 MB, 15 - 4096 MB. - WindowSize = IsDirectory ? 0 : ((size_t)0x20000) << ((compressionInfo >> 10) & 0xf); - - HostOs = reader.ReadRarVIntByte(); - - var nameSize = reader.ReadRarVIntUInt16(); - - // Variable length field containing Name length bytes in UTF-8 format without trailing zero. - // For file header this is a name of archived file. Forward slash character is used as the path separator both for Unix and Windows names. - // Backslashes are treated as a part of name for Unix names and as invalid character for Windows file names. Type of name is defined by Host OS field. - // - // TODO: not sure if anything needs to be done to handle the following: - // If Unix file name contains any high ASCII characters which cannot be correctly converted to Unicode and UTF-8 - // we map such characters to to 0xE080 - 0xE0FF private use Unicode area and insert 0xFFFE Unicode non-character - // to resulting string to indicate that it contains mapped characters, which need to be converted back when extracting. - // Concrete position of 0xFFFE is not defined, we need to search the entire string for it. Such mapped names are not - // portable and can be correctly unpacked only on the same system where they were created. - // - // For service header this field contains a name of service header. Now the following names are used: - // CMT Archive comment - // QO Archive quick open data - // ACL NTFS file permissions - // STM NTFS alternate data stream - // RR Recovery record - var b = reader.ReadBytes(nameSize); - FileName = ConvertPathV5(Encoding.UTF8.GetString(b, 0, b.Length)); - - // extra size seems to be redudant since we know the total header size - if (ExtraSize != RemainingHeaderBytes(reader)) - { - throw new InvalidFormatException("rar5 header size / extra size inconsistency"); - } - - isEncryptedRar5 = false; - - while (RemainingHeaderBytes(reader) > 0) - { - var size = reader.ReadRarVIntUInt16(); - int n = RemainingHeaderBytes(reader); - var type = reader.ReadRarVIntUInt16(); - switch (type) - { - //TODO - case 1: // file encryption - - { - isEncryptedRar5 = true; - - //var version = reader.ReadRarVIntByte(); - //if (version != 0) throw new InvalidFormatException("unknown encryption algorithm " + version); - } - break; - // case 2: // file hash - // { - // - // } - // break; - case 3: // file time - - { - ushort flags = reader.ReadRarVIntUInt16(); - var isWindowsTime = (flags & 1) == 0; - if ((flags & 0x2) == 0x2) - { - FileLastModifiedTime = ReadExtendedTimeV5(reader, isWindowsTime); - } - if ((flags & 0x4) == 0x4) - { - FileCreatedTime = ReadExtendedTimeV5(reader, isWindowsTime); - } - if ((flags & 0x8) == 0x8) - { - FileLastAccessedTime = ReadExtendedTimeV5(reader, isWindowsTime); - } - } - break; - //TODO - // case 4: // file version - // { - // - // } - // break; - // case 5: // file system redirection - // { - // - // } - // break; - // case 6: // unix owner - // { - // - // } - // break; - // case 7: // service data - // { - // - // } - // break; - - default: - // skip unknown record types to allow new record types to be added in the future - break; - } - // drain any trailing bytes of extra record - int did = n - RemainingHeaderBytes(reader); - int drain = size - did; - if (drain > 0) - { - reader.ReadBytes(drain); - } - } - - if (AdditionalDataSize != 0) - { - CompressedSize = AdditionalDataSize; - } + ReadFromReaderV4(reader); } - - private static DateTime ReadExtendedTimeV5(MarkingBinaryReader reader, bool isWindowsTime) - { - if (isWindowsTime) - { - return DateTime.FromFileTime(reader.ReadInt64()); - } - else - { - return Utility.UnixTimeToDateTime(reader.ReadUInt32()); - } - } - - private static string ConvertPathV5(string path) - { - if (Path.DirectorySeparatorChar == '\\') - { - // replace embedded \\ with valid filename char - return path.Replace('\\', '-').Replace('/', '\\'); - } - return path; - } - - private void ReadFromReaderV4(MarkingBinaryReader reader) - { - Flags = HeaderFlags; - IsSolid = HasFlag(FileFlagsV4.SOLID); - WindowSize = IsDirectory - ? 0U - : ((size_t)0x10000) << ((Flags & FileFlagsV4.WINDOW_MASK) >> 5); - - uint lowUncompressedSize = reader.ReadUInt32(); - - HostOs = reader.ReadByte(); - - FileCrc = reader.ReadUInt32(); - - FileLastModifiedTime = Utility.DosDateToDateTime(reader.ReadUInt32()); - - CompressionAlgorithm = reader.ReadByte(); - CompressionMethod = (byte)(reader.ReadByte() - 0x30); - - short nameSize = reader.ReadInt16(); - - FileAttributes = reader.ReadUInt32(); - - uint highCompressedSize = 0; - uint highUncompressedkSize = 0; - if (HasFlag(FileFlagsV4.LARGE)) - { - highCompressedSize = reader.ReadUInt32(); - highUncompressedkSize = reader.ReadUInt32(); - } - else - { - if (lowUncompressedSize == 0xffffffff) - { - lowUncompressedSize = 0xffffffff; - highUncompressedkSize = int.MaxValue; - } - } - CompressedSize = UInt32To64(highCompressedSize, checked((uint)AdditionalDataSize)); - UncompressedSize = UInt32To64(highUncompressedkSize, lowUncompressedSize); - - nameSize = nameSize > 4 * 1024 ? (short)(4 * 1024) : nameSize; - - byte[] fileNameBytes = reader.ReadBytes(nameSize); - - const int saltSize = 8; - const int newLhdSize = 32; - - switch (HeaderCode) - { - case HeaderCodeV.RAR4_FILE_HEADER: - - { - if (HasFlag(FileFlagsV4.UNICODE)) - { - int length = 0; - while (length < fileNameBytes.Length && fileNameBytes[length] != 0) - { - length++; - } - if (length != nameSize) - { - length++; - FileName = FileNameDecoder.Decode(fileNameBytes, length); - } - else - { - FileName = ArchiveEncoding.Decode(fileNameBytes); - } - } - else - { - FileName = ArchiveEncoding.Decode(fileNameBytes); - } - FileName = ConvertPathV4(FileName); - } - break; - case HeaderCodeV.RAR4_NEW_SUB_HEADER: - - { - int datasize = HeaderSize - newLhdSize - nameSize; - if (HasFlag(FileFlagsV4.SALT)) - { - datasize -= saltSize; - } - if (datasize > 0) - { - SubData = reader.ReadBytes(datasize); - } - - if (NewSubHeaderType.SUBHEAD_TYPE_RR.Equals(fileNameBytes)) - { - RecoverySectors = - SubData[8] - + (SubData[9] << 8) - + (SubData[10] << 16) - + (SubData[11] << 24); - } - } - break; - } - - if (HasFlag(FileFlagsV4.SALT)) - { - R4Salt = reader.ReadBytes(saltSize); - } - if (HasFlag(FileFlagsV4.EXT_TIME)) - { - // verify that the end of the header hasn't been reached before reading the Extended Time. - // some tools incorrectly omit Extended Time despite specifying FileFlags.EXTTIME, which most parsers tolerate. - if (RemainingHeaderBytes(reader) >= 2) - { - ushort extendedFlags = reader.ReadUInt16(); - FileLastModifiedTime = ProcessExtendedTimeV4( - extendedFlags, - FileLastModifiedTime, - reader, - 0 - ); - FileCreatedTime = ProcessExtendedTimeV4(extendedFlags, null, reader, 1); - FileLastAccessedTime = ProcessExtendedTimeV4(extendedFlags, null, reader, 2); - FileArchivedTime = ProcessExtendedTimeV4(extendedFlags, null, reader, 3); - } - } - } - - private static long UInt32To64(uint x, uint y) - { - long l = x; - l <<= 32; - return l + y; - } - - private static DateTime? ProcessExtendedTimeV4( - ushort extendedFlags, - DateTime? time, - MarkingBinaryReader reader, - int i - ) - { - uint rmode = (uint)extendedFlags >> (3 - i) * 4; - if ((rmode & 8) == 0) - { - return null; - } - if (i != 0) - { - uint dosTime = reader.ReadUInt32(); - time = Utility.DosDateToDateTime(dosTime); - } - if ((rmode & 4) == 0) - { - time = time.Value.AddSeconds(1); - } - uint nanosecondHundreds = 0; - int count = (int)rmode & 3; - for (int j = 0; j < count; j++) - { - byte b = reader.ReadByte(); - nanosecondHundreds |= (((uint)b) << ((j + 3 - count) * 8)); - } - - //10^-7 to 10^-3 - return time.Value.AddMilliseconds(nanosecondHundreds * Math.Pow(10, -4)); - } - - private static string ConvertPathV4(string path) - { - if (Path.DirectorySeparatorChar == '/') - { - return path.Replace('\\', '/'); - } - else if (Path.DirectorySeparatorChar == '\\') - { - return path.Replace('/', '\\'); - } - return path; - } - - public override string ToString() - { - return FileName; - } - - private ushort Flags { get; set; } - - private bool HasFlag(ushort flag) - { - return (Flags & flag) == flag; - } - - internal uint FileCrc - { - get - { - if (IsRar5 && !HasFlag(FileFlagsV5.HAS_CRC32)) - { - //!!! rar5: - throw new InvalidOperationException("TODO rar5"); - } - return _fileCrc; - } - private set => _fileCrc = value; - } - - // 0 - storing - // 1 - fastest compression - // 2 - fast compression - // 3 - normal compression - // 4 - good compression - // 5 - best compression - internal byte CompressionMethod { get; private set; } - internal bool IsStored => CompressionMethod == 0; - - // eg (see DoUnpack()) - //case 15: // rar 1.5 compression - //case 20: // rar 2.x compression - //case 26: // files larger than 2GB - //case 29: // rar 3.x compression - //case 50: // RAR 5.0 compression algorithm. - internal byte CompressionAlgorithm { get; private set; } - - public bool IsSolid { get; private set; } - - // unused for UnpackV1 implementation (limitation) - internal size_t WindowSize { get; private set; } - - internal byte[] R4Salt { get; private set; } - - private byte HostOs { get; set; } - internal uint FileAttributes { get; private set; } - internal long CompressedSize { get; private set; } - internal long UncompressedSize { get; private set; } - internal string FileName { get; private set; } - internal byte[] SubData { get; private set; } - internal int RecoverySectors { get; private set; } - internal long DataStartPosition { get; set; } - public Stream PackedStream { get; set; } - - public bool IsSplitBefore => - IsRar5 ? HasHeaderFlag(HeaderFlagsV5.SPLIT_BEFORE) : HasFlag(FileFlagsV4.SPLIT_BEFORE); - public bool IsSplitAfter => - IsRar5 ? HasHeaderFlag(HeaderFlagsV5.SPLIT_AFTER) : HasFlag(FileFlagsV4.SPLIT_AFTER); - - public bool IsDirectory => HasFlag(IsRar5 ? FileFlagsV5.DIRECTORY : FileFlagsV4.DIRECTORY); - - private bool isEncryptedRar5 = false; - public bool IsEncrypted => IsRar5 ? isEncryptedRar5 : HasFlag(FileFlagsV4.PASSWORD); - - internal DateTime? FileLastModifiedTime { get; private set; } - - internal DateTime? FileCreatedTime { get; private set; } - - internal DateTime? FileLastAccessedTime { get; private set; } - - internal DateTime? FileArchivedTime { get; private set; } } + + private void ReadFromReaderV5(MarkingBinaryReader reader) + { + Flags = reader.ReadRarVIntUInt16(); + + var lvalue = checked((long)reader.ReadRarVInt()); + + // long.MaxValue causes the unpack code to finish when the input stream is exhausted + UncompressedSize = HasFlag(FileFlagsV5.UNPACKED_SIZE_UNKNOWN) ? long.MaxValue : lvalue; + + FileAttributes = reader.ReadRarVIntUInt32(); + + if (HasFlag(FileFlagsV5.HAS_MOD_TIME)) + { + FileLastModifiedTime = Utility.UnixTimeToDateTime(reader.ReadUInt32()); + } + + if (HasFlag(FileFlagsV5.HAS_CRC32)) + { + FileCrc = reader.ReadUInt32(); + } + + var compressionInfo = reader.ReadRarVIntUInt16(); + + // Lower 6 bits (0x003f mask) contain the version of compression algorithm, resulting in possible 0 - 63 values. Current version is 0. + // "+ 50" to not mix with old RAR format algorithms. For example, + // we may need to use the compression algorithm 15 in the future, + // but it was already used in RAR 1.5 and Unpack needs to distinguish + // them. + CompressionAlgorithm = (byte)((compressionInfo & 0x3f) + 50); + + // 7th bit (0x0040) defines the solid flag. If it is set, RAR continues to use the compression dictionary left after processing preceding files. + // It can be set only for file headers and is never set for service headers. + IsSolid = (compressionInfo & 0x40) == 0x40; + + // Bits 8 - 10 (0x0380 mask) define the compression method. Currently only values 0 - 5 are used. 0 means no compression. + CompressionMethod = (byte)((compressionInfo >> 7) & 0x7); + + // Bits 11 - 14 (0x3c00) define the minimum size of dictionary size required to extract data. Value 0 means 128 KB, 1 - 256 KB, ..., 14 - 2048 MB, 15 - 4096 MB. + WindowSize = IsDirectory ? 0 : ((size_t)0x20000) << ((compressionInfo >> 10) & 0xf); + + HostOs = reader.ReadRarVIntByte(); + + var nameSize = reader.ReadRarVIntUInt16(); + + // Variable length field containing Name length bytes in UTF-8 format without trailing zero. + // For file header this is a name of archived file. Forward slash character is used as the path separator both for Unix and Windows names. + // Backslashes are treated as a part of name for Unix names and as invalid character for Windows file names. Type of name is defined by Host OS field. + // + // TODO: not sure if anything needs to be done to handle the following: + // If Unix file name contains any high ASCII characters which cannot be correctly converted to Unicode and UTF-8 + // we map such characters to to 0xE080 - 0xE0FF private use Unicode area and insert 0xFFFE Unicode non-character + // to resulting string to indicate that it contains mapped characters, which need to be converted back when extracting. + // Concrete position of 0xFFFE is not defined, we need to search the entire string for it. Such mapped names are not + // portable and can be correctly unpacked only on the same system where they were created. + // + // For service header this field contains a name of service header. Now the following names are used: + // CMT Archive comment + // QO Archive quick open data + // ACL NTFS file permissions + // STM NTFS alternate data stream + // RR Recovery record + var b = reader.ReadBytes(nameSize); + FileName = ConvertPathV5(Encoding.UTF8.GetString(b, 0, b.Length)); + + // extra size seems to be redudant since we know the total header size + if (ExtraSize != RemainingHeaderBytes(reader)) + { + throw new InvalidFormatException("rar5 header size / extra size inconsistency"); + } + + isEncryptedRar5 = false; + + while (RemainingHeaderBytes(reader) > 0) + { + var size = reader.ReadRarVIntUInt16(); + var n = RemainingHeaderBytes(reader); + var type = reader.ReadRarVIntUInt16(); + switch (type) + { + //TODO + case 1: // file encryption + + { + isEncryptedRar5 = true; + + //var version = reader.ReadRarVIntByte(); + //if (version != 0) throw new InvalidFormatException("unknown encryption algorithm " + version); + } + break; + // case 2: // file hash + // { + // + // } + // break; + case 3: // file time + + { + var flags = reader.ReadRarVIntUInt16(); + var isWindowsTime = (flags & 1) == 0; + if ((flags & 0x2) == 0x2) + { + FileLastModifiedTime = ReadExtendedTimeV5(reader, isWindowsTime); + } + if ((flags & 0x4) == 0x4) + { + FileCreatedTime = ReadExtendedTimeV5(reader, isWindowsTime); + } + if ((flags & 0x8) == 0x8) + { + FileLastAccessedTime = ReadExtendedTimeV5(reader, isWindowsTime); + } + } + break; + //TODO + // case 4: // file version + // { + // + // } + // break; + // case 5: // file system redirection + // { + // + // } + // break; + // case 6: // unix owner + // { + // + // } + // break; + // case 7: // service data + // { + // + // } + // break; + + default: + // skip unknown record types to allow new record types to be added in the future + break; + } + // drain any trailing bytes of extra record + var did = n - RemainingHeaderBytes(reader); + var drain = size - did; + if (drain > 0) + { + reader.ReadBytes(drain); + } + } + + if (AdditionalDataSize != 0) + { + CompressedSize = AdditionalDataSize; + } + } + + private static DateTime ReadExtendedTimeV5(MarkingBinaryReader reader, bool isWindowsTime) + { + if (isWindowsTime) + { + return DateTime.FromFileTime(reader.ReadInt64()); + } + else + { + return Utility.UnixTimeToDateTime(reader.ReadUInt32()); + } + } + + private static string ConvertPathV5(string path) + { + if (Path.DirectorySeparatorChar == '\\') + { + // replace embedded \\ with valid filename char + return path.Replace('\\', '-').Replace('/', '\\'); + } + return path; + } + + private void ReadFromReaderV4(MarkingBinaryReader reader) + { + Flags = HeaderFlags; + IsSolid = HasFlag(FileFlagsV4.SOLID); + WindowSize = IsDirectory + ? 0U + : ((size_t)0x10000) << ((Flags & FileFlagsV4.WINDOW_MASK) >> 5); + + var lowUncompressedSize = reader.ReadUInt32(); + + HostOs = reader.ReadByte(); + + FileCrc = reader.ReadUInt32(); + + FileLastModifiedTime = Utility.DosDateToDateTime(reader.ReadUInt32()); + + CompressionAlgorithm = reader.ReadByte(); + CompressionMethod = (byte)(reader.ReadByte() - 0x30); + + var nameSize = reader.ReadInt16(); + + FileAttributes = reader.ReadUInt32(); + + uint highCompressedSize = 0; + uint highUncompressedkSize = 0; + if (HasFlag(FileFlagsV4.LARGE)) + { + highCompressedSize = reader.ReadUInt32(); + highUncompressedkSize = reader.ReadUInt32(); + } + else + { + if (lowUncompressedSize == 0xffffffff) + { + lowUncompressedSize = 0xffffffff; + highUncompressedkSize = int.MaxValue; + } + } + CompressedSize = UInt32To64(highCompressedSize, checked((uint)AdditionalDataSize)); + UncompressedSize = UInt32To64(highUncompressedkSize, lowUncompressedSize); + + nameSize = nameSize > 4 * 1024 ? (short)(4 * 1024) : nameSize; + + var fileNameBytes = reader.ReadBytes(nameSize); + + const int saltSize = 8; + const int newLhdSize = 32; + + switch (HeaderCode) + { + case HeaderCodeV.RAR4_FILE_HEADER: + + { + if (HasFlag(FileFlagsV4.UNICODE)) + { + var length = 0; + while (length < fileNameBytes.Length && fileNameBytes[length] != 0) + { + length++; + } + if (length != nameSize) + { + length++; + FileName = FileNameDecoder.Decode(fileNameBytes, length); + } + else + { + FileName = ArchiveEncoding.Decode(fileNameBytes); + } + } + else + { + FileName = ArchiveEncoding.Decode(fileNameBytes); + } + FileName = ConvertPathV4(FileName); + } + break; + case HeaderCodeV.RAR4_NEW_SUB_HEADER: + + { + var datasize = HeaderSize - newLhdSize - nameSize; + if (HasFlag(FileFlagsV4.SALT)) + { + datasize -= saltSize; + } + if (datasize > 0) + { + SubData = reader.ReadBytes(datasize); + } + + if (NewSubHeaderType.SUBHEAD_TYPE_RR.Equals(fileNameBytes)) + { + RecoverySectors = + SubData[8] + + (SubData[9] << 8) + + (SubData[10] << 16) + + (SubData[11] << 24); + } + } + break; + } + + if (HasFlag(FileFlagsV4.SALT)) + { + R4Salt = reader.ReadBytes(saltSize); + } + if (HasFlag(FileFlagsV4.EXT_TIME)) + { + // verify that the end of the header hasn't been reached before reading the Extended Time. + // some tools incorrectly omit Extended Time despite specifying FileFlags.EXTTIME, which most parsers tolerate. + if (RemainingHeaderBytes(reader) >= 2) + { + var extendedFlags = reader.ReadUInt16(); + FileLastModifiedTime = ProcessExtendedTimeV4( + extendedFlags, + FileLastModifiedTime, + reader, + 0 + ); + FileCreatedTime = ProcessExtendedTimeV4(extendedFlags, null, reader, 1); + FileLastAccessedTime = ProcessExtendedTimeV4(extendedFlags, null, reader, 2); + FileArchivedTime = ProcessExtendedTimeV4(extendedFlags, null, reader, 3); + } + } + } + + private static long UInt32To64(uint x, uint y) + { + long l = x; + l <<= 32; + return l + y; + } + + private static DateTime? ProcessExtendedTimeV4( + ushort extendedFlags, + DateTime? time, + MarkingBinaryReader reader, + int i + ) + { + var rmode = (uint)extendedFlags >> ((3 - i) * 4); + if ((rmode & 8) == 0) + { + return null; + } + if (i != 0) + { + var dosTime = reader.ReadUInt32(); + time = Utility.DosDateToDateTime(dosTime); + } + if ((rmode & 4) == 0) + { + time = time.Value.AddSeconds(1); + } + uint nanosecondHundreds = 0; + var count = (int)rmode & 3; + for (var j = 0; j < count; j++) + { + var b = reader.ReadByte(); + nanosecondHundreds |= (((uint)b) << ((j + 3 - count) * 8)); + } + + //10^-7 to 10^-3 + return time.Value.AddMilliseconds(nanosecondHundreds * Math.Pow(10, -4)); + } + + private static string ConvertPathV4(string path) + { + if (Path.DirectorySeparatorChar == '/') + { + return path.Replace('\\', '/'); + } + else if (Path.DirectorySeparatorChar == '\\') + { + return path.Replace('/', '\\'); + } + return path; + } + + public override string ToString() + { + return FileName; + } + + private ushort Flags { get; set; } + + private bool HasFlag(ushort flag) + { + return (Flags & flag) == flag; + } + + internal uint FileCrc + { + get + { + if (IsRar5 && !HasFlag(FileFlagsV5.HAS_CRC32)) + { + //!!! rar5: + throw new InvalidOperationException("TODO rar5"); + } + return _fileCrc; + } + private set => _fileCrc = value; + } + + // 0 - storing + // 1 - fastest compression + // 2 - fast compression + // 3 - normal compression + // 4 - good compression + // 5 - best compression + internal byte CompressionMethod { get; private set; } + internal bool IsStored => CompressionMethod == 0; + + // eg (see DoUnpack()) + //case 15: // rar 1.5 compression + //case 20: // rar 2.x compression + //case 26: // files larger than 2GB + //case 29: // rar 3.x compression + //case 50: // RAR 5.0 compression algorithm. + internal byte CompressionAlgorithm { get; private set; } + + public bool IsSolid { get; private set; } + + // unused for UnpackV1 implementation (limitation) + internal size_t WindowSize { get; private set; } + + internal byte[] R4Salt { get; private set; } + + private byte HostOs { get; set; } + internal uint FileAttributes { get; private set; } + internal long CompressedSize { get; private set; } + internal long UncompressedSize { get; private set; } + internal string FileName { get; private set; } + internal byte[] SubData { get; private set; } + internal int RecoverySectors { get; private set; } + internal long DataStartPosition { get; set; } + public Stream PackedStream { get; set; } + + public bool IsSplitBefore => + IsRar5 ? HasHeaderFlag(HeaderFlagsV5.SPLIT_BEFORE) : HasFlag(FileFlagsV4.SPLIT_BEFORE); + public bool IsSplitAfter => + IsRar5 ? HasHeaderFlag(HeaderFlagsV5.SPLIT_AFTER) : HasFlag(FileFlagsV4.SPLIT_AFTER); + + public bool IsDirectory => HasFlag(IsRar5 ? FileFlagsV5.DIRECTORY : FileFlagsV4.DIRECTORY); + + private bool isEncryptedRar5 = false; + public bool IsEncrypted => IsRar5 ? isEncryptedRar5 : HasFlag(FileFlagsV4.PASSWORD); + + internal DateTime? FileLastModifiedTime { get; private set; } + + internal DateTime? FileCreatedTime { get; private set; } + + internal DateTime? FileLastAccessedTime { get; private set; } + + internal DateTime? FileArchivedTime { get; private set; } } diff --git a/src/SharpCompress/Common/Rar/Headers/FileNameDecoder.cs b/src/SharpCompress/Common/Rar/Headers/FileNameDecoder.cs index f2afaa39..c6b85001 100644 --- a/src/SharpCompress/Common/Rar/Headers/FileNameDecoder.cs +++ b/src/SharpCompress/Common/Rar/Headers/FileNameDecoder.cs @@ -1,86 +1,85 @@ using System.Text; -namespace SharpCompress.Common.Rar.Headers +namespace SharpCompress.Common.Rar.Headers; + +/// +/// This is for the crazy Rar encoding that I don't understand +/// +internal static class FileNameDecoder { - /// - /// This is for the crazy Rar encoding that I don't understand - /// - internal static class FileNameDecoder + internal static int GetChar(byte[] name, int pos) { - internal static int GetChar(byte[] name, int pos) - { - return name[pos] & 0xff; - } + return name[pos] & 0xff; + } - internal static string Decode(byte[] name, int encPos) - { - int decPos = 0; - int flags = 0; - int flagBits = 0; + internal static string Decode(byte[] name, int encPos) + { + var decPos = 0; + var flags = 0; + var flagBits = 0; - int low = 0; - int high = 0; - int highByte = GetChar(name, encPos++); - StringBuilder buf = new StringBuilder(); - while (encPos < name.Length) + var low = 0; + var high = 0; + var highByte = GetChar(name, encPos++); + var buf = new StringBuilder(); + while (encPos < name.Length) + { + if (flagBits == 0) { - if (flagBits == 0) - { - flags = GetChar(name, encPos++); - flagBits = 8; - } - switch (flags >> 6) - { - case 0: - buf.Append((char)(GetChar(name, encPos++))); - ++decPos; - break; - - case 1: - buf.Append((char)(GetChar(name, encPos++) + (highByte << 8))); - ++decPos; - break; - - case 2: - low = GetChar(name, encPos); - high = GetChar(name, encPos + 1); - buf.Append((char)((high << 8) + low)); - ++decPos; - encPos += 2; - break; - - case 3: - int length = GetChar(name, encPos++); - if ((length & 0x80) != 0) - { - int correction = GetChar(name, encPos++); - for ( - length = (length & 0x7f) + 2; - length > 0 && decPos < name.Length; - length--, decPos++ - ) - { - low = (GetChar(name, decPos) + correction) & 0xff; - buf.Append((char)((highByte << 8) + low)); - } - } - else - { - for ( - length += 2; - length > 0 && decPos < name.Length; - length--, decPos++ - ) - { - buf.Append((char)(GetChar(name, decPos))); - } - } - break; - } - flags = (flags << 2) & 0xff; - flagBits -= 2; + flags = GetChar(name, encPos++); + flagBits = 8; } - return buf.ToString(); + switch (flags >> 6) + { + case 0: + buf.Append((char)(GetChar(name, encPos++))); + ++decPos; + break; + + case 1: + buf.Append((char)(GetChar(name, encPos++) + (highByte << 8))); + ++decPos; + break; + + case 2: + low = GetChar(name, encPos); + high = GetChar(name, encPos + 1); + buf.Append((char)((high << 8) + low)); + ++decPos; + encPos += 2; + break; + + case 3: + var length = GetChar(name, encPos++); + if ((length & 0x80) != 0) + { + var correction = GetChar(name, encPos++); + for ( + length = (length & 0x7f) + 2; + length > 0 && decPos < name.Length; + length--, decPos++ + ) + { + low = (GetChar(name, decPos) + correction) & 0xff; + buf.Append((char)((highByte << 8) + low)); + } + } + else + { + for ( + length += 2; + length > 0 && decPos < name.Length; + length--, decPos++ + ) + { + buf.Append((char)(GetChar(name, decPos))); + } + } + break; + } + flags = (flags << 2) & 0xff; + flagBits -= 2; } + return buf.ToString(); } } diff --git a/src/SharpCompress/Common/Rar/Headers/Flags.cs b/src/SharpCompress/Common/Rar/Headers/Flags.cs index 7f6ad0aa..5a52f001 100644 --- a/src/SharpCompress/Common/Rar/Headers/Flags.cs +++ b/src/SharpCompress/Common/Rar/Headers/Flags.cs @@ -1,149 +1,148 @@ -namespace SharpCompress.Common.Rar.Headers +namespace SharpCompress.Common.Rar.Headers; + +public enum HeaderType : byte { - public enum HeaderType : byte - { - Null, - Mark, - Archive, - File, - Service, - Comment, - Av, - Protect, - Sign, - NewSub, - EndArchive, - Crypt - } - - internal static class HeaderCodeV - { - public const byte RAR4_MARK_HEADER = 0x72; - public const byte RAR4_ARCHIVE_HEADER = 0x73; - public const byte RAR4_FILE_HEADER = 0x74; - public const byte RAR4_COMMENT_HEADER = 0x75; - public const byte RAR4_AV_HEADER = 0x76; - public const byte RAR4_SUB_HEADER = 0x77; - public const byte RAR4_PROTECT_HEADER = 0x78; - public const byte RAR4_SIGN_HEADER = 0x79; - public const byte RAR4_NEW_SUB_HEADER = 0x7a; - public const byte RAR4_END_ARCHIVE_HEADER = 0x7b; - - public const byte RAR5_ARCHIVE_HEADER = 0x01; - public const byte RAR5_FILE_HEADER = 0x02; - public const byte RAR5_SERVICE_HEADER = 0x03; - public const byte RAR5_ARCHIVE_ENCRYPTION_HEADER = 0x04; - public const byte RAR5_END_ARCHIVE_HEADER = 0x05; - } - - internal static class HeaderFlagsV4 - { - public const ushort HAS_DATA = 0x8000; - } - - internal static class EncryptionFlagsV5 - { - // RAR 5.0 archive encryption header specific flags. - public const uint CHFL_CRYPT_PSWCHECK = 0x01; // Password check data is present. - - public const uint FHEXTRA_CRYPT_PSWCHECK = 0x01; // Password check data is present. - public const uint FHEXTRA_CRYPT_HASHMAC = 0x02; - } - - internal static class HeaderFlagsV5 - { - public const ushort HAS_EXTRA = 0x0001; - public const ushort HAS_DATA = 0x0002; - public const ushort KEEP = 0x0004; // block must be kept during an update - public const ushort SPLIT_BEFORE = 0x0008; - public const ushort SPLIT_AFTER = 0x0010; - public const ushort CHILD = 0x0020; // ??? Block depends on preceding file block. - public const ushort PRESERVE_CHILD = 0x0040; // ???? Preserve a child block if host block is modified - } - - internal static class ArchiveFlagsV4 - { - public const ushort VOLUME = 0x0001; - public const ushort COMMENT = 0x0002; - public const ushort LOCK = 0x0004; - public const ushort SOLID = 0x0008; - public const ushort NEW_NUMBERING = 0x0010; - public const ushort AV = 0x0020; - public const ushort PROTECT = 0x0040; - public const ushort PASSWORD = 0x0080; - public const ushort FIRST_VOLUME = 0x0100; - public const ushort ENCRYPT_VER = 0x0200; - } - - internal static class ArchiveFlagsV5 - { - public const ushort VOLUME = 0x0001; - public const ushort HAS_VOLUME_NUMBER = 0x0002; - public const ushort SOLID = 0x0004; - public const ushort PROTECT = 0x0008; - public const ushort LOCK = 0x0010; - } - - internal static class HostOsV4 - { - public const byte MS_DOS = 0; - public const byte OS2 = 1; - public const byte WIN32 = 2; - public const byte UNIX = 3; - public const byte MAC_OS = 4; - public const byte BE_OS = 5; - } - - internal static class HostOsV5 - { - public const byte WINDOWS = 0; - public const byte UNIX = 1; - } - - internal static class FileFlagsV4 - { - public const ushort SPLIT_BEFORE = 0x0001; - public const ushort SPLIT_AFTER = 0x0002; - public const ushort PASSWORD = 0x0004; - public const ushort COMMENT = 0x0008; - public const ushort SOLID = 0x0010; - - public const ushort WINDOW_MASK = 0x00e0; - public const ushort WINDOW64 = 0x0000; - public const ushort WINDOW128 = 0x0020; - public const ushort WINDOW256 = 0x0040; - public const ushort WINDOW512 = 0x0060; - public const ushort WINDOW1024 = 0x0080; - public const ushort WINDOW2048 = 0x00a0; - public const ushort WINDOW4096 = 0x00c0; - public const ushort DIRECTORY = 0x00e0; - - public const ushort LARGE = 0x0100; - public const ushort UNICODE = 0x0200; - public const ushort SALT = 0x0400; - public const ushort VERSION = 0x0800; - public const ushort EXT_TIME = 0x1000; - public const ushort EXT_FLAGS = 0x2000; - } - - internal static class FileFlagsV5 - { - public const ushort DIRECTORY = 0x0001; - public const ushort HAS_MOD_TIME = 0x0002; - public const ushort HAS_CRC32 = 0x0004; - public const ushort UNPACKED_SIZE_UNKNOWN = 0x0008; - } - - internal static class EndArchiveFlagsV4 - { - public const ushort NEXT_VOLUME = 0x0001; - public const ushort DATA_CRC = 0x0002; - public const ushort REV_SPACE = 0x0004; - public const ushort VOLUME_NUMBER = 0x0008; - } - - internal static class EndArchiveFlagsV5 - { - public const ushort HAS_NEXT_VOLUME = 0x0001; - } + Null, + Mark, + Archive, + File, + Service, + Comment, + Av, + Protect, + Sign, + NewSub, + EndArchive, + Crypt +} + +internal static class HeaderCodeV +{ + public const byte RAR4_MARK_HEADER = 0x72; + public const byte RAR4_ARCHIVE_HEADER = 0x73; + public const byte RAR4_FILE_HEADER = 0x74; + public const byte RAR4_COMMENT_HEADER = 0x75; + public const byte RAR4_AV_HEADER = 0x76; + public const byte RAR4_SUB_HEADER = 0x77; + public const byte RAR4_PROTECT_HEADER = 0x78; + public const byte RAR4_SIGN_HEADER = 0x79; + public const byte RAR4_NEW_SUB_HEADER = 0x7a; + public const byte RAR4_END_ARCHIVE_HEADER = 0x7b; + + public const byte RAR5_ARCHIVE_HEADER = 0x01; + public const byte RAR5_FILE_HEADER = 0x02; + public const byte RAR5_SERVICE_HEADER = 0x03; + public const byte RAR5_ARCHIVE_ENCRYPTION_HEADER = 0x04; + public const byte RAR5_END_ARCHIVE_HEADER = 0x05; +} + +internal static class HeaderFlagsV4 +{ + public const ushort HAS_DATA = 0x8000; +} + +internal static class EncryptionFlagsV5 +{ + // RAR 5.0 archive encryption header specific flags. + public const uint CHFL_CRYPT_PSWCHECK = 0x01; // Password check data is present. + + public const uint FHEXTRA_CRYPT_PSWCHECK = 0x01; // Password check data is present. + public const uint FHEXTRA_CRYPT_HASHMAC = 0x02; +} + +internal static class HeaderFlagsV5 +{ + public const ushort HAS_EXTRA = 0x0001; + public const ushort HAS_DATA = 0x0002; + public const ushort KEEP = 0x0004; // block must be kept during an update + public const ushort SPLIT_BEFORE = 0x0008; + public const ushort SPLIT_AFTER = 0x0010; + public const ushort CHILD = 0x0020; // ??? Block depends on preceding file block. + public const ushort PRESERVE_CHILD = 0x0040; // ???? Preserve a child block if host block is modified +} + +internal static class ArchiveFlagsV4 +{ + public const ushort VOLUME = 0x0001; + public const ushort COMMENT = 0x0002; + public const ushort LOCK = 0x0004; + public const ushort SOLID = 0x0008; + public const ushort NEW_NUMBERING = 0x0010; + public const ushort AV = 0x0020; + public const ushort PROTECT = 0x0040; + public const ushort PASSWORD = 0x0080; + public const ushort FIRST_VOLUME = 0x0100; + public const ushort ENCRYPT_VER = 0x0200; +} + +internal static class ArchiveFlagsV5 +{ + public const ushort VOLUME = 0x0001; + public const ushort HAS_VOLUME_NUMBER = 0x0002; + public const ushort SOLID = 0x0004; + public const ushort PROTECT = 0x0008; + public const ushort LOCK = 0x0010; +} + +internal static class HostOsV4 +{ + public const byte MS_DOS = 0; + public const byte OS2 = 1; + public const byte WIN32 = 2; + public const byte UNIX = 3; + public const byte MAC_OS = 4; + public const byte BE_OS = 5; +} + +internal static class HostOsV5 +{ + public const byte WINDOWS = 0; + public const byte UNIX = 1; +} + +internal static class FileFlagsV4 +{ + public const ushort SPLIT_BEFORE = 0x0001; + public const ushort SPLIT_AFTER = 0x0002; + public const ushort PASSWORD = 0x0004; + public const ushort COMMENT = 0x0008; + public const ushort SOLID = 0x0010; + + public const ushort WINDOW_MASK = 0x00e0; + public const ushort WINDOW64 = 0x0000; + public const ushort WINDOW128 = 0x0020; + public const ushort WINDOW256 = 0x0040; + public const ushort WINDOW512 = 0x0060; + public const ushort WINDOW1024 = 0x0080; + public const ushort WINDOW2048 = 0x00a0; + public const ushort WINDOW4096 = 0x00c0; + public const ushort DIRECTORY = 0x00e0; + + public const ushort LARGE = 0x0100; + public const ushort UNICODE = 0x0200; + public const ushort SALT = 0x0400; + public const ushort VERSION = 0x0800; + public const ushort EXT_TIME = 0x1000; + public const ushort EXT_FLAGS = 0x2000; +} + +internal static class FileFlagsV5 +{ + public const ushort DIRECTORY = 0x0001; + public const ushort HAS_MOD_TIME = 0x0002; + public const ushort HAS_CRC32 = 0x0004; + public const ushort UNPACKED_SIZE_UNKNOWN = 0x0008; +} + +internal static class EndArchiveFlagsV4 +{ + public const ushort NEXT_VOLUME = 0x0001; + public const ushort DATA_CRC = 0x0002; + public const ushort REV_SPACE = 0x0004; + public const ushort VOLUME_NUMBER = 0x0008; +} + +internal static class EndArchiveFlagsV5 +{ + public const ushort HAS_NEXT_VOLUME = 0x0001; } diff --git a/src/SharpCompress/Common/Rar/Headers/IRarHeader.cs b/src/SharpCompress/Common/Rar/Headers/IRarHeader.cs index a168690c..17a1a930 100644 --- a/src/SharpCompress/Common/Rar/Headers/IRarHeader.cs +++ b/src/SharpCompress/Common/Rar/Headers/IRarHeader.cs @@ -1,7 +1,6 @@ -namespace SharpCompress.Common.Rar.Headers +namespace SharpCompress.Common.Rar.Headers; + +public interface IRarHeader { - public interface IRarHeader - { - HeaderType HeaderType { get; } - } + HeaderType HeaderType { get; } } diff --git a/src/SharpCompress/Common/Rar/Headers/MarkHeader.cs b/src/SharpCompress/Common/Rar/Headers/MarkHeader.cs index 8416270d..d359aef4 100644 --- a/src/SharpCompress/Common/Rar/Headers/MarkHeader.cs +++ b/src/SharpCompress/Common/Rar/Headers/MarkHeader.cs @@ -1,136 +1,135 @@ using System; using System.IO; -namespace SharpCompress.Common.Rar.Headers +namespace SharpCompress.Common.Rar.Headers; + +internal class MarkHeader : IRarHeader { - internal class MarkHeader : IRarHeader + private const int MAX_SFX_SIZE = 0x80000 - 16; //archive.cpp line 136 + + internal bool OldNumberingFormat { get; private set; } + + public bool IsRar5 { get; } + + private MarkHeader(bool isRar5) { - private const int MAX_SFX_SIZE = 0x80000 - 16; //archive.cpp line 136 + IsRar5 = isRar5; + } - internal bool OldNumberingFormat { get; private set; } + public HeaderType HeaderType => HeaderType.Mark; - public bool IsRar5 { get; } - - private MarkHeader(bool isRar5) + private static byte GetByte(Stream stream) + { + var b = stream.ReadByte(); + if (b != -1) { - IsRar5 = isRar5; + return (byte)b; } + throw new EndOfStreamException(); + } - public HeaderType HeaderType => HeaderType.Mark; - - private static byte GetByte(Stream stream) + public static MarkHeader Read(Stream stream, bool leaveStreamOpen, bool lookForHeader) + { + var maxScanIndex = lookForHeader ? MAX_SFX_SIZE : 0; + try { - var b = stream.ReadByte(); - if (b != -1) + var start = -1; + var b = GetByte(stream); + start++; + while (start <= maxScanIndex) { - return (byte)b; - } - throw new EndOfStreamException(); - } - - public static MarkHeader Read(Stream stream, bool leaveStreamOpen, bool lookForHeader) - { - int maxScanIndex = lookForHeader ? MAX_SFX_SIZE : 0; - try - { - int start = -1; - var b = GetByte(stream); - start++; - while (start <= maxScanIndex) + // Rar old signature: 52 45 7E 5E + // Rar4 signature: 52 61 72 21 1A 07 00 + // Rar5 signature: 52 61 72 21 1A 07 01 00 + if (b == 0x52) { - // Rar old signature: 52 45 7E 5E - // Rar4 signature: 52 61 72 21 1A 07 00 - // Rar5 signature: 52 61 72 21 1A 07 01 00 - if (b == 0x52) + b = GetByte(stream); + start++; + if (b == 0x61) { b = GetByte(stream); start++; - if (b == 0x61) + if (b != 0x72) { - b = GetByte(stream); - start++; - if (b != 0x72) - { - continue; - } - - b = GetByte(stream); - start++; - if (b != 0x21) - { - continue; - } - - b = GetByte(stream); - start++; - if (b != 0x1a) - { - continue; - } - - b = GetByte(stream); - start++; - if (b != 0x07) - { - continue; - } - - b = GetByte(stream); - start++; - if (b == 1) - { - b = GetByte(stream); - start++; - if (b != 0) - { - continue; - } - - return new MarkHeader(true); // Rar5 - } - else if (b == 0) - { - return new MarkHeader(false); // Rar4 - } + continue; } - else if (b == 0x45) + + b = GetByte(stream); + start++; + if (b != 0x21) + { + continue; + } + + b = GetByte(stream); + start++; + if (b != 0x1a) + { + continue; + } + + b = GetByte(stream); + start++; + if (b != 0x07) + { + continue; + } + + b = GetByte(stream); + start++; + if (b == 1) { b = GetByte(stream); start++; - if (b != 0x7e) + if (b != 0) { continue; } - b = GetByte(stream); - start++; - if (b != 0x5e) - { - continue; - } - - throw new InvalidFormatException( - "Rar format version pre-4 is unsupported." - ); + return new MarkHeader(true); // Rar5 + } + else if (b == 0) + { + return new MarkHeader(false); // Rar4 } } - else + else if (b == 0x45) { b = GetByte(stream); start++; + if (b != 0x7e) + { + continue; + } + + b = GetByte(stream); + start++; + if (b != 0x5e) + { + continue; + } + + throw new InvalidFormatException( + "Rar format version pre-4 is unsupported." + ); } } - } - catch (Exception e) - { - if (!leaveStreamOpen) + else { - stream.Dispose(); + b = GetByte(stream); + start++; } - throw new InvalidFormatException("Error trying to read rar signature.", e); } - - throw new InvalidFormatException("Rar signature not found"); } + catch (Exception e) + { + if (!leaveStreamOpen) + { + stream.Dispose(); + } + throw new InvalidFormatException("Error trying to read rar signature.", e); + } + + throw new InvalidFormatException("Rar signature not found"); } } diff --git a/src/SharpCompress/Common/Rar/Headers/NewSubHeaderType.cs b/src/SharpCompress/Common/Rar/Headers/NewSubHeaderType.cs index 9814d6bc..01b2ffc0 100644 --- a/src/SharpCompress/Common/Rar/Headers/NewSubHeaderType.cs +++ b/src/SharpCompress/Common/Rar/Headers/NewSubHeaderType.cs @@ -1,49 +1,48 @@ -using System; +using System; -namespace SharpCompress.Common.Rar.Headers +namespace SharpCompress.Common.Rar.Headers; + +internal sealed class NewSubHeaderType : IEquatable { - internal sealed class NewSubHeaderType : IEquatable + internal static readonly NewSubHeaderType SUBHEAD_TYPE_CMT = new('C', 'M', 'T'); + + //internal static final NewSubHeaderType SUBHEAD_TYPE_ACL = new (new byte[]{'A','C','L'}); + + //internal static final NewSubHeaderType SUBHEAD_TYPE_STREAM = new (new byte[]{'S','T','M'}); + + //internal static final NewSubHeaderType SUBHEAD_TYPE_UOWNER = new (new byte[]{'U','O','W'}); + + //internal static final NewSubHeaderType SUBHEAD_TYPE_AV = new (new byte[]{'A','V'}); + + internal static readonly NewSubHeaderType SUBHEAD_TYPE_RR = new('R', 'R'); + + //internal static final NewSubHeaderType SUBHEAD_TYPE_OS2EA = new (new byte[]{'E','A','2'}); + + //internal static final NewSubHeaderType SUBHEAD_TYPE_BEOSEA = new (new byte[]{'E','A','B','E'}); + + private readonly byte[] _bytes; + + private NewSubHeaderType(params char[] chars) { - internal static readonly NewSubHeaderType SUBHEAD_TYPE_CMT = new('C', 'M', 'T'); - - //internal static final NewSubHeaderType SUBHEAD_TYPE_ACL = new (new byte[]{'A','C','L'}); - - //internal static final NewSubHeaderType SUBHEAD_TYPE_STREAM = new (new byte[]{'S','T','M'}); - - //internal static final NewSubHeaderType SUBHEAD_TYPE_UOWNER = new (new byte[]{'U','O','W'}); - - //internal static final NewSubHeaderType SUBHEAD_TYPE_AV = new (new byte[]{'A','V'}); - - internal static readonly NewSubHeaderType SUBHEAD_TYPE_RR = new('R', 'R'); - - //internal static final NewSubHeaderType SUBHEAD_TYPE_OS2EA = new (new byte[]{'E','A','2'}); - - //internal static final NewSubHeaderType SUBHEAD_TYPE_BEOSEA = new (new byte[]{'E','A','B','E'}); - - private readonly byte[] _bytes; - - private NewSubHeaderType(params char[] chars) + _bytes = new byte[chars.Length]; + for (var i = 0; i < chars.Length; ++i) { - _bytes = new byte[chars.Length]; - for (int i = 0; i < chars.Length; ++i) - { - _bytes[i] = (byte)chars[i]; - } - } - - internal bool Equals(byte[] bytes) - { - if (_bytes.Length != bytes.Length) - { - return false; - } - - return _bytes.AsSpan().SequenceEqual(bytes); - } - - public bool Equals(NewSubHeaderType? other) - { - return other is not null && Equals(other._bytes); + _bytes[i] = (byte)chars[i]; } } + + internal bool Equals(byte[] bytes) + { + if (_bytes.Length != bytes.Length) + { + return false; + } + + return _bytes.AsSpan().SequenceEqual(bytes); + } + + public bool Equals(NewSubHeaderType? other) + { + return other is not null && Equals(other._bytes); + } } diff --git a/src/SharpCompress/Common/Rar/Headers/ProtectHeader.cs b/src/SharpCompress/Common/Rar/Headers/ProtectHeader.cs index 9785f369..cf8db3c0 100644 --- a/src/SharpCompress/Common/Rar/Headers/ProtectHeader.cs +++ b/src/SharpCompress/Common/Rar/Headers/ProtectHeader.cs @@ -1,31 +1,30 @@ -using SharpCompress.IO; +using SharpCompress.IO; -namespace SharpCompress.Common.Rar.Headers +namespace SharpCompress.Common.Rar.Headers; + +// ProtectHeader is part of the Recovery Record feature +internal sealed class ProtectHeader : RarHeader { - // ProtectHeader is part of the Recovery Record feature - internal sealed class ProtectHeader : RarHeader + public ProtectHeader(RarHeader header, RarCrcBinaryReader reader) + : base(header, reader, HeaderType.Protect) { - public ProtectHeader(RarHeader header, RarCrcBinaryReader reader) - : base(header, reader, HeaderType.Protect) + if (IsRar5) { - if (IsRar5) - { - throw new InvalidFormatException("unexpected rar5 record"); - } + throw new InvalidFormatException("unexpected rar5 record"); } - - protected override void ReadFinish(MarkingBinaryReader reader) - { - Version = reader.ReadByte(); - RecSectors = reader.ReadUInt16(); - TotalBlocks = reader.ReadUInt32(); - Mark = reader.ReadBytes(8); - } - - internal uint DataSize => checked((uint)AdditionalDataSize); - internal byte Version { get; private set; } - internal ushort RecSectors { get; private set; } - internal uint TotalBlocks { get; private set; } - internal byte[]? Mark { get; private set; } } + + protected override void ReadFinish(MarkingBinaryReader reader) + { + Version = reader.ReadByte(); + RecSectors = reader.ReadUInt16(); + TotalBlocks = reader.ReadUInt32(); + Mark = reader.ReadBytes(8); + } + + internal uint DataSize => checked((uint)AdditionalDataSize); + internal byte Version { get; private set; } + internal ushort RecSectors { get; private set; } + internal uint TotalBlocks { get; private set; } + internal byte[]? Mark { get; private set; } } diff --git a/src/SharpCompress/Common/Rar/Headers/RarHeader.cs b/src/SharpCompress/Common/Rar/Headers/RarHeader.cs index 732bfab4..571da972 100644 --- a/src/SharpCompress/Common/Rar/Headers/RarHeader.cs +++ b/src/SharpCompress/Common/Rar/Headers/RarHeader.cs @@ -1,138 +1,137 @@ -using System; +using System; using System.IO; using SharpCompress.IO; -namespace SharpCompress.Common.Rar.Headers +namespace SharpCompress.Common.Rar.Headers; + +// http://www.forensicswiki.org/w/images/5/5b/RARFileStructure.txt +// https://www.rarlab.com/technote.htm +internal class RarHeader : IRarHeader { - // http://www.forensicswiki.org/w/images/5/5b/RARFileStructure.txt - // https://www.rarlab.com/technote.htm - internal class RarHeader : IRarHeader + private readonly HeaderType _headerType; + private readonly bool _isRar5; + + internal static RarHeader? TryReadBase( + RarCrcBinaryReader reader, + bool isRar5, + ArchiveEncoding archiveEncoding + ) { - private readonly HeaderType _headerType; - private readonly bool _isRar5; - - internal static RarHeader? TryReadBase( - RarCrcBinaryReader reader, - bool isRar5, - ArchiveEncoding archiveEncoding - ) + try { - try - { - return new RarHeader(reader, isRar5, archiveEncoding); - } - catch (EndOfStreamException) - { - return null; - } + return new RarHeader(reader, isRar5, archiveEncoding); } - - private RarHeader(RarCrcBinaryReader reader, bool isRar5, ArchiveEncoding archiveEncoding) + catch (EndOfStreamException) { - _headerType = HeaderType.Null; - _isRar5 = isRar5; - ArchiveEncoding = archiveEncoding; - if (IsRar5) - { - HeaderCrc = reader.ReadUInt32(); - reader.ResetCrc(); - HeaderSize = (int)reader.ReadRarVIntUInt32(3); - reader.Mark(); - HeaderCode = reader.ReadRarVIntByte(); - HeaderFlags = reader.ReadRarVIntUInt16(2); - - if (HasHeaderFlag(HeaderFlagsV5.HAS_EXTRA)) - { - ExtraSize = reader.ReadRarVIntUInt32(); - } - if (HasHeaderFlag(HeaderFlagsV5.HAS_DATA)) - { - AdditionalDataSize = (long)reader.ReadRarVInt(); - } - } - else - { - reader.Mark(); - HeaderCrc = reader.ReadUInt16(); - reader.ResetCrc(); - HeaderCode = reader.ReadByte(); - HeaderFlags = reader.ReadUInt16(); - HeaderSize = reader.ReadInt16(); - if (HasHeaderFlag(HeaderFlagsV4.HAS_DATA)) - { - AdditionalDataSize = reader.ReadUInt32(); - } - } + return null; } - - protected RarHeader(RarHeader header, RarCrcBinaryReader reader, HeaderType headerType) - { - _headerType = headerType; - _isRar5 = header.IsRar5; - HeaderCrc = header.HeaderCrc; - HeaderCode = header.HeaderCode; - HeaderFlags = header.HeaderFlags; - HeaderSize = header.HeaderSize; - ExtraSize = header.ExtraSize; - AdditionalDataSize = header.AdditionalDataSize; - ArchiveEncoding = header.ArchiveEncoding; - ReadFinish(reader); - - int n = RemainingHeaderBytes(reader); - if (n > 0) - { - reader.ReadBytes(n); - } - - VerifyHeaderCrc(reader.GetCrc32()); - } - - protected int RemainingHeaderBytes(MarkingBinaryReader reader) - { - return checked(HeaderSize - (int)reader.CurrentReadByteCount); - } - - protected virtual void ReadFinish(MarkingBinaryReader reader) - { - throw new NotImplementedException(); - } - - private void VerifyHeaderCrc(uint crc32) - { - var b = (IsRar5 ? crc32 : (ushort)crc32) == HeaderCrc; - if (!b) - { - throw new InvalidFormatException("rar header crc mismatch"); - } - } - - public HeaderType HeaderType => _headerType; - - protected bool IsRar5 => _isRar5; - - protected uint HeaderCrc { get; } - - internal byte HeaderCode { get; } - - protected ushort HeaderFlags { get; } - - protected bool HasHeaderFlag(ushort flag) - { - return (HeaderFlags & flag) == flag; - } - - protected int HeaderSize { get; } - - internal ArchiveEncoding ArchiveEncoding { get; } - - /// - /// Extra header size. - /// - protected uint ExtraSize { get; } - - /// - /// Size of additional data (eg file contents) - /// - protected long AdditionalDataSize { get; } } + + private RarHeader(RarCrcBinaryReader reader, bool isRar5, ArchiveEncoding archiveEncoding) + { + _headerType = HeaderType.Null; + _isRar5 = isRar5; + ArchiveEncoding = archiveEncoding; + if (IsRar5) + { + HeaderCrc = reader.ReadUInt32(); + reader.ResetCrc(); + HeaderSize = (int)reader.ReadRarVIntUInt32(3); + reader.Mark(); + HeaderCode = reader.ReadRarVIntByte(); + HeaderFlags = reader.ReadRarVIntUInt16(2); + + if (HasHeaderFlag(HeaderFlagsV5.HAS_EXTRA)) + { + ExtraSize = reader.ReadRarVIntUInt32(); + } + if (HasHeaderFlag(HeaderFlagsV5.HAS_DATA)) + { + AdditionalDataSize = (long)reader.ReadRarVInt(); + } + } + else + { + reader.Mark(); + HeaderCrc = reader.ReadUInt16(); + reader.ResetCrc(); + HeaderCode = reader.ReadByte(); + HeaderFlags = reader.ReadUInt16(); + HeaderSize = reader.ReadInt16(); + if (HasHeaderFlag(HeaderFlagsV4.HAS_DATA)) + { + AdditionalDataSize = reader.ReadUInt32(); + } + } + } + + protected RarHeader(RarHeader header, RarCrcBinaryReader reader, HeaderType headerType) + { + _headerType = headerType; + _isRar5 = header.IsRar5; + HeaderCrc = header.HeaderCrc; + HeaderCode = header.HeaderCode; + HeaderFlags = header.HeaderFlags; + HeaderSize = header.HeaderSize; + ExtraSize = header.ExtraSize; + AdditionalDataSize = header.AdditionalDataSize; + ArchiveEncoding = header.ArchiveEncoding; + ReadFinish(reader); + + var n = RemainingHeaderBytes(reader); + if (n > 0) + { + reader.ReadBytes(n); + } + + VerifyHeaderCrc(reader.GetCrc32()); + } + + protected int RemainingHeaderBytes(MarkingBinaryReader reader) + { + return checked(HeaderSize - (int)reader.CurrentReadByteCount); + } + + protected virtual void ReadFinish(MarkingBinaryReader reader) + { + throw new NotImplementedException(); + } + + private void VerifyHeaderCrc(uint crc32) + { + var b = (IsRar5 ? crc32 : (ushort)crc32) == HeaderCrc; + if (!b) + { + throw new InvalidFormatException("rar header crc mismatch"); + } + } + + public HeaderType HeaderType => _headerType; + + protected bool IsRar5 => _isRar5; + + protected uint HeaderCrc { get; } + + internal byte HeaderCode { get; } + + protected ushort HeaderFlags { get; } + + protected bool HasHeaderFlag(ushort flag) + { + return (HeaderFlags & flag) == flag; + } + + protected int HeaderSize { get; } + + internal ArchiveEncoding ArchiveEncoding { get; } + + /// + /// Extra header size. + /// + protected uint ExtraSize { get; } + + /// + /// Size of additional data (eg file contents) + /// + protected long AdditionalDataSize { get; } } diff --git a/src/SharpCompress/Common/Rar/Headers/RarHeaderFactory.cs b/src/SharpCompress/Common/Rar/Headers/RarHeaderFactory.cs index d5641959..37a59d2d 100644 --- a/src/SharpCompress/Common/Rar/Headers/RarHeaderFactory.cs +++ b/src/SharpCompress/Common/Rar/Headers/RarHeaderFactory.cs @@ -3,204 +3,203 @@ using System.IO; using SharpCompress.IO; using SharpCompress.Readers; -namespace SharpCompress.Common.Rar.Headers +namespace SharpCompress.Common.Rar.Headers; + +public class RarHeaderFactory { - public class RarHeaderFactory + private bool _isRar5; + + public RarHeaderFactory(StreamingMode mode, ReaderOptions options) { - private bool _isRar5; + StreamingMode = mode; + Options = options; + } - public RarHeaderFactory(StreamingMode mode, ReaderOptions options) + public ReaderOptions Options { get; } + public StreamingMode StreamingMode { get; } + public bool IsEncrypted { get; private set; } + + public IEnumerable ReadHeaders(Stream stream) + { + var markHeader = MarkHeader.Read( + stream, + Options.LeaveStreamOpen, + Options.LookForHeader + ); + _isRar5 = markHeader.IsRar5; + yield return markHeader; + + RarHeader? header; + while ((header = TryReadNextHeader(stream)) != null) { - StreamingMode = mode; - Options = options; - } - - public ReaderOptions Options { get; } - public StreamingMode StreamingMode { get; } - public bool IsEncrypted { get; private set; } - - public IEnumerable ReadHeaders(Stream stream) - { - var markHeader = MarkHeader.Read( - stream, - Options.LeaveStreamOpen, - Options.LookForHeader - ); - _isRar5 = markHeader.IsRar5; - yield return markHeader; - - RarHeader? header; - while ((header = TryReadNextHeader(stream)) != null) + yield return header; + if (header.HeaderType == HeaderType.EndArchive) { - yield return header; - if (header.HeaderType == HeaderType.EndArchive) - { - // End of archive marker. RAR does not read anything after this header letting to use third - // party tools to add extra information such as a digital signature to archive. - yield break; - } + // End of archive marker. RAR does not read anything after this header letting to use third + // party tools to add extra information such as a digital signature to archive. + yield break; } } + } - private RarHeader? TryReadNextHeader(Stream stream) + private RarHeader? TryReadNextHeader(Stream stream) + { + RarCrcBinaryReader reader; + if (!IsEncrypted) { - RarCrcBinaryReader reader; - if (!IsEncrypted) + reader = new RarCrcBinaryReader(stream); + } + else + { + if (Options.Password is null) { - reader = new RarCrcBinaryReader(stream); + throw new CryptographicException( + "Encrypted Rar archive has no password specified." + ); } - else + reader = new RarCryptoBinaryReader(stream, Options.Password); + } + + var header = RarHeader.TryReadBase(reader, _isRar5, Options.ArchiveEncoding); + if (header is null) + { + return null; + } + switch (header.HeaderCode) + { + case HeaderCodeV.RAR5_ARCHIVE_HEADER: + case HeaderCodeV.RAR4_ARCHIVE_HEADER: { - if (Options.Password is null) + var ah = new ArchiveHeader(header, reader); + if (ah.IsEncrypted == true) { - throw new CryptographicException( - "Encrypted Rar archive has no password specified." - ); - } - reader = new RarCryptoBinaryReader(stream, Options.Password); - } - - var header = RarHeader.TryReadBase(reader, _isRar5, Options.ArchiveEncoding); - if (header is null) - { - return null; - } - switch (header.HeaderCode) - { - case HeaderCodeV.RAR5_ARCHIVE_HEADER: - case HeaderCodeV.RAR4_ARCHIVE_HEADER: - { - var ah = new ArchiveHeader(header, reader); - if (ah.IsEncrypted == true) - { - //!!! rar5 we don't know yet - IsEncrypted = true; - } - return ah; - } - - case HeaderCodeV.RAR4_PROTECT_HEADER: - { - var ph = new ProtectHeader(header, reader); - // skip the recovery record data, we do not use it. - switch (StreamingMode) - { - case StreamingMode.Seekable: - - { - reader.BaseStream.Position += ph.DataSize; - } - break; - case StreamingMode.Streaming: - - { - reader.BaseStream.Skip(ph.DataSize); - } - break; - default: - { - throw new InvalidFormatException("Invalid StreamingMode"); - } - } - - return ph; - } - - case HeaderCodeV.RAR5_SERVICE_HEADER: - { - var fh = new FileHeader(header, reader, HeaderType.Service); - SkipData(fh, reader); - return fh; - } - - case HeaderCodeV.RAR4_NEW_SUB_HEADER: - { - var fh = new FileHeader(header, reader, HeaderType.NewSub); - SkipData(fh, reader); - return fh; - } - - case HeaderCodeV.RAR5_FILE_HEADER: - case HeaderCodeV.RAR4_FILE_HEADER: - { - var fh = new FileHeader(header, reader, HeaderType.File); - 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) - { - fh.PackedStream = ms; - } - else - { - fh.PackedStream = new RarCryptoWrapper( - ms, - Options.Password!, - fh.R4Salt - ); - } - } - break; - default: - { - throw new InvalidFormatException("Invalid StreamingMode"); - } - } - return fh; - } - case HeaderCodeV.RAR5_END_ARCHIVE_HEADER: - case HeaderCodeV.RAR4_END_ARCHIVE_HEADER: - { - return new EndArchiveHeader(header, reader); - } - case HeaderCodeV.RAR5_ARCHIVE_ENCRYPTION_HEADER: - { - var ch = new ArchiveCryptHeader(header, reader); + //!!! rar5 we don't know yet IsEncrypted = true; - return ch; - } - default: - { - throw new InvalidFormatException("Unknown Rar Header: " + header.HeaderCode); } + return ah; } - } - private void SkipData(FileHeader fh, RarCrcBinaryReader reader) - { - switch (StreamingMode) + case HeaderCodeV.RAR4_PROTECT_HEADER: { - case StreamingMode.Seekable: + var ph = new ProtectHeader(header, reader); + // skip the recovery record data, we do not use it. + switch (StreamingMode) + { + case StreamingMode.Seekable: + + { + reader.BaseStream.Position += ph.DataSize; + } + break; + case StreamingMode.Streaming: + + { + reader.BaseStream.Skip(ph.DataSize); + } + break; + default: + { + throw new InvalidFormatException("Invalid StreamingMode"); + } + } + + return ph; + } + + case HeaderCodeV.RAR5_SERVICE_HEADER: + { + var fh = new FileHeader(header, reader, HeaderType.Service); + SkipData(fh, reader); + return fh; + } + + case HeaderCodeV.RAR4_NEW_SUB_HEADER: + { + var fh = new FileHeader(header, reader, HeaderType.NewSub); + SkipData(fh, reader); + return fh; + } + + case HeaderCodeV.RAR5_FILE_HEADER: + case HeaderCodeV.RAR4_FILE_HEADER: + { + var fh = new FileHeader(header, reader, HeaderType.File); + switch (StreamingMode) + { + case StreamingMode.Seekable: { fh.DataStartPosition = reader.BaseStream.Position; reader.BaseStream.Position += fh.CompressedSize; } break; - case StreamingMode.Streaming: + case StreamingMode.Streaming: { - //skip the data because it's useless? - reader.BaseStream.Skip(fh.CompressedSize); + var ms = new ReadOnlySubStream( + reader.BaseStream, + fh.CompressedSize + ); + if (fh.R4Salt is null) + { + fh.PackedStream = ms; + } + else + { + fh.PackedStream = new RarCryptoWrapper( + ms, + Options.Password!, + fh.R4Salt + ); + } } break; - default: - { - throw new InvalidFormatException("Invalid StreamingMode"); + default: + { + throw new InvalidFormatException("Invalid StreamingMode"); + } } + return fh; + } + case HeaderCodeV.RAR5_END_ARCHIVE_HEADER: + case HeaderCodeV.RAR4_END_ARCHIVE_HEADER: + { + return new EndArchiveHeader(header, reader); + } + case HeaderCodeV.RAR5_ARCHIVE_ENCRYPTION_HEADER: + { + var ch = new ArchiveCryptHeader(header, reader); + IsEncrypted = true; + return ch; + } + default: + { + throw new InvalidFormatException("Unknown Rar Header: " + header.HeaderCode); + } + } + } + + private void SkipData(FileHeader fh, RarCrcBinaryReader reader) + { + 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); + } + break; + default: + { + throw new InvalidFormatException("Invalid StreamingMode"); } } } diff --git a/src/SharpCompress/Common/Rar/Headers/SignHeader.cs b/src/SharpCompress/Common/Rar/Headers/SignHeader.cs index c03a60f1..837ff3dc 100644 --- a/src/SharpCompress/Common/Rar/Headers/SignHeader.cs +++ b/src/SharpCompress/Common/Rar/Headers/SignHeader.cs @@ -1,29 +1,28 @@ -using SharpCompress.IO; +using SharpCompress.IO; -namespace SharpCompress.Common.Rar.Headers +namespace SharpCompress.Common.Rar.Headers; + +internal class SignHeader : RarHeader { - internal class SignHeader : RarHeader + protected SignHeader(RarHeader header, RarCrcBinaryReader reader) + : base(header, reader, HeaderType.Sign) { - protected SignHeader(RarHeader header, RarCrcBinaryReader reader) - : base(header, reader, HeaderType.Sign) + if (IsRar5) { - if (IsRar5) - { - throw new InvalidFormatException("unexpected rar5 record"); - } + throw new InvalidFormatException("unexpected rar5 record"); } - - protected override void ReadFinish(MarkingBinaryReader reader) - { - CreationTime = reader.ReadInt32(); - ArcNameSize = reader.ReadInt16(); - UserNameSize = reader.ReadInt16(); - } - - internal int CreationTime { get; private set; } - - internal short ArcNameSize { get; private set; } - - internal short UserNameSize { get; private set; } } + + protected override void ReadFinish(MarkingBinaryReader reader) + { + CreationTime = reader.ReadInt32(); + ArcNameSize = reader.ReadInt16(); + UserNameSize = reader.ReadInt16(); + } + + internal int CreationTime { get; private set; } + + internal short ArcNameSize { get; private set; } + + internal short UserNameSize { get; private set; } } diff --git a/src/SharpCompress/Common/Rar/RarCrcBinaryReader.cs b/src/SharpCompress/Common/Rar/RarCrcBinaryReader.cs index 34a64d16..586b9a8f 100644 --- a/src/SharpCompress/Common/Rar/RarCrcBinaryReader.cs +++ b/src/SharpCompress/Common/Rar/RarCrcBinaryReader.cs @@ -2,46 +2,45 @@ using System.IO; using SharpCompress.Compressors.Rar; using SharpCompress.IO; -namespace SharpCompress.Common.Rar +namespace SharpCompress.Common.Rar; + +internal class RarCrcBinaryReader : MarkingBinaryReader { - internal class RarCrcBinaryReader : MarkingBinaryReader + private uint _currentCrc; + + public RarCrcBinaryReader(Stream stream) : base(stream) { } + + public uint GetCrc32() { - private uint _currentCrc; + return ~_currentCrc; + } - public RarCrcBinaryReader(Stream stream) : base(stream) { } + public void ResetCrc() + { + _currentCrc = 0xffffffff; + } - public uint GetCrc32() - { - return ~_currentCrc; - } + protected void UpdateCrc(byte b) + { + _currentCrc = RarCRC.CheckCrc(_currentCrc, b); + } - public void ResetCrc() - { - _currentCrc = 0xffffffff; - } + protected byte[] ReadBytesNoCrc(int count) + { + return base.ReadBytes(count); + } - protected void UpdateCrc(byte b) - { - _currentCrc = RarCRC.CheckCrc(_currentCrc, b); - } + public override byte ReadByte() + { + var b = base.ReadByte(); + _currentCrc = RarCRC.CheckCrc(_currentCrc, b); + return b; + } - protected byte[] ReadBytesNoCrc(int count) - { - return base.ReadBytes(count); - } - - public override byte ReadByte() - { - var b = base.ReadByte(); - _currentCrc = RarCRC.CheckCrc(_currentCrc, b); - return b; - } - - public override byte[] ReadBytes(int count) - { - var result = base.ReadBytes(count); - _currentCrc = RarCRC.CheckCrc(_currentCrc, result, 0, result.Length); - return result; - } + public override byte[] ReadBytes(int count) + { + var result = base.ReadBytes(count); + _currentCrc = RarCRC.CheckCrc(_currentCrc, result, 0, result.Length); + return result; } } diff --git a/src/SharpCompress/Common/Rar/RarCryptoBinaryReader.cs b/src/SharpCompress/Common/Rar/RarCryptoBinaryReader.cs index 728690e3..d02750ed 100644 --- a/src/SharpCompress/Common/Rar/RarCryptoBinaryReader.cs +++ b/src/SharpCompress/Common/Rar/RarCryptoBinaryReader.cs @@ -1,110 +1,109 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.IO; -namespace SharpCompress.Common.Rar +namespace SharpCompress.Common.Rar; + +internal sealed class RarCryptoBinaryReader : RarCrcBinaryReader { - internal sealed class RarCryptoBinaryReader : RarCrcBinaryReader + private RarRijndael _rijndael; + private byte[] _salt; + private readonly string _password; + private readonly Queue _data = new Queue(); + private long _readCount; + + public RarCryptoBinaryReader(Stream stream, string password) : base(stream) { - private RarRijndael _rijndael; - private byte[] _salt; - private readonly string _password; - private readonly Queue _data = new Queue(); - private long _readCount; + _password = password; - public RarCryptoBinaryReader(Stream stream, string password) : base(stream) + // coderb: not sure why this was being done at this logical point + //SkipQueue(); + var salt = ReadBytes(8); + + _salt = salt; + _rijndael = RarRijndael.InitializeFrom(_password, salt); + } + + // track read count ourselves rather than using the underlying stream since we buffer + public override long CurrentReadByteCount + { + get => _readCount; + protected set { - _password = password; - - // coderb: not sure why this was being done at this logical point - //SkipQueue(); - byte[] salt = ReadBytes(8); - - _salt = salt; - _rijndael = RarRijndael.InitializeFrom(_password, salt); - } - - // track read count ourselves rather than using the underlying stream since we buffer - public override long CurrentReadByteCount - { - get => _readCount; - protected set - { - // ignore - } - } - - public override void Mark() - { - _readCount = 0; - } - - private bool UseEncryption => _salt != null; - - 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); - } - - private byte[] ReadAndDecryptBytes(int count) - { - int queueSize = _data.Count; - int sizeToRead = count - queueSize; - - if (sizeToRead > 0) - { - int alignedSize = sizeToRead + ((~sizeToRead + 1) & 0xf); - for (int i = 0; i < alignedSize / 16; i++) - { - //long ax = System.currentTimeMillis(); - byte[] cipherText = ReadBytesNoCrc(16); - var readBytes = _rijndael.ProcessBlock(cipherText); - foreach (var readByte in readBytes) - { - _data.Enqueue(readByte); - } - } - } - - var decryptedBytes = new byte[count]; - - for (int i = 0; i < count; i++) - { - var b = _data.Dequeue(); - decryptedBytes[i] = b; - UpdateCrc(b); - } - - _readCount += count; - return decryptedBytes; - } - - public void ClearQueue() - { - _data.Clear(); - } - - public void SkipQueue() - { - var position = BaseStream.Position; - BaseStream.Position = position + _data.Count; - ClearQueue(); + // ignore } } + + public override void Mark() + { + _readCount = 0; + } + + private bool UseEncryption => _salt != null; + + 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); + } + + private byte[] ReadAndDecryptBytes(int count) + { + var queueSize = _data.Count; + var sizeToRead = count - queueSize; + + if (sizeToRead > 0) + { + var alignedSize = sizeToRead + ((~sizeToRead + 1) & 0xf); + for (var i = 0; i < alignedSize / 16; i++) + { + //long ax = System.currentTimeMillis(); + var cipherText = ReadBytesNoCrc(16); + var readBytes = _rijndael.ProcessBlock(cipherText); + foreach (var readByte in readBytes) + { + _data.Enqueue(readByte); + } + } + } + + var decryptedBytes = new byte[count]; + + for (var i = 0; i < count; i++) + { + var b = _data.Dequeue(); + decryptedBytes[i] = b; + UpdateCrc(b); + } + + _readCount += count; + return decryptedBytes; + } + + public void ClearQueue() + { + _data.Clear(); + } + + public void SkipQueue() + { + var position = BaseStream.Position; + BaseStream.Position = position + _data.Count; + ClearQueue(); + } } diff --git a/src/SharpCompress/Common/Rar/RarCryptoWrapper.cs b/src/SharpCompress/Common/Rar/RarCryptoWrapper.cs index 78fee933..385ed2a0 100644 --- a/src/SharpCompress/Common/Rar/RarCryptoWrapper.cs +++ b/src/SharpCompress/Common/Rar/RarCryptoWrapper.cs @@ -2,98 +2,97 @@ using System; using System.Collections.Generic; using System.IO; -namespace SharpCompress.Common.Rar +namespace SharpCompress.Common.Rar; + +internal sealed class RarCryptoWrapper : Stream { - internal sealed class RarCryptoWrapper : Stream + private readonly Stream _actualStream; + private readonly byte[] _salt; + private RarRijndael _rijndael; + private readonly Queue _data = new Queue(); + + public RarCryptoWrapper(Stream actualStream, string password, byte[] salt) { - private readonly Stream _actualStream; - private readonly byte[] _salt; - private RarRijndael _rijndael; - private readonly Queue _data = new Queue(); + _actualStream = actualStream; + _salt = salt; + _rijndael = RarRijndael.InitializeFrom(password, salt); + } - public RarCryptoWrapper(Stream actualStream, string password, byte[] salt) + public override void Flush() + { + throw new NotSupportedException(); + } + + 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) { - _actualStream = actualStream; - _salt = salt; - _rijndael = RarRijndael.InitializeFrom(password, salt); + return _actualStream.Read(buffer, offset, count); } + return ReadAndDecrypt(buffer, offset, count); + } - public override void Flush() - { - throw new NotSupportedException(); - } + public int ReadAndDecrypt(byte[] buffer, int offset, int count) + { + var queueSize = _data.Count; + var sizeToRead = count - queueSize; - public override long Seek(long offset, SeekOrigin origin) + if (sizeToRead > 0) { - 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) + var alignedSize = sizeToRead + ((~sizeToRead + 1) & 0xf); + Span cipherText = stackalloc byte[RarRijndael.CRYPTO_BLOCK_SIZE]; + for (var i = 0; i < alignedSize / 16; i++) { - return _actualStream.Read(buffer, offset, count); - } - return ReadAndDecrypt(buffer, offset, count); - } + //long ax = System.currentTimeMillis(); + _actualStream.Read(cipherText); - public int ReadAndDecrypt(byte[] buffer, int offset, int count) - { - int queueSize = _data.Count; - int sizeToRead = count - queueSize; - - if (sizeToRead > 0) - { - int alignedSize = sizeToRead + ((~sizeToRead + 1) & 0xf); - Span cipherText = stackalloc byte[RarRijndael.CRYPTO_BLOCK_SIZE]; - for (int i = 0; i < alignedSize / 16; i++) + var readBytes = _rijndael.ProcessBlock(cipherText); + foreach (var readByte in readBytes) { - //long ax = System.currentTimeMillis(); - _actualStream.Read(cipherText); - - var readBytes = _rijndael.ProcessBlock(cipherText); - foreach (var readByte in readBytes) - { - _data.Enqueue(readByte); - } - } - - for (int i = 0; i < count; i++) - { - buffer[offset + i] = _data.Dequeue(); + _data.Enqueue(readByte); } } - return count; - } - public override void Write(byte[] buffer, int offset, int count) - { - throw new NotSupportedException(); - } - - public override bool CanRead => true; - - public override bool CanSeek => false; - - public override bool CanWrite => false; - - public override long Length => throw new NotSupportedException(); - - public override long Position { get; set; } - - protected override void Dispose(bool disposing) - { - if (_rijndael != null) + for (var i = 0; i < count; i++) { - _rijndael.Dispose(); - _rijndael = null!; + buffer[offset + i] = _data.Dequeue(); } - base.Dispose(disposing); } + return count; + } + + public override void Write(byte[] buffer, int offset, int count) + { + throw new NotSupportedException(); + } + + public override bool CanRead => true; + + public override bool CanSeek => false; + + public override bool CanWrite => false; + + public override long Length => throw new NotSupportedException(); + + public override long Position { get; set; } + + protected override void Dispose(bool disposing) + { + if (_rijndael != null) + { + _rijndael.Dispose(); + _rijndael = null!; + } + base.Dispose(disposing); } } diff --git a/src/SharpCompress/Common/Rar/RarEntry.cs b/src/SharpCompress/Common/Rar/RarEntry.cs index 05ab67ec..54c12b8c 100644 --- a/src/SharpCompress/Common/Rar/RarEntry.cs +++ b/src/SharpCompress/Common/Rar/RarEntry.cs @@ -1,74 +1,73 @@ -using System; +using System; using SharpCompress.Common.Rar.Headers; -namespace SharpCompress.Common.Rar +namespace SharpCompress.Common.Rar; + +public abstract class RarEntry : Entry { - public abstract class RarEntry : Entry + internal abstract FileHeader FileHeader { get; } + + /// + /// As the V2017 port isn't complete, add this check to use the legacy Rar code. + /// + internal bool IsRarV3 => + FileHeader.CompressionAlgorithm == 20 + || FileHeader.CompressionAlgorithm == 26 + || FileHeader.CompressionAlgorithm == 29 + || FileHeader.CompressionAlgorithm == 36; //Nanook - Added 20+26 as Test arc from WinRar2.8 (algo 20) was failing with 2017 code + + /// + /// The File's 32 bit CRC Hash + /// + public override long Crc => FileHeader.FileCrc; + + /// + /// The path of the file internal to the Rar Archive. + /// + public override string Key => FileHeader.FileName; + + public override string? LinkTarget => null; + + /// + /// The entry last modified time in the archive, if recorded + /// + public override DateTime? LastModifiedTime => FileHeader.FileLastModifiedTime; + + /// + /// The entry create time in the archive, if recorded + /// + public override DateTime? CreatedTime => FileHeader.FileCreatedTime; + + /// + /// The entry last accessed time in the archive, if recorded + /// + public override DateTime? LastAccessedTime => FileHeader.FileLastAccessedTime; + + /// + /// The entry time whend archived, if recorded + /// + public override DateTime? ArchivedTime => FileHeader.FileArchivedTime; + + /// + /// Entry is password protected and encrypted and cannot be extracted. + /// + public override bool IsEncrypted => FileHeader.IsEncrypted; + + /// + /// Entry is password protected and encrypted and cannot be extracted. + /// + public override bool IsDirectory => FileHeader.IsDirectory; + + public override bool IsSplitAfter => FileHeader.IsSplitAfter; + + public override string ToString() { - internal abstract FileHeader FileHeader { get; } - - /// - /// As the V2017 port isn't complete, add this check to use the legacy Rar code. - /// - internal bool IsRarV3 => - FileHeader.CompressionAlgorithm == 20 - || FileHeader.CompressionAlgorithm == 26 - || FileHeader.CompressionAlgorithm == 29 - || FileHeader.CompressionAlgorithm == 36; //Nanook - Added 20+26 as Test arc from WinRar2.8 (algo 20) was failing with 2017 code - - /// - /// The File's 32 bit CRC Hash - /// - public override long Crc => FileHeader.FileCrc; - - /// - /// The path of the file internal to the Rar Archive. - /// - public override string Key => FileHeader.FileName; - - public override string? LinkTarget => null; - - /// - /// The entry last modified time in the archive, if recorded - /// - public override DateTime? LastModifiedTime => FileHeader.FileLastModifiedTime; - - /// - /// The entry create time in the archive, if recorded - /// - public override DateTime? CreatedTime => FileHeader.FileCreatedTime; - - /// - /// The entry last accessed time in the archive, if recorded - /// - public override DateTime? LastAccessedTime => FileHeader.FileLastAccessedTime; - - /// - /// The entry time whend archived, if recorded - /// - public override DateTime? ArchivedTime => FileHeader.FileArchivedTime; - - /// - /// Entry is password protected and encrypted and cannot be extracted. - /// - public override bool IsEncrypted => FileHeader.IsEncrypted; - - /// - /// Entry is password protected and encrypted and cannot be extracted. - /// - public override bool IsDirectory => FileHeader.IsDirectory; - - public override bool IsSplitAfter => FileHeader.IsSplitAfter; - - public override string ToString() - { - return string.Format( - "Entry Path: {0} Compressed Size: {1} Uncompressed Size: {2} CRC: {3}", - Key, - CompressedSize, - Size, - Crc - ); - } + return string.Format( + "Entry Path: {0} Compressed Size: {1} Uncompressed Size: {2} CRC: {3}", + Key, + CompressedSize, + Size, + Crc + ); } } diff --git a/src/SharpCompress/Common/Rar/RarFilePart.cs b/src/SharpCompress/Common/Rar/RarFilePart.cs index b57ab184..fa99614b 100644 --- a/src/SharpCompress/Common/Rar/RarFilePart.cs +++ b/src/SharpCompress/Common/Rar/RarFilePart.cs @@ -1,27 +1,26 @@ using System.IO; using SharpCompress.Common.Rar.Headers; -namespace SharpCompress.Common.Rar +namespace SharpCompress.Common.Rar; + +/// +/// This represents a single file part that exists in a rar volume. A compressed file is one or many file parts that are spread across one or may rar parts. +/// +internal abstract class RarFilePart : FilePart { - /// - /// This represents a single file part that exists in a rar volume. A compressed file is one or many file parts that are spread across one or may rar parts. - /// - internal abstract class RarFilePart : FilePart + internal RarFilePart(MarkHeader mh, FileHeader fh, int index) : base(fh.ArchiveEncoding) { - internal RarFilePart(MarkHeader mh, FileHeader fh, int index) : base(fh.ArchiveEncoding) - { - MarkHeader = mh; - FileHeader = fh; - Index = index; - } + MarkHeader = mh; + FileHeader = fh; + Index = index; + } - internal MarkHeader MarkHeader { get; } + internal MarkHeader MarkHeader { get; } - internal FileHeader FileHeader { get; } + internal FileHeader FileHeader { get; } - internal override Stream? GetRawStream() - { - return null; - } + internal override Stream? GetRawStream() + { + return null; } } diff --git a/src/SharpCompress/Common/Rar/RarRijndael.cs b/src/SharpCompress/Common/Rar/RarRijndael.cs index a2a5731f..94592639 100644 --- a/src/SharpCompress/Common/Rar/RarRijndael.cs +++ b/src/SharpCompress/Common/Rar/RarRijndael.cs @@ -1,115 +1,114 @@ -#nullable disable +#nullable disable using System; using System.Security.Cryptography; using System.Text; using SharpCompress.Crypto; -namespace SharpCompress.Common.Rar +namespace SharpCompress.Common.Rar; + +internal class RarRijndael : IDisposable { - 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) { - 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]; - int rawLength = 2 * _password.Length; - byte[] rawPassword = new byte[rawLength + 8]; - byte[] passwordBytes = Encoding.UTF8.GetBytes(_password); - for (int i = 0; i < _password.Length; i++) - { - rawPassword[i * 2] = passwordBytes[i]; - rawPassword[i * 2 + 1] = 0; - } - for (int i = 0; i < _salt.Length; i++) - { - rawPassword[i + rawLength] = _salt[i]; - } - - const int noOfRounds = (1 << 18); - const int iblock = 3; - byte[] digest; - byte[] data = new byte[(rawPassword.Length + iblock) * noOfRounds]; - - //TODO slow code below, find ways to optimize - for (int 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 - - byte[] aesKey = new byte[CRYPTO_BLOCK_SIZE]; - for (int i = 0; i < 4; i++) - { - for (int 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 - byte[] decryptedBytes = new byte[CRYPTO_BLOCK_SIZE]; - _rijndael.ProcessBlock(cipherText, plainText); - - for (int j = 0; j < CRYPTO_BLOCK_SIZE; j++) - { - decryptedBytes[j] = (byte)(plainText[j] ^ _aesInitializationVector[j % 16]); //32:114, 33:101 - } - - for (int j = 0; j < _aesInitializationVector.Length; j++) - { - _aesInitializationVector[j] = cipherText[j]; - } - - return decryptedBytes; - } - - public void Dispose() { } + _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 8e6a8026..eac09e33 100644 --- a/src/SharpCompress/Common/Rar/RarVolume.cs +++ b/src/SharpCompress/Common/Rar/RarVolume.cs @@ -6,169 +6,187 @@ using SharpCompress.Common.Rar.Headers; using SharpCompress.IO; using SharpCompress.Readers; -namespace SharpCompress.Common.Rar -{ - /// - /// A RarArchiveVolume is a single rar file that may or may not be a split RarArchive. A Rar Archive is one to many Rar Parts - /// - public abstract class RarVolume : Volume - { - private readonly RarHeaderFactory _headerFactory; - internal int _maxCompressionAlgorithm; +namespace SharpCompress.Common.Rar; - internal RarVolume(StreamingMode mode, Stream stream, ReaderOptions options, int index = 0) - : base(stream, options, index) - { - _headerFactory = new RarHeaderFactory(mode, options); - } +/// +/// A RarArchiveVolume is a single rar file that may or may not be a split RarArchive. A Rar Archive is one to many Rar Parts +/// +public abstract class RarVolume : Volume +{ + private readonly RarHeaderFactory _headerFactory; + internal int _maxCompressionAlgorithm; + + internal RarVolume(StreamingMode mode, Stream stream, ReaderOptions options, int index = 0) + : base(stream, options, index) + { + _headerFactory = new RarHeaderFactory(mode, options); + } #nullable disable - internal ArchiveHeader ArchiveHeader { get; private set; } + internal ArchiveHeader ArchiveHeader { get; private set; } #nullable enable - internal StreamingMode Mode => _headerFactory.StreamingMode; + internal StreamingMode Mode => _headerFactory.StreamingMode; - internal abstract IEnumerable ReadFileParts(); + internal abstract IEnumerable ReadFileParts(); - internal abstract RarFilePart CreateFilePart(MarkHeader markHeader, FileHeader fileHeader); + internal abstract RarFilePart CreateFilePart(MarkHeader markHeader, FileHeader fileHeader); - internal IEnumerable GetVolumeFileParts() + internal IEnumerable GetVolumeFileParts() + { + MarkHeader? lastMarkHeader = null; + foreach (var header in _headerFactory.ReadHeaders(Stream)) { - MarkHeader? lastMarkHeader = null; - foreach (var header in _headerFactory.ReadHeaders(Stream)) + switch (header.HeaderType) { - switch (header.HeaderType) + case HeaderType.Mark: + { - 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) - _maxCompressionAlgorithm = fh.CompressionAlgorithm; - yield return CreateFilePart(lastMarkHeader!, fh); - } - 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 - ); - } - } - break; + lastMarkHeader = (MarkHeader)header; } - } - } + break; + case HeaderType.Archive: - private void EnsureArchiveHeaderLoaded() - { - if (ArchiveHeader is null) - { - if (Mode == StreamingMode.Streaming) { - throw new InvalidOperationException( - "ArchiveHeader should never been null in a streaming read." - ); + ArchiveHeader = (ArchiveHeader)header; } + break; + case HeaderType.File: - // we only want to load the archive header to avoid overhead but have to do the nasty thing and reset the stream - GetVolumeFileParts().First(); - Stream.Position = 0; + { + var fh = (FileHeader)header; + if (_maxCompressionAlgorithm < fh.CompressionAlgorithm) + { + _maxCompressionAlgorithm = fh.CompressionAlgorithm; + } + + yield return CreateFilePart(lastMarkHeader!, fh); + } + 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 + ); + } + } + break; } } - - /// - /// RarArchive is the first volume of a multi-part archive. - /// Only Rar 3.0 format and higher - /// - public override bool IsFirstVolume - { - get - { - EnsureArchiveHeaderLoaded(); - return ArchiveHeader.IsFirstVolume; - } - } - - /// - /// RarArchive is part of a multi-part archive. - /// - public override bool IsMultiVolume - { - get - { - EnsureArchiveHeaderLoaded(); - return ArchiveHeader.IsVolume; - } - } - - /// - /// RarArchive is SOLID (this means the Archive saved bytes by reusing information which helps for archives containing many small files). - /// Currently, SharpCompress cannot decompress SOLID archives. - /// - public bool IsSolidArchive - { - get - { - EnsureArchiveHeaderLoaded(); - return ArchiveHeader.IsSolid; - } - } - - public int MinVersion - { - get - { - EnsureArchiveHeaderLoaded(); - if (_maxCompressionAlgorithm >= 50) - return 5; //5-6 - else if (_maxCompressionAlgorithm >= 29) - return 3; //3-4 - else if (_maxCompressionAlgorithm >= 20) - return 2; //2 - else - return 1; - } - } - - public int MaxVersion - { - get - { - EnsureArchiveHeaderLoaded(); - if (_maxCompressionAlgorithm >= 50) - return 6; //5-6 - else if (_maxCompressionAlgorithm >= 29) - return 4; //3-4 - else if (_maxCompressionAlgorithm >= 20) - return 2; //2 - else - return 1; - } - } - - public string? Comment { get; internal set; } } + + private void EnsureArchiveHeaderLoaded() + { + if (ArchiveHeader is null) + { + if (Mode == StreamingMode.Streaming) + { + throw new InvalidOperationException( + "ArchiveHeader should never been null in a streaming read." + ); + } + + // we only want to load the archive header to avoid overhead but have to do the nasty thing and reset the stream + GetVolumeFileParts().First(); + Stream.Position = 0; + } + } + + /// + /// RarArchive is the first volume of a multi-part archive. + /// Only Rar 3.0 format and higher + /// + public override bool IsFirstVolume + { + get + { + EnsureArchiveHeaderLoaded(); + return ArchiveHeader.IsFirstVolume; + } + } + + /// + /// RarArchive is part of a multi-part archive. + /// + public override bool IsMultiVolume + { + get + { + EnsureArchiveHeaderLoaded(); + return ArchiveHeader.IsVolume; + } + } + + /// + /// RarArchive is SOLID (this means the Archive saved bytes by reusing information which helps for archives containing many small files). + /// Currently, SharpCompress cannot decompress SOLID archives. + /// + public bool IsSolidArchive + { + get + { + EnsureArchiveHeaderLoaded(); + return ArchiveHeader.IsSolid; + } + } + + public int MinVersion + { + get + { + EnsureArchiveHeaderLoaded(); + if (_maxCompressionAlgorithm >= 50) + { + return 5; //5-6 + } + else if (_maxCompressionAlgorithm >= 29) + { + return 3; //3-4 + } + else if (_maxCompressionAlgorithm >= 20) + { + return 2; //2 + } + else + { + return 1; + } + } + } + + public int MaxVersion + { + get + { + EnsureArchiveHeaderLoaded(); + if (_maxCompressionAlgorithm >= 50) + { + return 6; //5-6 + } + else if (_maxCompressionAlgorithm >= 29) + { + return 4; //3-4 + } + else if (_maxCompressionAlgorithm >= 20) + { + return 2; //2 + } + else + { + return 1; + } + } + } + + public string? Comment { get; internal set; } } diff --git a/src/SharpCompress/Common/ReaderExtractionEventArgs.cs b/src/SharpCompress/Common/ReaderExtractionEventArgs.cs index 87362b68..7c4363e2 100644 --- a/src/SharpCompress/Common/ReaderExtractionEventArgs.cs +++ b/src/SharpCompress/Common/ReaderExtractionEventArgs.cs @@ -1,18 +1,17 @@ -using System; +using System; using SharpCompress.Readers; -namespace SharpCompress.Common +namespace SharpCompress.Common; + +public sealed class ReaderExtractionEventArgs : EventArgs { - public sealed class ReaderExtractionEventArgs : EventArgs + internal ReaderExtractionEventArgs(T entry, ReaderProgress? readerProgress = null) { - internal ReaderExtractionEventArgs(T entry, ReaderProgress? readerProgress = null) - { - Item = entry; - ReaderProgress = readerProgress; - } - - public T Item { get; } - - public ReaderProgress? ReaderProgress { get; } + Item = entry; + ReaderProgress = readerProgress; } + + public T Item { get; } + + public ReaderProgress? ReaderProgress { get; } } diff --git a/src/SharpCompress/Common/SevenZip/ArchiveDatabase.cs b/src/SharpCompress/Common/SevenZip/ArchiveDatabase.cs index e16751e6..dbacf332 100644 --- a/src/SharpCompress/Common/SevenZip/ArchiveDatabase.cs +++ b/src/SharpCompress/Common/SevenZip/ArchiveDatabase.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable using System; using System.Collections.Generic; @@ -6,186 +6,167 @@ using System.IO; using SharpCompress.Compressors.LZMA; using SharpCompress.Compressors.LZMA.Utilites; -namespace SharpCompress.Common.SevenZip +namespace SharpCompress.Common.SevenZip; + +internal class ArchiveDatabase { - internal class ArchiveDatabase + internal byte _majorVersion; + internal byte _minorVersion; + internal long _startPositionAfterHeader; + internal long _dataStartPosition; + + internal List _packSizes = new List(); + internal List _packCrCs = new List(); + internal List _folders = new List(); + internal List _numUnpackStreamsVector; + internal List _files = new List(); + + internal List _packStreamStartPositions = new List(); + internal List _folderStartFileIndex = new List(); + internal List _fileIndexToFolderIndexMap = new List(); + + internal IPasswordProvider PasswordProvider { get; } + + public ArchiveDatabase(IPasswordProvider passwordProvider) { - internal byte _majorVersion; - internal byte _minorVersion; - internal long _startPositionAfterHeader; - internal long _dataStartPosition; + PasswordProvider = passwordProvider; + } - internal List _packSizes = new List(); - internal List _packCrCs = new List(); - internal List _folders = new List(); - internal List _numUnpackStreamsVector; - internal List _files = new List(); + internal void Clear() + { + _packSizes.Clear(); + _packCrCs.Clear(); + _folders.Clear(); + _numUnpackStreamsVector = null!; + _files.Clear(); - internal List _packStreamStartPositions = new List(); - internal List _folderStartFileIndex = new List(); - internal List _fileIndexToFolderIndexMap = new List(); + _packStreamStartPositions.Clear(); + _folderStartFileIndex.Clear(); + _fileIndexToFolderIndexMap.Clear(); + } - internal IPasswordProvider PasswordProvider { get; } + internal bool IsEmpty() + { + return _packSizes.Count == 0 + && _packCrCs.Count == 0 + && _folders.Count == 0 + && _numUnpackStreamsVector.Count == 0 + && _files.Count == 0; + } - public ArchiveDatabase(IPasswordProvider passwordProvider) + private void FillStartPos() + { + _packStreamStartPositions.Clear(); + + long startPos = 0; + for (var i = 0; i < _packSizes.Count; i++) { - PasswordProvider = passwordProvider; - } - - internal void Clear() - { - _packSizes.Clear(); - _packCrCs.Clear(); - _folders.Clear(); - _numUnpackStreamsVector = null!; - _files.Clear(); - - _packStreamStartPositions.Clear(); - _folderStartFileIndex.Clear(); - _fileIndexToFolderIndexMap.Clear(); - } - - internal bool IsEmpty() - { - return _packSizes.Count == 0 - && _packCrCs.Count == 0 - && _folders.Count == 0 - && _numUnpackStreamsVector.Count == 0 - && _files.Count == 0; - } - - private void FillStartPos() - { - _packStreamStartPositions.Clear(); - - long startPos = 0; - for (int i = 0; i < _packSizes.Count; i++) - { - _packStreamStartPositions.Add(startPos); - startPos += _packSizes[i]; - } - } - - private void FillFolderStartFileIndex() - { - _folderStartFileIndex.Clear(); - _fileIndexToFolderIndexMap.Clear(); - - int folderIndex = 0; - int indexInFolder = 0; - for (int i = 0; i < _files.Count; i++) - { - CFileItem file = _files[i]; - - bool emptyStream = !file.HasStream; - - if (emptyStream && indexInFolder == 0) - { - _fileIndexToFolderIndexMap.Add(-1); - continue; - } - - if (indexInFolder == 0) - { - // v3.13 incorrectly worked with empty folders - // v4.07: Loop for skipping empty folders - for (; ; ) - { - if (folderIndex >= _folders.Count) - { - throw new InvalidOperationException(); - } - - _folderStartFileIndex.Add(i); // check it - - if (_numUnpackStreamsVector![folderIndex] != 0) - { - break; - } - - folderIndex++; - } - } - - _fileIndexToFolderIndexMap.Add(folderIndex); - - if (emptyStream) - { - continue; - } - - indexInFolder++; - - if (indexInFolder >= _numUnpackStreamsVector![folderIndex]) - { - folderIndex++; - indexInFolder = 0; - } - } - } - - public void Fill() - { - FillStartPos(); - FillFolderStartFileIndex(); - } - - internal long GetFolderStreamPos(CFolder folder, int indexInFolder) - { - int index = folder._firstPackStreamId + indexInFolder; - return _dataStartPosition + _packStreamStartPositions[index]; - } - - internal long GetFolderFullPackSize(int folderIndex) - { - int packStreamIndex = _folders[folderIndex]._firstPackStreamId; - CFolder folder = _folders[folderIndex]; - - long size = 0; - for (int i = 0; i < folder._packStreams.Count; i++) - { - size += _packSizes[packStreamIndex + i]; - } - - return size; - } - - internal Stream GetFolderStream(Stream stream, CFolder folder, IPasswordProvider pw) - { - int packStreamIndex = folder._firstPackStreamId; - long folderStartPackPos = GetFolderStreamPos(folder, 0); - int count = folder._packStreams.Count; - long[] packSizes = new long[count]; - for (int j = 0; j < count; j++) - { - packSizes[j] = _packSizes[packStreamIndex + j]; - } - - return DecoderStreamHelper.CreateDecoderStream( - stream, - folderStartPackPos, - packSizes, - folder, - pw - ); - } - - private long GetFolderPackStreamSize(int folderIndex, int streamIndex) - { - return _packSizes[_folders[folderIndex]._firstPackStreamId + streamIndex]; - } - - private long GetFilePackSize(int fileIndex) - { - int folderIndex = _fileIndexToFolderIndexMap[fileIndex]; - if (folderIndex != -1) - { - if (_folderStartFileIndex[folderIndex] == fileIndex) - { - return GetFolderFullPackSize(folderIndex); - } - } - return 0; + _packStreamStartPositions.Add(startPos); + startPos += _packSizes[i]; } } + + private void FillFolderStartFileIndex() + { + _folderStartFileIndex.Clear(); + _fileIndexToFolderIndexMap.Clear(); + + var folderIndex = 0; + var indexInFolder = 0; + for (var i = 0; i < _files.Count; i++) + { + var file = _files[i]; + + var emptyStream = !file.HasStream; + + if (emptyStream && indexInFolder == 0) + { + _fileIndexToFolderIndexMap.Add(-1); + continue; + } + + if (indexInFolder == 0) + { + // v3.13 incorrectly worked with empty folders + // v4.07: Loop for skipping empty folders + for (; ; ) + { + if (folderIndex >= _folders.Count) + { + throw new InvalidOperationException(); + } + + _folderStartFileIndex.Add(i); // check it + + if (_numUnpackStreamsVector![folderIndex] != 0) + { + break; + } + + folderIndex++; + } + } + + _fileIndexToFolderIndexMap.Add(folderIndex); + + if (emptyStream) + { + continue; + } + + indexInFolder++; + + if (indexInFolder >= _numUnpackStreamsVector![folderIndex]) + { + folderIndex++; + indexInFolder = 0; + } + } + } + + public void Fill() + { + FillStartPos(); + FillFolderStartFileIndex(); + } + + internal long GetFolderStreamPos(CFolder folder, int indexInFolder) + { + var index = folder._firstPackStreamId + indexInFolder; + return _dataStartPosition + _packStreamStartPositions[index]; + } + + internal long GetFolderFullPackSize(int folderIndex) + { + var packStreamIndex = _folders[folderIndex]._firstPackStreamId; + var folder = _folders[folderIndex]; + + long size = 0; + for (var i = 0; i < folder._packStreams.Count; i++) + { + size += _packSizes[packStreamIndex + i]; + } + + return size; + } + + internal Stream GetFolderStream(Stream stream, CFolder folder, IPasswordProvider pw) + { + var packStreamIndex = folder._firstPackStreamId; + var folderStartPackPos = GetFolderStreamPos(folder, 0); + var count = folder._packStreams.Count; + var packSizes = new long[count]; + for (var j = 0; j < count; j++) + { + packSizes[j] = _packSizes[packStreamIndex + j]; + } + + return DecoderStreamHelper.CreateDecoderStream( + stream, + folderStartPackPos, + packSizes, + folder, + pw + ); + } } diff --git a/src/SharpCompress/Common/SevenZip/ArchiveReader.cs b/src/SharpCompress/Common/SevenZip/ArchiveReader.cs index babae147..908fb453 100644 --- a/src/SharpCompress/Common/SevenZip/ArchiveReader.cs +++ b/src/SharpCompress/Common/SevenZip/ArchiveReader.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable using System; using System.Collections.Generic; @@ -9,1704 +9,1696 @@ using SharpCompress.Compressors.LZMA; using SharpCompress.Compressors.LZMA.Utilites; using SharpCompress.IO; -namespace SharpCompress.Common.SevenZip +namespace SharpCompress.Common.SevenZip; + +internal class ArchiveReader { - internal class ArchiveReader + internal Stream _stream; + internal Stack _readerStack = new Stack(); + internal DataReader _currentReader; + internal long _streamOrigin; + internal long _streamEnding; + internal byte[] _header; + + private readonly Dictionary _cachedStreams = new Dictionary(); + + internal void AddByteStream(byte[] buffer, int offset, int length) { - internal Stream _stream; - internal Stack _readerStack = new Stack(); - internal DataReader _currentReader; - internal long _streamOrigin; - internal long _streamEnding; - internal byte[] _header; + _readerStack.Push(_currentReader); + _currentReader = new DataReader(buffer, offset, length); + } - private readonly Dictionary _cachedStreams = new Dictionary(); + internal void DeleteByteStream() + { + _currentReader = _readerStack.Pop(); + } - internal void AddByteStream(byte[] buffer, int offset, int length) + #region Private Methods - Data Reader + + internal byte ReadByte() + { + return _currentReader.ReadByte(); + } + + private void ReadBytes(byte[] buffer, int offset, int length) + { + _currentReader.ReadBytes(buffer, offset, length); + } + + private ulong ReadNumber() + { + return _currentReader.ReadNumber(); + } + + internal int ReadNum() + { + return _currentReader.ReadNum(); + } + + private uint ReadUInt32() + { + return _currentReader.ReadUInt32(); + } + + private ulong ReadUInt64() + { + return _currentReader.ReadUInt64(); + } + + private BlockType? ReadId() + { + var id = _currentReader.ReadNumber(); + if (id > 25) { - _readerStack.Push(_currentReader); - _currentReader = new DataReader(buffer, offset, length); - } - - internal void DeleteByteStream() - { - _currentReader = _readerStack.Pop(); - } - - #region Private Methods - Data Reader - - internal Byte ReadByte() - { - return _currentReader.ReadByte(); - } - - private void ReadBytes(byte[] buffer, int offset, int length) - { - _currentReader.ReadBytes(buffer, offset, length); - } - - private ulong ReadNumber() - { - return _currentReader.ReadNumber(); - } - - internal int ReadNum() - { - return _currentReader.ReadNum(); - } - - private uint ReadUInt32() - { - return _currentReader.ReadUInt32(); - } - - private ulong ReadUInt64() - { - return _currentReader.ReadUInt64(); - } - - private BlockType? ReadId() - { - ulong id = _currentReader.ReadNumber(); - if (id > 25) - { - return null; - } -#if DEBUG - Log.WriteLine("ReadId: {0}", (BlockType)id); -#endif - return (BlockType)id; - } - - private void SkipData(long size) - { - _currentReader.SkipData(size); - } - - private void SkipData() - { - _currentReader.SkipData(); - } - - private void WaitAttribute(BlockType attribute) - { - for (; ; ) - { - BlockType? type = ReadId(); - if (type == attribute) - { - return; - } - if (type == BlockType.End) - { - throw new InvalidOperationException(); - } - SkipData(); - } - } - - private void ReadArchiveProperties() - { - while (ReadId() != BlockType.End) - { - SkipData(); - } - } - - #endregion - - #region Private Methods - Reader Utilities - - private BitVector ReadBitVector(int length) - { - var bits = new BitVector(length); - - byte data = 0; - byte mask = 0; - - for (int i = 0; i < length; i++) - { - if (mask == 0) - { - data = ReadByte(); - mask = 0x80; - } - - if ((data & mask) != 0) - { - bits.SetBit(i); - } - - mask >>= 1; - } - - return bits; - } - - private BitVector ReadOptionalBitVector(int length) - { - byte allTrue = ReadByte(); - if (allTrue != 0) - { - return new BitVector(length, true); - } - - return ReadBitVector(length); - } - - private void ReadNumberVector( - List dataVector, - int numFiles, - Action action - ) - { - var defined = ReadOptionalBitVector(numFiles); - - using (CStreamSwitch streamSwitch = new CStreamSwitch()) - { - streamSwitch.Set(this, dataVector); - - for (int i = 0; i < numFiles; i++) - { - if (defined[i]) - { - action(i, checked((long)ReadUInt64())); - } - else - { - action(i, null); - } - } - } - } - - private DateTime TranslateTime(long time) - { - // FILETIME = 100-nanosecond intervals since January 1, 1601 (UTC) - return DateTime.FromFileTimeUtc(time).ToLocalTime(); - } - - private DateTime? TranslateTime(long? time) - { - if (time.HasValue && time.Value >= 0 && time.Value <= 2650467743999999999) //maximum Windows file time 31.12.9999 - { - return TranslateTime(time.Value); - } return null; } +#if DEBUG + Log.WriteLine("ReadId: {0}", (BlockType)id); +#endif + return (BlockType)id; + } - private void ReadDateTimeVector( - List dataVector, - int numFiles, - Action action - ) + private void SkipData(long size) + { + _currentReader.SkipData(size); + } + + private void SkipData() + { + _currentReader.SkipData(); + } + + private void WaitAttribute(BlockType attribute) + { + for (; ; ) { - ReadNumberVector( - dataVector, - numFiles, - (index, value) => action(index, TranslateTime(value)) - ); + var type = ReadId(); + if (type == attribute) + { + return; + } + if (type == BlockType.End) + { + throw new InvalidOperationException(); + } + SkipData(); + } + } + + private void ReadArchiveProperties() + { + while (ReadId() != BlockType.End) + { + SkipData(); + } + } + + #endregion + + #region Private Methods - Reader Utilities + + private BitVector ReadBitVector(int length) + { + var bits = new BitVector(length); + + byte data = 0; + byte mask = 0; + + for (var i = 0; i < length; i++) + { + if (mask == 0) + { + data = ReadByte(); + mask = 0x80; + } + + if ((data & mask) != 0) + { + bits.SetBit(i); + } + + mask >>= 1; } - private void ReadAttributeVector( - List dataVector, - int numFiles, - Action action - ) + return bits; + } + + private BitVector ReadOptionalBitVector(int length) + { + var allTrue = ReadByte(); + if (allTrue != 0) { - BitVector boolVector = ReadOptionalBitVector(numFiles); - using (var streamSwitch = new CStreamSwitch()) + return new BitVector(length, true); + } + + return ReadBitVector(length); + } + + private void ReadNumberVector( + List dataVector, + int numFiles, + Action action + ) + { + var defined = ReadOptionalBitVector(numFiles); + + using var streamSwitch = new CStreamSwitch(); + streamSwitch.Set(this, dataVector); + + for (var i = 0; i < numFiles; i++) + { + if (defined[i]) { - streamSwitch.Set(this, dataVector); - for (int i = 0; i < numFiles; i++) - { - if (boolVector[i]) - { - action(i, ReadUInt32()); - } - else - { - action(i, null); - } - } + action(i, checked((long)ReadUInt64())); + } + else + { + action(i, null); } } + } - #endregion + private DateTime TranslateTime(long time) + { + // FILETIME = 100-nanosecond intervals since January 1, 1601 (UTC) + return DateTime.FromFileTimeUtc(time).ToLocalTime(); + } - #region Private Methods - - private void GetNextFolderItem(CFolder folder) + private DateTime? TranslateTime(long? time) + { + if (time.HasValue && time.Value >= 0 && time.Value <= 2650467743999999999) //maximum Windows file time 31.12.9999 { -#if DEBUG - Log.WriteLine("-- GetNextFolderItem --"); - Log.PushIndent(); -#endif - try + return TranslateTime(time.Value); + } + return null; + } + + private void ReadDateTimeVector( + List dataVector, + int numFiles, + Action action + ) + { + ReadNumberVector( + dataVector, + numFiles, + (index, value) => action(index, TranslateTime(value)) + ); + } + + private void ReadAttributeVector( + List dataVector, + int numFiles, + Action action + ) + { + var boolVector = ReadOptionalBitVector(numFiles); + using var streamSwitch = new CStreamSwitch(); + streamSwitch.Set(this, dataVector); + for (var i = 0; i < numFiles; i++) + { + if (boolVector[i]) { - int numCoders = ReadNum(); -#if DEBUG - Log.WriteLine("NumCoders: " + numCoders); -#endif - folder._coders = new List(numCoders); - int numInStreams = 0; - int numOutStreams = 0; - for (int i = 0; i < numCoders; i++) - { -#if DEBUG - Log.WriteLine("-- Coder --"); - Log.PushIndent(); -#endif - try - { - CCoderInfo coder = new CCoderInfo(); - folder._coders.Add(coder); + action(i, ReadUInt32()); + } + else + { + action(i, null); + } + } + } - byte mainByte = ReadByte(); - int idSize = (mainByte & 0xF); - byte[] longId = new byte[idSize]; - ReadBytes(longId, 0, idSize); -#if DEBUG - Log.WriteLine( - "MethodId: " - + String.Join( - "", - Enumerable - .Range(0, idSize) - .Select(x => longId[x].ToString("x2")) - .ToArray() - ) - ); -#endif - if (idSize > 8) - { - throw new NotSupportedException(); - } - ulong id = 0; - for (int j = 0; j < idSize; j++) - { - id |= (ulong)longId[idSize - 1 - j] << (8 * j); - } - coder._methodId = new CMethodId(id); + #endregion - if ((mainByte & 0x10) != 0) - { - coder._numInStreams = ReadNum(); - coder._numOutStreams = ReadNum(); -#if DEBUG - Log.WriteLine( - "Complex Stream (In: " - + coder._numInStreams - + " - Out: " - + coder._numOutStreams - + ")" - ); -#endif - } - else - { -#if DEBUG - Log.WriteLine("Simple Stream (In: 1 - Out: 1)"); -#endif - coder._numInStreams = 1; - coder._numOutStreams = 1; - } + #region Private Methods - if ((mainByte & 0x20) != 0) - { - int propsSize = ReadNum(); - coder._props = new byte[propsSize]; - ReadBytes(coder._props, 0, propsSize); + private void GetNextFolderItem(CFolder folder) + { #if DEBUG - Log.WriteLine( - "Settings: " - + String.Join( - "", - coder._props.Select(bt => bt.ToString("x2")).ToArray() - ) - ); + Log.WriteLine("-- GetNextFolderItem --"); + Log.PushIndent(); #endif - } - - if ((mainByte & 0x80) != 0) - { - throw new NotSupportedException(); - } - - numInStreams += coder._numInStreams; - numOutStreams += coder._numOutStreams; - } - finally - { + try + { + var numCoders = ReadNum(); #if DEBUG - Log.PopIndent(); + Log.WriteLine("NumCoders: " + numCoders); #endif - } - } - - int numBindPairs = numOutStreams - 1; - folder._bindPairs = new List(numBindPairs); + folder._coders = new List(numCoders); + var numInStreams = 0; + var numOutStreams = 0; + for (var i = 0; i < numCoders; i++) + { #if DEBUG - Log.WriteLine("BindPairs: " + numBindPairs); + Log.WriteLine("-- Coder --"); Log.PushIndent(); #endif - for (int i = 0; i < numBindPairs; i++) + try { - CBindPair bp = new CBindPair(); - bp._inIndex = ReadNum(); - bp._outIndex = ReadNum(); - folder._bindPairs.Add(bp); + var coder = new CCoderInfo(); + folder._coders.Add(coder); + + var mainByte = ReadByte(); + var idSize = (mainByte & 0xF); + var longId = new byte[idSize]; + ReadBytes(longId, 0, idSize); #if DEBUG - Log.WriteLine("#" + i + " - In: " + bp._inIndex + " - Out: " + bp._outIndex); + Log.WriteLine( + "MethodId: " + + string.Join( + "", + Enumerable + .Range(0, idSize) + .Select(x => longId[x].ToString("x2")) + .ToArray() + ) + ); #endif - } -#if DEBUG - Log.PopIndent(); -#endif - - if (numInStreams < numBindPairs) - { - throw new NotSupportedException(); - } - - int numPackStreams = numInStreams - numBindPairs; - - //folder.PackStreams.Reserve(numPackStreams); - if (numPackStreams == 1) - { - for (int i = 0; i < numInStreams; i++) - { - if (folder.FindBindPairForInStream(i) < 0) - { -#if DEBUG - Log.WriteLine("Single PackStream: #" + i); -#endif - folder._packStreams.Add(i); - break; - } - } - - if (folder._packStreams.Count != 1) + if (idSize > 8) { throw new NotSupportedException(); } - } - else - { -#if DEBUG - Log.WriteLine("Multiple PackStreams ..."); - Log.PushIndent(); -#endif - for (int i = 0; i < numPackStreams; i++) + ulong id = 0; + for (var j = 0; j < idSize; j++) { - var num = ReadNum(); -#if DEBUG - Log.WriteLine("#" + i + " - " + num); -#endif - folder._packStreams.Add(num); + id |= (ulong)longId[idSize - 1 - j] << (8 * j); } + coder._methodId = new CMethodId(id); + + if ((mainByte & 0x10) != 0) + { + coder._numInStreams = ReadNum(); + coder._numOutStreams = ReadNum(); +#if DEBUG + Log.WriteLine( + "Complex Stream (In: " + + coder._numInStreams + + " - Out: " + + coder._numOutStreams + + ")" + ); +#endif + } + else + { +#if DEBUG + Log.WriteLine("Simple Stream (In: 1 - Out: 1)"); +#endif + coder._numInStreams = 1; + coder._numOutStreams = 1; + } + + if ((mainByte & 0x20) != 0) + { + var propsSize = ReadNum(); + coder._props = new byte[propsSize]; + ReadBytes(coder._props, 0, propsSize); +#if DEBUG + Log.WriteLine( + "Settings: " + + string.Join( + "", + coder._props.Select(bt => bt.ToString("x2")).ToArray() + ) + ); +#endif + } + + if ((mainByte & 0x80) != 0) + { + throw new NotSupportedException(); + } + + numInStreams += coder._numInStreams; + numOutStreams += coder._numOutStreams; + } + finally + { #if DEBUG Log.PopIndent(); #endif } } - finally + + var numBindPairs = numOutStreams - 1; + folder._bindPairs = new List(numBindPairs); +#if DEBUG + Log.WriteLine("BindPairs: " + numBindPairs); + Log.PushIndent(); +#endif + for (var i = 0; i < numBindPairs; i++) { + var bp = new CBindPair(); + bp._inIndex = ReadNum(); + bp._outIndex = ReadNum(); + folder._bindPairs.Add(bp); +#if DEBUG + Log.WriteLine("#" + i + " - In: " + bp._inIndex + " - Out: " + bp._outIndex); +#endif + } +#if DEBUG + Log.PopIndent(); +#endif + + if (numInStreams < numBindPairs) + { + throw new NotSupportedException(); + } + + var numPackStreams = numInStreams - numBindPairs; + + //folder.PackStreams.Reserve(numPackStreams); + if (numPackStreams == 1) + { + for (var i = 0; i < numInStreams; i++) + { + if (folder.FindBindPairForInStream(i) < 0) + { +#if DEBUG + Log.WriteLine("Single PackStream: #" + i); +#endif + folder._packStreams.Add(i); + break; + } + } + + if (folder._packStreams.Count != 1) + { + throw new NotSupportedException(); + } + } + else + { +#if DEBUG + Log.WriteLine("Multiple PackStreams ..."); + Log.PushIndent(); +#endif + for (var i = 0; i < numPackStreams; i++) + { + var num = ReadNum(); +#if DEBUG + Log.WriteLine("#" + i + " - " + num); +#endif + folder._packStreams.Add(num); + } #if DEBUG Log.PopIndent(); #endif } } - - private List ReadHashDigests(int count) + finally { #if DEBUG - Log.Write("ReadHashDigests:"); + Log.PopIndent(); +#endif + } + } + + private List ReadHashDigests(int count) + { +#if DEBUG + Log.Write("ReadHashDigests:"); #endif - var defined = ReadOptionalBitVector(count); - var digests = new List(count); - for (int i = 0; i < count; i++) + var defined = ReadOptionalBitVector(count); + var digests = new List(count); + for (var i = 0; i < count; i++) + { + if (defined[i]) { - if (defined[i]) - { - uint crc = ReadUInt32(); + var crc = ReadUInt32(); #if DEBUG - Log.Write(" " + crc.ToString("x8")); + Log.Write(" " + crc.ToString("x8")); #endif - digests.Add(crc); - } - else - { + digests.Add(crc); + } + else + { #if DEBUG - Log.Write(" ########"); + Log.Write(" ########"); #endif - digests.Add(null); - } + digests.Add(null); + } + } +#if DEBUG + + Log.WriteLine(); +#endif + return digests; + } + + private void ReadPackInfo( + out long dataOffset, + out List packSizes, + out List packCrCs + ) + { +#if DEBUG + Log.WriteLine("-- ReadPackInfo --"); + Log.PushIndent(); +#endif + try + { + packCrCs = null; + + dataOffset = checked((long)ReadNumber()); +#if DEBUG + Log.WriteLine("DataOffset: " + dataOffset); +#endif + + var numPackStreams = ReadNum(); +#if DEBUG + Log.WriteLine("NumPackStreams: " + numPackStreams); +#endif + + WaitAttribute(BlockType.Size); + packSizes = new List(numPackStreams); +#if DEBUG + Log.Write("Sizes:"); +#endif + for (var i = 0; i < numPackStreams; i++) + { + var size = checked((long)ReadNumber()); +#if DEBUG + Log.Write(" " + size); +#endif + packSizes.Add(size); } #if DEBUG - Log.WriteLine(); #endif - return digests; - } - private void ReadPackInfo( - out long dataOffset, - out List packSizes, - out List packCrCs - ) + BlockType? type; + for (; ; ) + { + type = ReadId(); + if (type == BlockType.End) + { + break; + } + if (type == BlockType.Crc) + { + packCrCs = ReadHashDigests(numPackStreams); + continue; + } + SkipData(); + } + + if (packCrCs is null) + { + packCrCs = new List(numPackStreams); + for (var i = 0; i < numPackStreams; i++) + { + packCrCs.Add(null); + } + } + } + finally { #if DEBUG - Log.WriteLine("-- ReadPackInfo --"); - Log.PushIndent(); + Log.PopIndent(); #endif - try + } + } + + private void ReadUnpackInfo(List dataVector, out List folders) + { +#if DEBUG + Log.WriteLine("-- ReadUnpackInfo --"); + Log.PushIndent(); +#endif + try + { + WaitAttribute(BlockType.Folder); + var numFolders = ReadNum(); +#if DEBUG + Log.WriteLine("NumFolders: {0}", numFolders); +#endif + + using (var streamSwitch = new CStreamSwitch()) { - packCrCs = null; + streamSwitch.Set(this, dataVector); - dataOffset = checked((long)ReadNumber()); -#if DEBUG - Log.WriteLine("DataOffset: " + dataOffset); -#endif + //folders.Clear(); + //folders.Reserve(numFolders); + folders = new List(numFolders); + var index = 0; + for (var i = 0; i < numFolders; i++) + { + var f = new CFolder { _firstPackStreamId = index }; + folders.Add(f); + GetNextFolderItem(f); + index += f._packStreams.Count; + } + } - int numPackStreams = ReadNum(); + WaitAttribute(BlockType.CodersUnpackSize); #if DEBUG - Log.WriteLine("NumPackStreams: " + numPackStreams); + Log.WriteLine("UnpackSizes:"); #endif - - WaitAttribute(BlockType.Size); - packSizes = new List(numPackStreams); + for (var i = 0; i < numFolders; i++) + { + var folder = folders[i]; #if DEBUG - Log.Write("Sizes:"); + Log.Write(" #" + i + ":"); #endif - for (int i = 0; i < numPackStreams; i++) + var numOutStreams = folder.GetNumOutStreams(); + for (var j = 0; j < numOutStreams; j++) { var size = checked((long)ReadNumber()); #if DEBUG Log.Write(" " + size); #endif - packSizes.Add(size); + folder._unpackSizes.Add(size); } #if DEBUG Log.WriteLine(); #endif - - BlockType? type; - for (; ; ) - { - type = ReadId(); - if (type == BlockType.End) - { - break; - } - if (type == BlockType.Crc) - { - packCrCs = ReadHashDigests(numPackStreams); - continue; - } - SkipData(); - } - - if (packCrCs is null) - { - packCrCs = new List(numPackStreams); - for (int i = 0; i < numPackStreams; i++) - { - packCrCs.Add(null); - } - } } - finally + + for (; ; ) { -#if DEBUG - Log.PopIndent(); -#endif - } - } - - private void ReadUnpackInfo(List dataVector, out List folders) - { -#if DEBUG - Log.WriteLine("-- ReadUnpackInfo --"); - Log.PushIndent(); -#endif - try - { - WaitAttribute(BlockType.Folder); - int numFolders = ReadNum(); -#if DEBUG - Log.WriteLine("NumFolders: {0}", numFolders); -#endif - - using (CStreamSwitch streamSwitch = new CStreamSwitch()) - { - streamSwitch.Set(this, dataVector); - - //folders.Clear(); - //folders.Reserve(numFolders); - folders = new List(numFolders); - int index = 0; - for (int i = 0; i < numFolders; i++) - { - var f = new CFolder { _firstPackStreamId = index }; - folders.Add(f); - GetNextFolderItem(f); - index += f._packStreams.Count; - } - } - - WaitAttribute(BlockType.CodersUnpackSize); -#if DEBUG - Log.WriteLine("UnpackSizes:"); -#endif - for (int i = 0; i < numFolders; i++) - { - CFolder folder = folders[i]; -#if DEBUG - Log.Write(" #" + i + ":"); -#endif - int numOutStreams = folder.GetNumOutStreams(); - for (int j = 0; j < numOutStreams; j++) - { - long size = checked((long)ReadNumber()); -#if DEBUG - Log.Write(" " + size); -#endif - folder._unpackSizes.Add(size); - } -#if DEBUG - Log.WriteLine(); -#endif - } - - for (; ; ) - { - BlockType? type = ReadId(); - if (type == BlockType.End) - { - return; - } - - if (type == BlockType.Crc) - { - List crcs = ReadHashDigests(numFolders); - for (int i = 0; i < numFolders; i++) - { - folders[i]._unpackCrc = crcs[i]; - } - continue; - } - - SkipData(); - } - } - finally - { -#if DEBUG - Log.PopIndent(); -#endif - } - } - - private void ReadSubStreamsInfo( - List folders, - out List numUnpackStreamsInFolders, - out List unpackSizes, - out List digests - ) - { -#if DEBUG - Log.WriteLine("-- ReadSubStreamsInfo --"); - Log.PushIndent(); -#endif - try - { - numUnpackStreamsInFolders = null; - - BlockType? type; - for (; ; ) - { - type = ReadId(); - if (type == BlockType.NumUnpackStream) - { - numUnpackStreamsInFolders = new List(folders.Count); -#if DEBUG - Log.Write("NumUnpackStreams:"); -#endif - for (int i = 0; i < folders.Count; i++) - { - var num = ReadNum(); -#if DEBUG - Log.Write(" " + num); -#endif - numUnpackStreamsInFolders.Add(num); - } -#if DEBUG - Log.WriteLine(); -#endif - continue; - } - if (type is BlockType.Crc or BlockType.Size) - { - break; - } - if (type == BlockType.End) - { - break; - } - SkipData(); - } - - if (numUnpackStreamsInFolders is null) - { - numUnpackStreamsInFolders = new List(folders.Count); - for (int i = 0; i < folders.Count; i++) - { - numUnpackStreamsInFolders.Add(1); - } - } - - unpackSizes = new List(folders.Count); - for (int i = 0; i < numUnpackStreamsInFolders.Count; i++) - { - // v3.13 incorrectly worked with empty folders - // v4.07: we check that folder is empty - int numSubstreams = numUnpackStreamsInFolders[i]; - if (numSubstreams == 0) - { - continue; - } -#if DEBUG - Log.Write("#{0} StreamSizes:", i); -#endif - long sum = 0; - for (int j = 1; j < numSubstreams; j++) - { - if (type == BlockType.Size) - { - long size = checked((long)ReadNumber()); -#if DEBUG - Log.Write(" " + size); -#endif - unpackSizes.Add(size); - sum += size; - } - } - unpackSizes.Add(folders[i].GetUnpackSize() - sum); -#if DEBUG - Log.WriteLine(" - rest: " + unpackSizes.Last()); -#endif - } - if (type == BlockType.Size) - { - type = ReadId(); - } - - int numDigests = 0; - int numDigestsTotal = 0; - for (int i = 0; i < folders.Count; i++) - { - int numSubstreams = numUnpackStreamsInFolders[i]; - if (numSubstreams != 1 || !folders[i].UnpackCrcDefined) - { - numDigests += numSubstreams; - } - numDigestsTotal += numSubstreams; - } - - digests = null; - - for (; ; ) - { - if (type == BlockType.Crc) - { - digests = new List(numDigestsTotal); - - List digests2 = ReadHashDigests(numDigests); - - int digestIndex = 0; - for (int i = 0; i < folders.Count; i++) - { - int numSubstreams = numUnpackStreamsInFolders[i]; - CFolder folder = folders[i]; - if (numSubstreams == 1 && folder.UnpackCrcDefined) - { - digests.Add(folder._unpackCrc.Value); - } - else - { - for (int j = 0; j < numSubstreams; j++, digestIndex++) - { - digests.Add(digests2[digestIndex]); - } - } - } - - if (digestIndex != numDigests || numDigestsTotal != digests.Count) - { - Debugger.Break(); - } - } - else if (type == BlockType.End) - { - if (digests is null) - { - digests = new List(numDigestsTotal); - for (int i = 0; i < numDigestsTotal; i++) - { - digests.Add(null); - } - } - return; - } - else - { - SkipData(); - } - - type = ReadId(); - } - } - finally - { -#if DEBUG - Log.PopIndent(); -#endif - } - } - - private void ReadStreamsInfo( - List dataVector, - out long dataOffset, - out List packSizes, - out List packCrCs, - out List folders, - out List numUnpackStreamsInFolders, - out List unpackSizes, - out List digests - ) - { -#if DEBUG - Log.WriteLine("-- ReadStreamsInfo --"); - Log.PushIndent(); -#endif - try - { - dataOffset = long.MinValue; - packSizes = null; - packCrCs = null; - folders = null; - numUnpackStreamsInFolders = null; - unpackSizes = null; - digests = null; - - for (; ; ) - { - switch (ReadId()) - { - case BlockType.End: - return; - case BlockType.PackInfo: - ReadPackInfo(out dataOffset, out packSizes, out packCrCs); - break; - case BlockType.UnpackInfo: - ReadUnpackInfo(dataVector, out folders); - break; - case BlockType.SubStreamsInfo: - ReadSubStreamsInfo( - folders, - out numUnpackStreamsInFolders, - out unpackSizes, - out digests - ); - break; - default: - throw new InvalidOperationException(); - } - } - } - finally - { -#if DEBUG - Log.PopIndent(); -#endif - } - } - - private List ReadAndDecodePackedStreams(long baseOffset, IPasswordProvider pass) - { -#if DEBUG - Log.WriteLine("-- ReadAndDecodePackedStreams --"); - Log.PushIndent(); -#endif - try - { - ReadStreamsInfo( - null, - out long dataStartPos, - out List packSizes, - out List packCrCs, - out List folders, - out List numUnpackStreamsInFolders, - out List unpackSizes, - out List digests - ); - - dataStartPos += baseOffset; - - var dataVector = new List(folders.Count); - int packIndex = 0; - foreach (var folder in folders) - { - long oldDataStartPos = dataStartPos; - long[] myPackSizes = new long[folder._packStreams.Count]; - for (int i = 0; i < myPackSizes.Length; i++) - { - long packSize = packSizes[packIndex + i]; - myPackSizes[i] = packSize; - dataStartPos += packSize; - } - - var outStream = DecoderStreamHelper.CreateDecoderStream( - _stream, - oldDataStartPos, - myPackSizes, - folder, - pass - ); - - int unpackSize = checked((int)folder.GetUnpackSize()); - byte[] data = new byte[unpackSize]; - outStream.ReadExact(data, 0, data.Length); - if (outStream.ReadByte() >= 0) - { - throw new InvalidOperationException( - "Decoded stream is longer than expected." - ); - } - dataVector.Add(data); - - if (folder.UnpackCrcDefined) - { - if ( - Crc.Finish(Crc.Update(Crc.INIT_CRC, data, 0, unpackSize)) - != folder._unpackCrc - ) - { - throw new InvalidOperationException( - "Decoded stream does not match expected CRC." - ); - } - } - } - return dataVector; - } - finally - { -#if DEBUG - Log.PopIndent(); -#endif - } - } - - private void ReadHeader(ArchiveDatabase db, IPasswordProvider getTextPassword) - { -#if DEBUG - Log.WriteLine("-- ReadHeader --"); - Log.PushIndent(); -#endif - try - { - BlockType? type = ReadId(); - - if (type == BlockType.ArchiveProperties) - { - ReadArchiveProperties(); - type = ReadId(); - } - - List dataVector = null; - if (type == BlockType.AdditionalStreamsInfo) - { - dataVector = ReadAndDecodePackedStreams( - db._startPositionAfterHeader, - getTextPassword - ); - type = ReadId(); - } - - List unpackSizes; - List digests; - - if (type == BlockType.MainStreamsInfo) - { - ReadStreamsInfo( - dataVector, - out db._dataStartPosition, - out db._packSizes, - out db._packCrCs, - out db._folders, - out db._numUnpackStreamsVector, - out unpackSizes, - out digests - ); - - db._dataStartPosition += db._startPositionAfterHeader; - type = ReadId(); - } - else - { - unpackSizes = new List(db._folders.Count); - digests = new List(db._folders.Count); - db._numUnpackStreamsVector = new List(db._folders.Count); - for (int i = 0; i < db._folders.Count; i++) - { - var folder = db._folders[i]; - unpackSizes.Add(folder.GetUnpackSize()); - digests.Add(folder._unpackCrc); - db._numUnpackStreamsVector.Add(1); - } - } - - db._files.Clear(); - + var type = ReadId(); if (type == BlockType.End) { return; } - if (type != BlockType.FilesInfo) + if (type == BlockType.Crc) { - throw new InvalidOperationException(); + var crcs = ReadHashDigests(numFolders); + for (var i = 0; i < numFolders; i++) + { + folders[i]._unpackCrc = crcs[i]; + } + continue; } - int numFiles = ReadNum(); -#if DEBUG - Log.WriteLine("NumFiles: " + numFiles); -#endif - db._files = new List(numFiles); - for (int i = 0; i < numFiles; i++) - { - db._files.Add(new CFileItem()); - } - - BitVector emptyStreamVector = new BitVector(numFiles); - BitVector emptyFileVector = null; - BitVector antiFileVector = null; - int numEmptyStreams = 0; - - for (; ; ) - { - type = ReadId(); - if (type == BlockType.End) - { - break; - } - - long size = checked((long)ReadNumber()); // TODO: throw invalid data on negative - int oldPos = _currentReader.Offset; - switch (type) - { - case BlockType.Name: - using (var streamSwitch = new CStreamSwitch()) - { - streamSwitch.Set(this, dataVector); -#if DEBUG - Log.Write("FileNames:"); -#endif - for (int i = 0; i < db._files.Count; i++) - { - db._files[i].Name = _currentReader.ReadString(); -#if DEBUG - Log.Write(" " + db._files[i].Name); -#endif - } -#if DEBUG - Log.WriteLine(); -#endif - } - break; - case BlockType.WinAttributes: -#if DEBUG - Log.Write("WinAttributes:"); -#endif - ReadAttributeVector( - dataVector, - numFiles, - delegate(int i, uint? attr) - { - // Some third party implementations established an unofficial extension - // of the 7z archive format by placing posix file attributes in the high - // bits of the windows file attributes. This makes use of the fact that - // the official implementation does not perform checks on this value. - // - // Newer versions of the official 7z GUI client will try to parse this - // extension, thus acknowledging the unofficial use of these bits. - // - // For us it is safe to just discard the upper bits if they are set and - // keep the windows attributes from the lower bits (which should be set - // properly even if posix file attributes are present, in order to be - // compatible with older 7z archive readers) - // - // Note that the 15th bit is used by some implementations to indicate - // presence of the extension, but not all implementations do that so - // we can't trust that bit and must ignore it. - // - if (attr.HasValue && (attr.Value >> 16) != 0) - { - attr = attr.Value & 0x7FFFu; - } - - db._files[i].Attrib = attr; -#if DEBUG - Log.Write( - " " + (attr.HasValue ? attr.Value.ToString("x8") : "n/a") - ); -#endif - } - ); -#if DEBUG - Log.WriteLine(); -#endif - break; - case BlockType.EmptyStream: - emptyStreamVector = ReadBitVector(numFiles); -#if DEBUG - - Log.Write("EmptyStream: "); -#endif - for (int i = 0; i < emptyStreamVector.Length; i++) - { - if (emptyStreamVector[i]) - { -#if DEBUG - Log.Write("x"); -#endif - numEmptyStreams++; - } - else - { -#if DEBUG - Log.Write("."); -#endif - } - } -#if DEBUG - Log.WriteLine(); -#endif - - emptyFileVector = new BitVector(numEmptyStreams); - antiFileVector = new BitVector(numEmptyStreams); - break; - case BlockType.EmptyFile: - emptyFileVector = ReadBitVector(numEmptyStreams); -#if DEBUG - Log.Write("EmptyFile: "); - for (int i = 0; i < numEmptyStreams; i++) - { - Log.Write(emptyFileVector[i] ? "x" : "."); - } - Log.WriteLine(); -#endif - break; - case BlockType.Anti: - antiFileVector = ReadBitVector(numEmptyStreams); -#if DEBUG - Log.Write("Anti: "); - for (int i = 0; i < numEmptyStreams; i++) - { - Log.Write(antiFileVector[i] ? "x" : "."); - } - Log.WriteLine(); -#endif - break; - case BlockType.StartPos: -#if DEBUG - Log.Write("StartPos:"); -#endif - ReadNumberVector( - dataVector, - numFiles, - delegate(int i, long? startPos) - { - db._files[i].StartPos = startPos; -#if DEBUG - Log.Write( - " " - + ( - startPos.HasValue - ? startPos.Value.ToString() - : "n/a" - ) - ); -#endif - } - ); -#if DEBUG - Log.WriteLine(); -#endif - break; - case BlockType.CTime: -#if DEBUG - Log.Write("CTime:"); -#endif - ReadDateTimeVector( - dataVector, - numFiles, - delegate(int i, DateTime? time) - { - db._files[i].CTime = time; -#if DEBUG - Log.Write( - " " + (time.HasValue ? time.Value.ToString() : "n/a") - ); -#endif - } - ); -#if DEBUG - Log.WriteLine(); -#endif - break; - case BlockType.ATime: -#if DEBUG - Log.Write("ATime:"); -#endif - ReadDateTimeVector( - dataVector, - numFiles, - delegate(int i, DateTime? time) - { - db._files[i].ATime = time; -#if DEBUG - Log.Write( - " " + (time.HasValue ? time.Value.ToString() : "n/a") - ); -#endif - } - ); -#if DEBUG - Log.WriteLine(); -#endif - break; - case BlockType.MTime: -#if DEBUG - Log.Write("MTime:"); -#endif - ReadDateTimeVector( - dataVector, - numFiles, - delegate(int i, DateTime? time) - { - db._files[i].MTime = time; -#if DEBUG - Log.Write( - " " + (time.HasValue ? time.Value.ToString() : "n/a") - ); -#endif - } - ); -#if DEBUG - Log.WriteLine(); -#endif - break; - case BlockType.Dummy: -#if DEBUG - Log.Write("Dummy: " + size); -#endif - for (long j = 0; j < size; j++) - { - if (ReadByte() != 0) - { - throw new InvalidOperationException(); - } - } - break; - default: - SkipData(size); - break; - } - - // since 0.3 record sizes must be correct - bool checkRecordsSize = (db._majorVersion > 0 || db._minorVersion > 2); - if (checkRecordsSize && _currentReader.Offset - oldPos != size) - { - throw new InvalidOperationException(); - } - } - - int emptyFileIndex = 0; - int sizeIndex = 0; - for (int i = 0; i < numFiles; i++) - { - CFileItem file = db._files[i]; - file.HasStream = !emptyStreamVector[i]; - if (file.HasStream) - { - file.IsDir = false; - file.IsAnti = false; - file.Size = unpackSizes[sizeIndex]; - file.Crc = digests[sizeIndex]; - sizeIndex++; - } - else - { - file.IsDir = !emptyFileVector[emptyFileIndex]; - file.IsAnti = antiFileVector[emptyFileIndex]; - emptyFileIndex++; - file.Size = 0; - file.Crc = null; - } - } - } - finally - { -#if DEBUG - Log.PopIndent(); -#endif + SkipData(); } } - - #endregion - - #region Public Methods - - public void Open(Stream stream) + finally { - Close(); - - _streamOrigin = stream.Position; - _streamEnding = stream.Length; - - // TODO: Check Signature! - _header = new byte[0x20]; - for (int offset = 0; offset < 0x20; ) - { - int delta = stream.Read(_header, offset, 0x20 - offset); - if (delta == 0) - { - throw new EndOfStreamException(); - } - offset += delta; - } - - _stream = stream; - } - - public void Close() - { - if (_stream != null) - { - _stream.Dispose(); - } - - foreach (var stream in _cachedStreams.Values) - { - stream.Dispose(); - } - - _cachedStreams.Clear(); - } - - public ArchiveDatabase ReadDatabase(IPasswordProvider pass) - { - var db = new ArchiveDatabase(pass); - db.Clear(); - - db._majorVersion = _header[6]; - db._minorVersion = _header[7]; - - if (db._majorVersion != 0) - { - throw new InvalidOperationException(); - } - - uint crcFromArchive = DataReader.Get32(_header, 8); - long nextHeaderOffset = (long)DataReader.Get64(_header, 0xC); - long nextHeaderSize = (long)DataReader.Get64(_header, 0x14); - uint nextHeaderCrc = DataReader.Get32(_header, 0x1C); - - uint crc = Crc.INIT_CRC; - crc = Crc.Update(crc, nextHeaderOffset); - crc = Crc.Update(crc, nextHeaderSize); - crc = Crc.Update(crc, nextHeaderCrc); - crc = Crc.Finish(crc); - - if (crc != crcFromArchive) - { - throw new InvalidOperationException(); - } - - db._startPositionAfterHeader = _streamOrigin + 0x20; - - // empty header is ok - if (nextHeaderSize == 0) - { - db.Fill(); - return db; - } - - if (nextHeaderOffset < 0 || nextHeaderSize < 0 || nextHeaderSize > Int32.MaxValue) - { - throw new InvalidOperationException(); - } - - if (nextHeaderOffset > _streamEnding - db._startPositionAfterHeader) - { - throw new InvalidOperationException("nextHeaderOffset is invalid"); - } - - _stream.Seek(nextHeaderOffset, SeekOrigin.Current); - - byte[] header = new byte[nextHeaderSize]; - _stream.ReadExact(header, 0, header.Length); - - if (Crc.Finish(Crc.Update(Crc.INIT_CRC, header, 0, header.Length)) != nextHeaderCrc) - { - throw new InvalidOperationException(); - } - - using (CStreamSwitch streamSwitch = new CStreamSwitch()) - { - streamSwitch.Set(this, header); - - BlockType? type = ReadId(); - if (type != BlockType.Header) - { - if (type != BlockType.EncodedHeader) - { - throw new InvalidOperationException(); - } - - var dataVector = ReadAndDecodePackedStreams( - db._startPositionAfterHeader, - db.PasswordProvider - ); - - // compressed header without content is odd but ok - if (dataVector.Count == 0) - { - db.Fill(); - return db; - } - - if (dataVector.Count != 1) - { - throw new InvalidOperationException(); - } - - streamSwitch.Set(this, dataVector[0]); - - if (ReadId() != BlockType.Header) - { - throw new InvalidOperationException(); - } - } - - ReadHeader(db, db.PasswordProvider); - } - db.Fill(); - return db; - } - - internal class CExtractFolderInfo - { - internal int _fileIndex; - internal int _folderIndex; - internal List _extractStatuses = new List(); - - internal CExtractFolderInfo(int fileIndex, int folderIndex) - { - _fileIndex = fileIndex; - _folderIndex = folderIndex; - if (fileIndex != -1) - { - _extractStatuses.Add(true); - } - } - } - - private class FolderUnpackStream : Stream - { - private readonly ArchiveDatabase _db; - private readonly int _startIndex; - private readonly List _extractStatuses; - - public FolderUnpackStream(ArchiveDatabase db, int p, int startIndex, List list) - { - _db = db; - _startIndex = startIndex; - _extractStatuses = list; - } - - #region Stream - - public override bool CanRead => true; - - public override bool CanSeek => false; - - public override bool CanWrite => false; - - public override void Flush() - { - throw new NotSupportedException(); - } - - public override long Length => throw new NotSupportedException(); - - public override long Position - { - get => throw new NotSupportedException(); - set => throw new NotSupportedException(); - } - - public override int Read(byte[] buffer, int offset, int count) - { - throw new NotSupportedException(); - } - - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } - - public override void SetLength(long value) - { - throw new NotSupportedException(); - } - - private Stream _stream; - private long _rem; - private int _currentIndex; - - private void ProcessEmptyFiles() - { - while ( - _currentIndex < _extractStatuses.Count - && _db._files[_startIndex + _currentIndex].Size == 0 - ) - { - OpenFile(); - _stream.Dispose(); - _stream = null; - _currentIndex++; - } - } - - private void OpenFile() - { - int index = _startIndex + _currentIndex; #if DEBUG - Log.WriteLine(_db._files[index].Name); + Log.PopIndent(); #endif - if (_db._files[index].CrcDefined) + } + } + + private void ReadSubStreamsInfo( + List folders, + out List numUnpackStreamsInFolders, + out List unpackSizes, + out List digests + ) + { +#if DEBUG + Log.WriteLine("-- ReadSubStreamsInfo --"); + Log.PushIndent(); +#endif + try + { + numUnpackStreamsInFolders = null; + + BlockType? type; + for (; ; ) + { + type = ReadId(); + if (type == BlockType.NumUnpackStream) { - _stream = new CrcCheckStream(_db._files[index].Crc.Value); + numUnpackStreamsInFolders = new List(folders.Count); +#if DEBUG + Log.Write("NumUnpackStreams:"); +#endif + for (var i = 0; i < folders.Count; i++) + { + var num = ReadNum(); +#if DEBUG + Log.Write(" " + num); +#endif + numUnpackStreamsInFolders.Add(num); + } +#if DEBUG + Log.WriteLine(); +#endif + continue; + } + if (type is BlockType.Crc or BlockType.Size) + { + break; + } + if (type == BlockType.End) + { + break; + } + SkipData(); + } + + if (numUnpackStreamsInFolders is null) + { + numUnpackStreamsInFolders = new List(folders.Count); + for (var i = 0; i < folders.Count; i++) + { + numUnpackStreamsInFolders.Add(1); + } + } + + unpackSizes = new List(folders.Count); + for (var i = 0; i < numUnpackStreamsInFolders.Count; i++) + { + // v3.13 incorrectly worked with empty folders + // v4.07: we check that folder is empty + var numSubstreams = numUnpackStreamsInFolders[i]; + if (numSubstreams == 0) + { + continue; + } +#if DEBUG + Log.Write("#{0} StreamSizes:", i); +#endif + long sum = 0; + for (var j = 1; j < numSubstreams; j++) + { + if (type == BlockType.Size) + { + var size = checked((long)ReadNumber()); +#if DEBUG + Log.Write(" " + size); +#endif + unpackSizes.Add(size); + sum += size; + } + } + unpackSizes.Add(folders[i].GetUnpackSize() - sum); +#if DEBUG + Log.WriteLine(" - rest: " + unpackSizes.Last()); +#endif + } + if (type == BlockType.Size) + { + type = ReadId(); + } + + var numDigests = 0; + var numDigestsTotal = 0; + for (var i = 0; i < folders.Count; i++) + { + var numSubstreams = numUnpackStreamsInFolders[i]; + if (numSubstreams != 1 || !folders[i].UnpackCrcDefined) + { + numDigests += numSubstreams; + } + numDigestsTotal += numSubstreams; + } + + digests = null; + + for (; ; ) + { + if (type == BlockType.Crc) + { + digests = new List(numDigestsTotal); + + var digests2 = ReadHashDigests(numDigests); + + var digestIndex = 0; + for (var i = 0; i < folders.Count; i++) + { + var numSubstreams = numUnpackStreamsInFolders[i]; + var folder = folders[i]; + if (numSubstreams == 1 && folder.UnpackCrcDefined) + { + digests.Add(folder._unpackCrc.Value); + } + else + { + for (var j = 0; j < numSubstreams; j++, digestIndex++) + { + digests.Add(digests2[digestIndex]); + } + } + } + + if (digestIndex != numDigests || numDigestsTotal != digests.Count) + { + Debugger.Break(); + } + } + else if (type == BlockType.End) + { + if (digests is null) + { + digests = new List(numDigestsTotal); + for (var i = 0; i < numDigestsTotal; i++) + { + digests.Add(null); + } + } + return; } else { - _stream = new MemoryStream(); + SkipData(); } - _rem = _db._files[index].Size; - } - public override void Write(byte[] buffer, int offset, int count) - { - while (count != 0) - { - if (_stream != null) - { - int write = count; - if (write > _rem) - { - write = (int)_rem; - } - _stream.Write(buffer, offset, write); - count -= write; - _rem -= write; - offset += write; - if (_rem == 0) - { - _stream.Dispose(); - _stream = null; - _currentIndex++; - ProcessEmptyFiles(); - } - } - else - { - ProcessEmptyFiles(); - if (_currentIndex == _extractStatuses.Count) - { - // we support partial extracting - Debugger.Break(); - throw new NotSupportedException(); - } - OpenFile(); - } - } + type = ReadId(); } - - #endregion } - - private Stream GetCachedDecoderStream(ArchiveDatabase db, int folderIndex) + finally { - if (!_cachedStreams.TryGetValue(folderIndex, out Stream s)) +#if DEBUG + Log.PopIndent(); +#endif + } + } + + private void ReadStreamsInfo( + List dataVector, + out long dataOffset, + out List packSizes, + out List packCrCs, + out List folders, + out List numUnpackStreamsInFolders, + out List unpackSizes, + out List digests + ) + { +#if DEBUG + Log.WriteLine("-- ReadStreamsInfo --"); + Log.PushIndent(); +#endif + try + { + dataOffset = long.MinValue; + packSizes = null; + packCrCs = null; + folders = null; + numUnpackStreamsInFolders = null; + unpackSizes = null; + digests = null; + + for (; ; ) { - CFolder folderInfo = db._folders[folderIndex]; - int packStreamIndex = db._folders[folderIndex]._firstPackStreamId; - long folderStartPackPos = db.GetFolderStreamPos(folderInfo, 0); - var count = folderInfo._packStreams.Count; - long[] packSizes = new long[count]; - for (int j = 0; j < count; j++) + switch (ReadId()) { - packSizes[j] = db._packSizes[packStreamIndex + j]; + case BlockType.End: + return; + case BlockType.PackInfo: + ReadPackInfo(out dataOffset, out packSizes, out packCrCs); + break; + case BlockType.UnpackInfo: + ReadUnpackInfo(dataVector, out folders); + break; + case BlockType.SubStreamsInfo: + ReadSubStreamsInfo( + folders, + out numUnpackStreamsInFolders, + out unpackSizes, + out digests + ); + break; + default: + throw new InvalidOperationException(); + } + } + } + finally + { +#if DEBUG + Log.PopIndent(); +#endif + } + } + + private List ReadAndDecodePackedStreams(long baseOffset, IPasswordProvider pass) + { +#if DEBUG + Log.WriteLine("-- ReadAndDecodePackedStreams --"); + Log.PushIndent(); +#endif + try + { + ReadStreamsInfo( + null, + out var dataStartPos, + out var packSizes, + out var packCrCs, + out var folders, + out var numUnpackStreamsInFolders, + out var unpackSizes, + out var digests + ); + + dataStartPos += baseOffset; + + var dataVector = new List(folders.Count); + var packIndex = 0; + foreach (var folder in folders) + { + var oldDataStartPos = dataStartPos; + var myPackSizes = new long[folder._packStreams.Count]; + for (var i = 0; i < myPackSizes.Length; i++) + { + var packSize = packSizes[packIndex + i]; + myPackSizes[i] = packSize; + dataStartPos += packSize; } - s = DecoderStreamHelper.CreateDecoderStream( + var outStream = DecoderStreamHelper.CreateDecoderStream( _stream, - folderStartPackPos, - packSizes, - folderInfo, - db.PasswordProvider + oldDataStartPos, + myPackSizes, + folder, + pass ); - _cachedStreams.Add(folderIndex, s); + + var unpackSize = checked((int)folder.GetUnpackSize()); + var data = new byte[unpackSize]; + outStream.ReadExact(data, 0, data.Length); + if (outStream.ReadByte() >= 0) + { + throw new InvalidOperationException( + "Decoded stream is longer than expected." + ); + } + dataVector.Add(data); + + if (folder.UnpackCrcDefined) + { + if ( + Crc.Finish(Crc.Update(Crc.INIT_CRC, data, 0, unpackSize)) + != folder._unpackCrc + ) + { + throw new InvalidOperationException( + "Decoded stream does not match expected CRC." + ); + } + } } - return s; + return dataVector; } - - public Stream OpenStream(ArchiveDatabase db, int fileIndex) + finally { - int folderIndex = db._fileIndexToFolderIndexMap[fileIndex]; - int numFilesInFolder = db._numUnpackStreamsVector[folderIndex]; - int firstFileIndex = db._folderStartFileIndex[folderIndex]; - if (firstFileIndex > fileIndex || fileIndex - firstFileIndex >= numFilesInFolder) - { - throw new InvalidOperationException(); - } - - int skipCount = fileIndex - firstFileIndex; - long skipSize = 0; - for (int i = 0; i < skipCount; i++) - { - skipSize += db._files[firstFileIndex + i].Size; - } - - Stream s = GetCachedDecoderStream(db, folderIndex); - s.Position = skipSize; - return new ReadOnlySubStream(s, db._files[fileIndex].Size); +#if DEBUG + Log.PopIndent(); +#endif } + } - public void Extract(ArchiveDatabase db, int[] indices) + private void ReadHeader(ArchiveDatabase db, IPasswordProvider getTextPassword) + { +#if DEBUG + Log.WriteLine("-- ReadHeader --"); + Log.PushIndent(); +#endif + try { - bool allFilesMode = (indices is null); + var type = ReadId(); - int numItems = allFilesMode ? db._files.Count : indices.Length; + if (type == BlockType.ArchiveProperties) + { + ReadArchiveProperties(); + type = ReadId(); + } - if (numItems == 0) + List dataVector = null; + if (type == BlockType.AdditionalStreamsInfo) + { + dataVector = ReadAndDecodePackedStreams( + db._startPositionAfterHeader, + getTextPassword + ); + type = ReadId(); + } + + List unpackSizes; + List digests; + + if (type == BlockType.MainStreamsInfo) + { + ReadStreamsInfo( + dataVector, + out db._dataStartPosition, + out db._packSizes, + out db._packCrCs, + out db._folders, + out db._numUnpackStreamsVector, + out unpackSizes, + out digests + ); + + db._dataStartPosition += db._startPositionAfterHeader; + type = ReadId(); + } + else + { + unpackSizes = new List(db._folders.Count); + digests = new List(db._folders.Count); + db._numUnpackStreamsVector = new List(db._folders.Count); + for (var i = 0; i < db._folders.Count; i++) + { + var folder = db._folders[i]; + unpackSizes.Add(folder.GetUnpackSize()); + digests.Add(folder._unpackCrc); + db._numUnpackStreamsVector.Add(1); + } + } + + db._files.Clear(); + + if (type == BlockType.End) { return; } - List extractFolderInfoVector = new List(); - for (int i = 0; i < numItems; i++) + if (type != BlockType.FilesInfo) { - int fileIndex = allFilesMode ? i : indices[i]; + throw new InvalidOperationException(); + } - int folderIndex = db._fileIndexToFolderIndexMap[fileIndex]; - if (folderIndex == -1) + var numFiles = ReadNum(); +#if DEBUG + Log.WriteLine("NumFiles: " + numFiles); +#endif + db._files = new List(numFiles); + for (var i = 0; i < numFiles; i++) + { + db._files.Add(new CFileItem()); + } + + var emptyStreamVector = new BitVector(numFiles); + BitVector emptyFileVector = null; + BitVector antiFileVector = null; + var numEmptyStreams = 0; + + for (; ; ) + { + type = ReadId(); + if (type == BlockType.End) { - extractFolderInfoVector.Add(new CExtractFolderInfo(fileIndex, -1)); - continue; + break; } - if ( - extractFolderInfoVector.Count == 0 - || folderIndex != extractFolderInfoVector.Last()._folderIndex - ) + var size = checked((long)ReadNumber()); // TODO: throw invalid data on negative + var oldPos = _currentReader.Offset; + switch (type) { - extractFolderInfoVector.Add(new CExtractFolderInfo(-1, folderIndex)); + case BlockType.Name: + using (var streamSwitch = new CStreamSwitch()) + { + streamSwitch.Set(this, dataVector); +#if DEBUG + Log.Write("FileNames:"); +#endif + for (var i = 0; i < db._files.Count; i++) + { + db._files[i].Name = _currentReader.ReadString(); +#if DEBUG + Log.Write(" " + db._files[i].Name); +#endif + } +#if DEBUG + Log.WriteLine(); +#endif + } + break; + case BlockType.WinAttributes: +#if DEBUG + Log.Write("WinAttributes:"); +#endif + ReadAttributeVector( + dataVector, + numFiles, + delegate (int i, uint? attr) + { + // Some third party implementations established an unofficial extension + // of the 7z archive format by placing posix file attributes in the high + // bits of the windows file attributes. This makes use of the fact that + // the official implementation does not perform checks on this value. + // + // Newer versions of the official 7z GUI client will try to parse this + // extension, thus acknowledging the unofficial use of these bits. + // + // For us it is safe to just discard the upper bits if they are set and + // keep the windows attributes from the lower bits (which should be set + // properly even if posix file attributes are present, in order to be + // compatible with older 7z archive readers) + // + // Note that the 15th bit is used by some implementations to indicate + // presence of the extension, but not all implementations do that so + // we can't trust that bit and must ignore it. + // + if (attr.HasValue && (attr.Value >> 16) != 0) + { + attr = attr.Value & 0x7FFFu; + } + + db._files[i].Attrib = attr; +#if DEBUG + Log.Write( + " " + (attr.HasValue ? attr.Value.ToString("x8") : "n/a") + ); +#endif + } + ); +#if DEBUG + Log.WriteLine(); +#endif + break; + case BlockType.EmptyStream: + emptyStreamVector = ReadBitVector(numFiles); +#if DEBUG + + Log.Write("EmptyStream: "); +#endif + for (var i = 0; i < emptyStreamVector.Length; i++) + { + if (emptyStreamVector[i]) + { +#if DEBUG + Log.Write("x"); +#endif + numEmptyStreams++; + } + else + { +#if DEBUG + Log.Write("."); +#endif + } + } +#if DEBUG + Log.WriteLine(); +#endif + + emptyFileVector = new BitVector(numEmptyStreams); + antiFileVector = new BitVector(numEmptyStreams); + break; + case BlockType.EmptyFile: + emptyFileVector = ReadBitVector(numEmptyStreams); +#if DEBUG + Log.Write("EmptyFile: "); + for (var i = 0; i < numEmptyStreams; i++) + { + Log.Write(emptyFileVector[i] ? "x" : "."); + } + Log.WriteLine(); +#endif + break; + case BlockType.Anti: + antiFileVector = ReadBitVector(numEmptyStreams); +#if DEBUG + Log.Write("Anti: "); + for (var i = 0; i < numEmptyStreams; i++) + { + Log.Write(antiFileVector[i] ? "x" : "."); + } + Log.WriteLine(); +#endif + break; + case BlockType.StartPos: +#if DEBUG + Log.Write("StartPos:"); +#endif + ReadNumberVector( + dataVector, + numFiles, + delegate (int i, long? startPos) + { + db._files[i].StartPos = startPos; +#if DEBUG + Log.Write( + " " + + ( + startPos.HasValue + ? startPos.Value.ToString() + : "n/a" + ) + ); +#endif + } + ); +#if DEBUG + Log.WriteLine(); +#endif + break; + case BlockType.CTime: +#if DEBUG + Log.Write("CTime:"); +#endif + ReadDateTimeVector( + dataVector, + numFiles, + delegate (int i, DateTime? time) + { + db._files[i].CTime = time; +#if DEBUG + Log.Write( + " " + (time.HasValue ? time.Value.ToString() : "n/a") + ); +#endif + } + ); +#if DEBUG + Log.WriteLine(); +#endif + break; + case BlockType.ATime: +#if DEBUG + Log.Write("ATime:"); +#endif + ReadDateTimeVector( + dataVector, + numFiles, + delegate (int i, DateTime? time) + { + db._files[i].ATime = time; +#if DEBUG + Log.Write( + " " + (time.HasValue ? time.Value.ToString() : "n/a") + ); +#endif + } + ); +#if DEBUG + Log.WriteLine(); +#endif + break; + case BlockType.MTime: +#if DEBUG + Log.Write("MTime:"); +#endif + ReadDateTimeVector( + dataVector, + numFiles, + delegate (int i, DateTime? time) + { + db._files[i].MTime = time; +#if DEBUG + Log.Write( + " " + (time.HasValue ? time.Value.ToString() : "n/a") + ); +#endif + } + ); +#if DEBUG + Log.WriteLine(); +#endif + break; + case BlockType.Dummy: +#if DEBUG + Log.Write("Dummy: " + size); +#endif + for (long j = 0; j < size; j++) + { + if (ReadByte() != 0) + { + throw new InvalidOperationException(); + } + } + break; + default: + SkipData(size); + break; } - CExtractFolderInfo efi = extractFolderInfoVector.Last(); - - int startIndex = db._folderStartFileIndex[folderIndex]; - for ( - int index = efi._extractStatuses.Count; - index <= fileIndex - startIndex; - index++ - ) + // since 0.3 record sizes must be correct + var checkRecordsSize = (db._majorVersion > 0 || db._minorVersion > 2); + if (checkRecordsSize && _currentReader.Offset - oldPos != size) { - efi._extractStatuses.Add(index == fileIndex - startIndex); + throw new InvalidOperationException(); } } - byte[] buffer = null; - foreach (CExtractFolderInfo efi in extractFolderInfoVector) + var emptyFileIndex = 0; + var sizeIndex = 0; + for (var i = 0; i < numFiles; i++) { - int startIndex; - if (efi._fileIndex != -1) + var file = db._files[i]; + file.HasStream = !emptyStreamVector[i]; + if (file.HasStream) { - startIndex = efi._fileIndex; + file.IsDir = false; + file.IsAnti = false; + file.Size = unpackSizes[sizeIndex]; + file.Crc = digests[sizeIndex]; + sizeIndex++; } else { - startIndex = db._folderStartFileIndex[efi._folderIndex]; - } - - var outStream = new FolderUnpackStream(db, 0, startIndex, efi._extractStatuses); - - if (efi._fileIndex != -1) - { - continue; - } - - int folderIndex = efi._folderIndex; - CFolder folderInfo = db._folders[folderIndex]; - - int packStreamIndex = db._folders[folderIndex]._firstPackStreamId; - long folderStartPackPos = db.GetFolderStreamPos(folderInfo, 0); - - var count = folderInfo._packStreams.Count; - long[] packSizes = new long[count]; - for (int j = 0; j < count; j++) - { - packSizes[j] = db._packSizes[packStreamIndex + j]; - } - - // TODO: If the decoding fails the last file may be extracted incompletely. Delete it? - - Stream s = DecoderStreamHelper.CreateDecoderStream( - _stream, - folderStartPackPos, - packSizes, - folderInfo, - db.PasswordProvider - ); - buffer ??= new byte[4 << 10]; - for (; ; ) - { - int processed = s.Read(buffer, 0, buffer.Length); - if (processed == 0) - { - break; - } - outStream.Write(buffer, 0, processed); + file.IsDir = !emptyFileVector[emptyFileIndex]; + file.IsAnti = antiFileVector[emptyFileIndex]; + emptyFileIndex++; + file.Size = 0; + file.Crc = null; } } } - - public IEnumerable GetFiles(ArchiveDatabase db) + finally { - return db._files; +#if DEBUG + Log.PopIndent(); +#endif + } + } + + #endregion + + #region Public Methods + + public void Open(Stream stream) + { + Close(); + + _streamOrigin = stream.Position; + _streamEnding = stream.Length; + + // TODO: Check Signature! + _header = new byte[0x20]; + for (var offset = 0; offset < 0x20;) + { + var delta = stream.Read(_header, offset, 0x20 - offset); + if (delta == 0) + { + throw new EndOfStreamException(); + } + offset += delta; } - public int GetFileIndex(ArchiveDatabase db, CFileItem item) + _stream = stream; + } + + public void Close() + { + _stream?.Dispose(); + + foreach (var stream in _cachedStreams.Values) { - return db._files.IndexOf(item); + stream.Dispose(); + } + + _cachedStreams.Clear(); + } + + public ArchiveDatabase ReadDatabase(IPasswordProvider pass) + { + var db = new ArchiveDatabase(pass); + db.Clear(); + + db._majorVersion = _header[6]; + db._minorVersion = _header[7]; + + if (db._majorVersion != 0) + { + throw new InvalidOperationException(); + } + + var crcFromArchive = DataReader.Get32(_header, 8); + var nextHeaderOffset = (long)DataReader.Get64(_header, 0xC); + var nextHeaderSize = (long)DataReader.Get64(_header, 0x14); + var nextHeaderCrc = DataReader.Get32(_header, 0x1C); + + var crc = Crc.INIT_CRC; + crc = Crc.Update(crc, nextHeaderOffset); + crc = Crc.Update(crc, nextHeaderSize); + crc = Crc.Update(crc, nextHeaderCrc); + crc = Crc.Finish(crc); + + if (crc != crcFromArchive) + { + throw new InvalidOperationException(); + } + + db._startPositionAfterHeader = _streamOrigin + 0x20; + + // empty header is ok + if (nextHeaderSize == 0) + { + db.Fill(); + return db; + } + + if (nextHeaderOffset < 0 || nextHeaderSize < 0 || nextHeaderSize > int.MaxValue) + { + throw new InvalidOperationException(); + } + + if (nextHeaderOffset > _streamEnding - db._startPositionAfterHeader) + { + throw new InvalidOperationException("nextHeaderOffset is invalid"); + } + + _stream.Seek(nextHeaderOffset, SeekOrigin.Current); + + var header = new byte[nextHeaderSize]; + _stream.ReadExact(header, 0, header.Length); + + if (Crc.Finish(Crc.Update(Crc.INIT_CRC, header, 0, header.Length)) != nextHeaderCrc) + { + throw new InvalidOperationException(); + } + + using (var streamSwitch = new CStreamSwitch()) + { + streamSwitch.Set(this, header); + + var type = ReadId(); + if (type != BlockType.Header) + { + if (type != BlockType.EncodedHeader) + { + throw new InvalidOperationException(); + } + + var dataVector = ReadAndDecodePackedStreams( + db._startPositionAfterHeader, + db.PasswordProvider + ); + + // compressed header without content is odd but ok + if (dataVector.Count == 0) + { + db.Fill(); + return db; + } + + if (dataVector.Count != 1) + { + throw new InvalidOperationException(); + } + + streamSwitch.Set(this, dataVector[0]); + + if (ReadId() != BlockType.Header) + { + throw new InvalidOperationException(); + } + } + + ReadHeader(db, db.PasswordProvider); + } + db.Fill(); + return db; + } + + internal class CExtractFolderInfo + { + internal int _fileIndex; + internal int _folderIndex; + internal List _extractStatuses = new List(); + + internal CExtractFolderInfo(int fileIndex, int folderIndex) + { + _fileIndex = fileIndex; + _folderIndex = folderIndex; + if (fileIndex != -1) + { + _extractStatuses.Add(true); + } + } + } + + private class FolderUnpackStream : Stream + { + private readonly ArchiveDatabase _db; + private readonly int _startIndex; + private readonly List _extractStatuses; + + public FolderUnpackStream(ArchiveDatabase db, int p, int startIndex, List list) + { + _db = db; + _startIndex = startIndex; + _extractStatuses = list; + } + + #region Stream + + public override bool CanRead => true; + + public override bool CanSeek => false; + + public override bool CanWrite => false; + + public override void Flush() + { + throw new NotSupportedException(); + } + + public override long Length => throw new NotSupportedException(); + + public override long Position + { + get => throw new NotSupportedException(); + set => throw new NotSupportedException(); + } + + public override int Read(byte[] buffer, int offset, int count) + { + throw new NotSupportedException(); + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } + + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + private Stream _stream; + private long _rem; + private int _currentIndex; + + private void ProcessEmptyFiles() + { + while ( + _currentIndex < _extractStatuses.Count + && _db._files[_startIndex + _currentIndex].Size == 0 + ) + { + OpenFile(); + _stream.Dispose(); + _stream = null; + _currentIndex++; + } + } + + private void OpenFile() + { + var index = _startIndex + _currentIndex; +#if DEBUG + Log.WriteLine(_db._files[index].Name); +#endif + if (_db._files[index].CrcDefined) + { + _stream = new CrcCheckStream(_db._files[index].Crc.Value); + } + else + { + _stream = new MemoryStream(); + } + _rem = _db._files[index].Size; + } + + public override void Write(byte[] buffer, int offset, int count) + { + while (count != 0) + { + if (_stream != null) + { + var write = count; + if (write > _rem) + { + write = (int)_rem; + } + _stream.Write(buffer, offset, write); + count -= write; + _rem -= write; + offset += write; + if (_rem == 0) + { + _stream.Dispose(); + _stream = null; + _currentIndex++; + ProcessEmptyFiles(); + } + } + else + { + ProcessEmptyFiles(); + if (_currentIndex == _extractStatuses.Count) + { + // we support partial extracting + Debugger.Break(); + throw new NotSupportedException(); + } + OpenFile(); + } + } } #endregion } + + private Stream GetCachedDecoderStream(ArchiveDatabase db, int folderIndex) + { + if (!_cachedStreams.TryGetValue(folderIndex, out var s)) + { + var folderInfo = db._folders[folderIndex]; + var packStreamIndex = db._folders[folderIndex]._firstPackStreamId; + var folderStartPackPos = db.GetFolderStreamPos(folderInfo, 0); + var count = folderInfo._packStreams.Count; + var packSizes = new long[count]; + for (var j = 0; j < count; j++) + { + packSizes[j] = db._packSizes[packStreamIndex + j]; + } + + s = DecoderStreamHelper.CreateDecoderStream( + _stream, + folderStartPackPos, + packSizes, + folderInfo, + db.PasswordProvider + ); + _cachedStreams.Add(folderIndex, s); + } + return s; + } + + public Stream OpenStream(ArchiveDatabase db, int fileIndex) + { + var folderIndex = db._fileIndexToFolderIndexMap[fileIndex]; + var numFilesInFolder = db._numUnpackStreamsVector[folderIndex]; + var firstFileIndex = db._folderStartFileIndex[folderIndex]; + if (firstFileIndex > fileIndex || fileIndex - firstFileIndex >= numFilesInFolder) + { + throw new InvalidOperationException(); + } + + var skipCount = fileIndex - firstFileIndex; + long skipSize = 0; + for (var i = 0; i < skipCount; i++) + { + skipSize += db._files[firstFileIndex + i].Size; + } + + var s = GetCachedDecoderStream(db, folderIndex); + s.Position = skipSize; + return new ReadOnlySubStream(s, db._files[fileIndex].Size); + } + + public void Extract(ArchiveDatabase db, int[] indices) + { + var allFilesMode = (indices is null); + + var numItems = allFilesMode ? db._files.Count : indices.Length; + + if (numItems == 0) + { + return; + } + + var extractFolderInfoVector = new List(); + for (var i = 0; i < numItems; i++) + { + var fileIndex = allFilesMode ? i : indices[i]; + + var folderIndex = db._fileIndexToFolderIndexMap[fileIndex]; + if (folderIndex == -1) + { + extractFolderInfoVector.Add(new CExtractFolderInfo(fileIndex, -1)); + continue; + } + + if ( + extractFolderInfoVector.Count == 0 + || folderIndex != extractFolderInfoVector.Last()._folderIndex + ) + { + extractFolderInfoVector.Add(new CExtractFolderInfo(-1, folderIndex)); + } + + var efi = extractFolderInfoVector.Last(); + + var startIndex = db._folderStartFileIndex[folderIndex]; + for ( + var index = efi._extractStatuses.Count; + index <= fileIndex - startIndex; + index++ + ) + { + efi._extractStatuses.Add(index == fileIndex - startIndex); + } + } + + byte[] buffer = null; + foreach (var efi in extractFolderInfoVector) + { + int startIndex; + if (efi._fileIndex != -1) + { + startIndex = efi._fileIndex; + } + else + { + startIndex = db._folderStartFileIndex[efi._folderIndex]; + } + + var outStream = new FolderUnpackStream(db, 0, startIndex, efi._extractStatuses); + + if (efi._fileIndex != -1) + { + continue; + } + + var folderIndex = efi._folderIndex; + var folderInfo = db._folders[folderIndex]; + + var packStreamIndex = db._folders[folderIndex]._firstPackStreamId; + var folderStartPackPos = db.GetFolderStreamPos(folderInfo, 0); + + var count = folderInfo._packStreams.Count; + var packSizes = new long[count]; + for (var j = 0; j < count; j++) + { + packSizes[j] = db._packSizes[packStreamIndex + j]; + } + + // TODO: If the decoding fails the last file may be extracted incompletely. Delete it? + + var s = DecoderStreamHelper.CreateDecoderStream( + _stream, + folderStartPackPos, + packSizes, + folderInfo, + db.PasswordProvider + ); + buffer ??= new byte[4 << 10]; + for (; ; ) + { + var processed = s.Read(buffer, 0, buffer.Length); + if (processed == 0) + { + break; + } + outStream.Write(buffer, 0, processed); + } + } + } + + public IEnumerable GetFiles(ArchiveDatabase db) + { + return db._files; + } + + public int GetFileIndex(ArchiveDatabase db, CFileItem item) + { + return db._files.IndexOf(item); + } + + #endregion } diff --git a/src/SharpCompress/Common/SevenZip/CBindPair.cs b/src/SharpCompress/Common/SevenZip/CBindPair.cs index 1d76acf0..f9d752e6 100644 --- a/src/SharpCompress/Common/SevenZip/CBindPair.cs +++ b/src/SharpCompress/Common/SevenZip/CBindPair.cs @@ -1,8 +1,7 @@ -namespace SharpCompress.Common.SevenZip +namespace SharpCompress.Common.SevenZip; + +internal class CBindPair { - internal class CBindPair - { - internal int _inIndex; - internal int _outIndex; - } + internal int _inIndex; + internal int _outIndex; } diff --git a/src/SharpCompress/Common/SevenZip/CCoderInfo.cs b/src/SharpCompress/Common/SevenZip/CCoderInfo.cs index 5db367b2..d53c44f0 100644 --- a/src/SharpCompress/Common/SevenZip/CCoderInfo.cs +++ b/src/SharpCompress/Common/SevenZip/CCoderInfo.cs @@ -1,12 +1,11 @@ -#nullable disable +#nullable disable -namespace SharpCompress.Common.SevenZip +namespace SharpCompress.Common.SevenZip; + +internal class CCoderInfo { - internal class CCoderInfo - { - internal CMethodId _methodId; - internal byte[] _props; - internal int _numInStreams; - internal int _numOutStreams; - } + internal CMethodId _methodId; + internal byte[] _props; + internal int _numInStreams; + internal int _numOutStreams; } diff --git a/src/SharpCompress/Common/SevenZip/CFileItem.cs b/src/SharpCompress/Common/SevenZip/CFileItem.cs index a97d2c9b..f83019fe 100644 --- a/src/SharpCompress/Common/SevenZip/CFileItem.cs +++ b/src/SharpCompress/Common/SevenZip/CFileItem.cs @@ -1,38 +1,37 @@ -#nullable disable +#nullable disable using System; -namespace SharpCompress.Common.SevenZip +namespace SharpCompress.Common.SevenZip; + +internal class CFileItem { - internal class CFileItem + public long Size { get; internal set; } + public uint? Attrib { get; internal set; } + public uint? Crc { get; internal set; } + public string Name { get; internal set; } + + public bool HasStream { get; internal set; } + public bool IsDir { get; internal set; } + + public bool CrcDefined => Crc != null; + + public bool AttribDefined => Attrib != null; + + public void SetAttrib(uint attrib) { - public long Size { get; internal set; } - public uint? Attrib { get; internal set; } - public uint? Crc { get; internal set; } - public string Name { get; internal set; } + Attrib = attrib; + } - public bool HasStream { get; internal set; } - public bool IsDir { get; internal set; } + public DateTime? CTime { get; internal set; } + public DateTime? ATime { get; internal set; } + public DateTime? MTime { get; internal set; } - public bool CrcDefined => Crc != null; + public long? StartPos { get; internal set; } + public bool IsAnti { get; internal set; } - public bool AttribDefined => Attrib != null; - - public void SetAttrib(uint attrib) - { - Attrib = attrib; - } - - public DateTime? CTime { get; internal set; } - public DateTime? ATime { get; internal set; } - public DateTime? MTime { get; internal set; } - - public long? StartPos { get; internal set; } - public bool IsAnti { get; internal set; } - - internal CFileItem() - { - HasStream = true; - } + internal CFileItem() + { + HasStream = true; } } diff --git a/src/SharpCompress/Common/SevenZip/CFolder.cs b/src/SharpCompress/Common/SevenZip/CFolder.cs index c15da80c..9d3516b1 100644 --- a/src/SharpCompress/Common/SevenZip/CFolder.cs +++ b/src/SharpCompress/Common/SevenZip/CFolder.cs @@ -1,188 +1,187 @@ -using System; +using System; using System.Collections.Generic; using SharpCompress.Compressors.LZMA; -namespace SharpCompress.Common.SevenZip +namespace SharpCompress.Common.SevenZip; + +internal class CFolder { - internal class CFolder + internal List _coders = new List(); + internal List _bindPairs = new List(); + internal List _packStreams = new List(); + internal int _firstPackStreamId; + internal List _unpackSizes = new List(); + internal uint? _unpackCrc; + + internal bool UnpackCrcDefined => _unpackCrc != null; + + public long GetUnpackSize() { - internal List _coders = new List(); - internal List _bindPairs = new List(); - internal List _packStreams = new List(); - internal int _firstPackStreamId; - internal List _unpackSizes = new List(); - internal uint? _unpackCrc; - - internal bool UnpackCrcDefined => _unpackCrc != null; - - public long GetUnpackSize() + if (_unpackSizes.Count == 0) { - if (_unpackSizes.Count == 0) - { - return 0; - } - - for (int i = _unpackSizes.Count - 1; i >= 0; i--) - { - if (FindBindPairForOutStream(i) < 0) - { - return _unpackSizes[i]; - } - } - - throw new InvalidOperationException(); + return 0; } - public int GetNumOutStreams() + for (var i = _unpackSizes.Count - 1; i >= 0; i--) { - int count = 0; - for (int i = 0; i < _coders.Count; i++) + if (FindBindPairForOutStream(i) < 0) { - count += _coders[i]._numOutStreams; + return _unpackSizes[i]; } - - return count; } - public int FindBindPairForInStream(int inStreamIndex) - { - for (int i = 0; i < _bindPairs.Count; i++) - { - if (_bindPairs[i]._inIndex == inStreamIndex) - { - return i; - } - } + throw new InvalidOperationException(); + } - return -1; + public int GetNumOutStreams() + { + var count = 0; + for (var i = 0; i < _coders.Count; i++) + { + count += _coders[i]._numOutStreams; } - public int FindBindPairForOutStream(int outStreamIndex) - { - for (int i = 0; i < _bindPairs.Count; i++) - { - if (_bindPairs[i]._outIndex == outStreamIndex) - { - return i; - } - } + return count; + } - return -1; + public int FindBindPairForInStream(int inStreamIndex) + { + for (var i = 0; i < _bindPairs.Count; i++) + { + if (_bindPairs[i]._inIndex == inStreamIndex) + { + return i; + } } - public int FindPackStreamArrayIndex(int inStreamIndex) - { - for (int i = 0; i < _packStreams.Count; i++) - { - if (_packStreams[i] == inStreamIndex) - { - return i; - } - } + return -1; + } - return -1; + public int FindBindPairForOutStream(int outStreamIndex) + { + for (var i = 0; i < _bindPairs.Count; i++) + { + if (_bindPairs[i]._outIndex == outStreamIndex) + { + return i; + } } - public bool IsEncrypted() - { - for (int i = _coders.Count - 1; i >= 0; i--) - { - if (_coders[i]._methodId == CMethodId.K_AES) - { - return true; - } - } + return -1; + } + public int FindPackStreamArrayIndex(int inStreamIndex) + { + for (var i = 0; i < _packStreams.Count; i++) + { + if (_packStreams[i] == inStreamIndex) + { + return i; + } + } + + return -1; + } + + public bool IsEncrypted() + { + for (var i = _coders.Count - 1; i >= 0; i--) + { + if (_coders[i]._methodId == CMethodId.K_AES) + { + return true; + } + } + + return false; + } + + public bool CheckStructure() + { + const int kNumCodersMax = 32; // don't change it + const int kMaskSize = 32; // it must be >= kNumCodersMax + const int kNumBindsMax = 32; + + if (_coders.Count > kNumCodersMax || _bindPairs.Count > kNumBindsMax) + { return false; } - public bool CheckStructure() { - const int kNumCodersMax = 32; // don't change it - const int kMaskSize = 32; // it must be >= kNumCodersMax - const int kNumBindsMax = 32; + var v = new BitVector(_bindPairs.Count + _packStreams.Count); - if (_coders.Count > kNumCodersMax || _bindPairs.Count > kNumBindsMax) + for (var i = 0; i < _bindPairs.Count; i++) { - return false; - } - - { - var v = new BitVector(_bindPairs.Count + _packStreams.Count); - - for (int i = 0; i < _bindPairs.Count; i++) - { - if (v.GetAndSet(_bindPairs[i]._inIndex)) - { - return false; - } - } - - for (int i = 0; i < _packStreams.Count; i++) - { - if (v.GetAndSet(_packStreams[i])) - { - return false; - } - } - } - - { - var v = new BitVector(_unpackSizes.Count); - for (int i = 0; i < _bindPairs.Count; i++) - { - if (v.GetAndSet(_bindPairs[i]._outIndex)) - { - return false; - } - } - } - - uint[] mask = new uint[kMaskSize]; - - { - List inStreamToCoder = new List(); - List outStreamToCoder = new List(); - for (int i = 0; i < _coders.Count; i++) - { - CCoderInfo coder = _coders[i]; - for (int j = 0; j < coder._numInStreams; j++) - { - inStreamToCoder.Add(i); - } - for (int j = 0; j < coder._numOutStreams; j++) - { - outStreamToCoder.Add(i); - } - } - - for (int i = 0; i < _bindPairs.Count; i++) - { - CBindPair bp = _bindPairs[i]; - mask[inStreamToCoder[bp._inIndex]] |= (1u << outStreamToCoder[bp._outIndex]); - } - } - - for (int i = 0; i < kMaskSize; i++) - { - for (int j = 0; j < kMaskSize; j++) - { - if (((1u << j) & mask[i]) != 0) - { - mask[i] |= mask[j]; - } - } - } - - for (int i = 0; i < kMaskSize; i++) - { - if (((1u << i) & mask[i]) != 0) + if (v.GetAndSet(_bindPairs[i]._inIndex)) { return false; } } - return true; + for (var i = 0; i < _packStreams.Count; i++) + { + if (v.GetAndSet(_packStreams[i])) + { + return false; + } + } } + + { + var v = new BitVector(_unpackSizes.Count); + for (var i = 0; i < _bindPairs.Count; i++) + { + if (v.GetAndSet(_bindPairs[i]._outIndex)) + { + return false; + } + } + } + + var mask = new uint[kMaskSize]; + + { + var inStreamToCoder = new List(); + var outStreamToCoder = new List(); + for (var i = 0; i < _coders.Count; i++) + { + var coder = _coders[i]; + for (var j = 0; j < coder._numInStreams; j++) + { + inStreamToCoder.Add(i); + } + for (var j = 0; j < coder._numOutStreams; j++) + { + outStreamToCoder.Add(i); + } + } + + for (var i = 0; i < _bindPairs.Count; i++) + { + var bp = _bindPairs[i]; + mask[inStreamToCoder[bp._inIndex]] |= (1u << outStreamToCoder[bp._outIndex]); + } + } + + for (var i = 0; i < kMaskSize; i++) + { + for (var j = 0; j < kMaskSize; j++) + { + if (((1u << j) & mask[i]) != 0) + { + mask[i] |= mask[j]; + } + } + } + + for (var i = 0; i < kMaskSize; i++) + { + if (((1u << i) & mask[i]) != 0) + { + return false; + } + } + + return true; } } diff --git a/src/SharpCompress/Common/SevenZip/CMethodId.cs b/src/SharpCompress/Common/SevenZip/CMethodId.cs index 871989e4..33a331c9 100644 --- a/src/SharpCompress/Common/SevenZip/CMethodId.cs +++ b/src/SharpCompress/Common/SevenZip/CMethodId.cs @@ -1,57 +1,56 @@ -namespace SharpCompress.Common.SevenZip +namespace SharpCompress.Common.SevenZip; + +internal readonly struct CMethodId { - internal readonly struct CMethodId + public const ulong K_COPY_ID = 0; + public const ulong K_LZMA_ID = 0x030101; + 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 readonly ulong _id; + + public CMethodId(ulong id) { - public const ulong K_COPY_ID = 0; - public const ulong K_LZMA_ID = 0x030101; - public const ulong K_LZMA2_ID = 0x21; - public const ulong K_AES_ID = 0x06F10701; + _id = id; + } - 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 override int GetHashCode() + { + return _id.GetHashCode(); + } - public readonly ulong _id; + public override bool Equals(object? obj) + { + return obj is CMethodId other && Equals(other); + } - public CMethodId(ulong id) + public bool Equals(CMethodId other) + { + return _id == other._id; + } + + public static bool operator ==(CMethodId left, CMethodId right) + { + return left._id == right._id; + } + + public static bool operator !=(CMethodId left, CMethodId right) + { + return left._id != right._id; + } + + public int GetLength() + { + var bytes = 0; + for (var value = _id; value != 0; value >>= 8) { - _id = id; - } - - public override int GetHashCode() - { - return _id.GetHashCode(); - } - - public override bool Equals(object? obj) - { - return obj is CMethodId other && Equals(other); - } - - public bool Equals(CMethodId other) - { - return _id == other._id; - } - - public static bool operator ==(CMethodId left, CMethodId right) - { - return left._id == right._id; - } - - public static bool operator !=(CMethodId left, CMethodId right) - { - return left._id != right._id; - } - - public int GetLength() - { - int bytes = 0; - for (ulong value = _id; value != 0; value >>= 8) - { - bytes++; - } - return bytes; + bytes++; } + return bytes; } } diff --git a/src/SharpCompress/Common/SevenZip/CStreamSwitch.cs b/src/SharpCompress/Common/SevenZip/CStreamSwitch.cs index 706bfc55..9238a5a1 100644 --- a/src/SharpCompress/Common/SevenZip/CStreamSwitch.cs +++ b/src/SharpCompress/Common/SevenZip/CStreamSwitch.cs @@ -1,69 +1,68 @@ -using System; +using System; using System.Collections.Generic; using SharpCompress.Compressors.LZMA; -namespace SharpCompress.Common.SevenZip +namespace SharpCompress.Common.SevenZip; + +internal struct CStreamSwitch : IDisposable { - internal struct CStreamSwitch : IDisposable + private ArchiveReader _archive; + private bool _needRemove; + private bool _active; + + public void Dispose() { - private ArchiveReader _archive; - private bool _needRemove; - private bool _active; - - public void Dispose() + if (_active) { - if (_active) - { - _active = false; + _active = false; #if DEBUG - Log.WriteLine("[end of switch]"); + Log.WriteLine("[end of switch]"); #endif - } - - if (_needRemove) - { - _needRemove = false; - _archive.DeleteByteStream(); - } } - public void Set(ArchiveReader archive, byte[] dataVector) + if (_needRemove) { - Dispose(); + _needRemove = false; + _archive.DeleteByteStream(); + } + } + + public void Set(ArchiveReader archive, byte[] dataVector) + { + Dispose(); + _archive = archive; + _archive.AddByteStream(dataVector, 0, dataVector.Length); + _needRemove = true; + _active = true; + } + + public void Set(ArchiveReader archive, List dataVector) + { + Dispose(); + _active = true; + + var external = archive.ReadByte(); + if (external != 0) + { + var dataIndex = archive.ReadNum(); + if (dataIndex < 0 || dataIndex >= dataVector.Count) + { + throw new InvalidOperationException(); + } + +#if DEBUG + Log.WriteLine("[switch to stream {0}]", dataIndex); +#endif _archive = archive; - _archive.AddByteStream(dataVector, 0, dataVector.Length); + _archive.AddByteStream(dataVector[dataIndex], 0, dataVector[dataIndex].Length); _needRemove = true; _active = true; } - - public void Set(ArchiveReader archive, List dataVector) + else { - Dispose(); - _active = true; - - byte external = archive.ReadByte(); - if (external != 0) - { - int dataIndex = archive.ReadNum(); - if (dataIndex < 0 || dataIndex >= dataVector.Count) - { - throw new InvalidOperationException(); - } - #if DEBUG - Log.WriteLine("[switch to stream {0}]", dataIndex); + Log.WriteLine("[inline data]"); #endif - _archive = archive; - _archive.AddByteStream(dataVector[dataIndex], 0, dataVector[dataIndex].Length); - _needRemove = true; - _active = true; - } - else - { -#if DEBUG - Log.WriteLine("[inline data]"); -#endif - } } } } diff --git a/src/SharpCompress/Common/SevenZip/DataReader.cs b/src/SharpCompress/Common/SevenZip/DataReader.cs index ad20a491..48e9dabc 100644 --- a/src/SharpCompress/Common/SevenZip/DataReader.cs +++ b/src/SharpCompress/Common/SevenZip/DataReader.cs @@ -1,186 +1,185 @@ -using System; +using System; using System.IO; using System.Text; using SharpCompress.Compressors.LZMA; -namespace SharpCompress.Common.SevenZip +namespace SharpCompress.Common.SevenZip; + +internal class DataReader { - internal class DataReader + #region Static Methods + + public static uint Get32(byte[] buffer, int offset) { - #region Static Methods - - public static uint Get32(byte[] buffer, int offset) - { - return buffer[offset] - + ((uint)buffer[offset + 1] << 8) - + ((uint)buffer[offset + 2] << 16) - + ((uint)buffer[offset + 3] << 24); - } - - public static ulong Get64(byte[] buffer, int offset) - { - return buffer[offset] - + ((ulong)buffer[offset + 1] << 8) - + ((ulong)buffer[offset + 2] << 16) - + ((ulong)buffer[offset + 3] << 24) - + ((ulong)buffer[offset + 4] << 32) - + ((ulong)buffer[offset + 5] << 40) - + ((ulong)buffer[offset + 6] << 48) - + ((ulong)buffer[offset + 7] << 56); - } - - #endregion - - #region Variables - - private readonly byte[] _buffer; - private readonly int _ending; - - #endregion - - #region Public Methods - - public DataReader(byte[] buffer, int offset, int length) - { - _buffer = buffer; - Offset = offset; - _ending = offset + length; - } - - public int Offset { get; private set; } - - public Byte ReadByte() - { - if (Offset >= _ending) - { - throw new EndOfStreamException(); - } - - return _buffer[Offset++]; - } - - public void ReadBytes(byte[] buffer, int offset, int length) - { - if (length > _ending - Offset) - { - throw new EndOfStreamException(); - } - - while (length-- > 0) - { - buffer[offset++] = _buffer[Offset++]; - } - } - - public void SkipData(long size) - { - if (size > _ending - Offset) - { - throw new EndOfStreamException(); - } - - Offset += (int)size; -#if DEBUG - Log.WriteLine("SkipData {0}", size); -#endif - } - - public void SkipData() - { - SkipData(checked((long)ReadNumber())); - } - - public ulong ReadNumber() - { - if (Offset >= _ending) - { - throw new EndOfStreamException(); - } - - byte firstByte = _buffer[Offset++]; - byte mask = 0x80; - ulong value = 0; - - for (int i = 0; i < 8; i++) - { - if ((firstByte & mask) == 0) - { - ulong highPart = firstByte & (mask - 1u); - value += highPart << (i * 8); - return value; - } - - if (Offset >= _ending) - { - throw new EndOfStreamException(); - } - - value |= (ulong)_buffer[Offset++] << (8 * i); - mask >>= 1; - } - - return value; - } - - public int ReadNum() - { - ulong value = ReadNumber(); - if (value > Int32.MaxValue) - { - throw new NotSupportedException(); - } - - return (int)value; - } - - public uint ReadUInt32() - { - if (Offset + 4 > _ending) - { - throw new EndOfStreamException(); - } - - uint res = Get32(_buffer, Offset); - Offset += 4; - return res; - } - - public ulong ReadUInt64() - { - if (Offset + 8 > _ending) - { - throw new EndOfStreamException(); - } - - ulong res = Get64(_buffer, Offset); - Offset += 8; - return res; - } - - public string ReadString() - { - int ending = Offset; - - for (; ; ) - { - if (ending + 2 > _ending) - { - throw new EndOfStreamException(); - } - - if (_buffer[ending] == 0 && _buffer[ending + 1] == 0) - { - break; - } - - ending += 2; - } - - string str = Encoding.Unicode.GetString(_buffer, Offset, ending - Offset); - Offset = ending + 2; - return str; - } - - #endregion + return buffer[offset] + + ((uint)buffer[offset + 1] << 8) + + ((uint)buffer[offset + 2] << 16) + + ((uint)buffer[offset + 3] << 24); } + + public static ulong Get64(byte[] buffer, int offset) + { + return buffer[offset] + + ((ulong)buffer[offset + 1] << 8) + + ((ulong)buffer[offset + 2] << 16) + + ((ulong)buffer[offset + 3] << 24) + + ((ulong)buffer[offset + 4] << 32) + + ((ulong)buffer[offset + 5] << 40) + + ((ulong)buffer[offset + 6] << 48) + + ((ulong)buffer[offset + 7] << 56); + } + + #endregion + + #region Variables + + private readonly byte[] _buffer; + private readonly int _ending; + + #endregion + + #region Public Methods + + public DataReader(byte[] buffer, int offset, int length) + { + _buffer = buffer; + Offset = offset; + _ending = offset + length; + } + + public int Offset { get; private set; } + + public byte ReadByte() + { + if (Offset >= _ending) + { + throw new EndOfStreamException(); + } + + return _buffer[Offset++]; + } + + public void ReadBytes(byte[] buffer, int offset, int length) + { + if (length > _ending - Offset) + { + throw new EndOfStreamException(); + } + + while (length-- > 0) + { + buffer[offset++] = _buffer[Offset++]; + } + } + + public void SkipData(long size) + { + if (size > _ending - Offset) + { + throw new EndOfStreamException(); + } + + Offset += (int)size; +#if DEBUG + Log.WriteLine("SkipData {0}", size); +#endif + } + + public void SkipData() + { + SkipData(checked((long)ReadNumber())); + } + + public ulong ReadNumber() + { + if (Offset >= _ending) + { + throw new EndOfStreamException(); + } + + var firstByte = _buffer[Offset++]; + byte mask = 0x80; + ulong value = 0; + + for (var i = 0; i < 8; i++) + { + if ((firstByte & mask) == 0) + { + ulong highPart = firstByte & (mask - 1u); + value += highPart << (i * 8); + return value; + } + + if (Offset >= _ending) + { + throw new EndOfStreamException(); + } + + value |= (ulong)_buffer[Offset++] << (8 * i); + mask >>= 1; + } + + return value; + } + + public int ReadNum() + { + var value = ReadNumber(); + if (value > int.MaxValue) + { + throw new NotSupportedException(); + } + + return (int)value; + } + + public uint ReadUInt32() + { + if (Offset + 4 > _ending) + { + throw new EndOfStreamException(); + } + + var res = Get32(_buffer, Offset); + Offset += 4; + return res; + } + + public ulong ReadUInt64() + { + if (Offset + 8 > _ending) + { + throw new EndOfStreamException(); + } + + var res = Get64(_buffer, Offset); + Offset += 8; + return res; + } + + public string ReadString() + { + var ending = Offset; + + for (; ; ) + { + if (ending + 2 > _ending) + { + throw new EndOfStreamException(); + } + + if (_buffer[ending] == 0 && _buffer[ending + 1] == 0) + { + break; + } + + ending += 2; + } + + var str = Encoding.Unicode.GetString(_buffer, Offset, ending - Offset); + Offset = ending + 2; + return str; + } + + #endregion } diff --git a/src/SharpCompress/Common/SevenZip/SevenZipEntry.cs b/src/SharpCompress/Common/SevenZip/SevenZipEntry.cs index 7be12a96..3e806681 100644 --- a/src/SharpCompress/Common/SevenZip/SevenZipEntry.cs +++ b/src/SharpCompress/Common/SevenZip/SevenZipEntry.cs @@ -1,46 +1,45 @@ -using System; +using System; using System.Collections.Generic; -namespace SharpCompress.Common.SevenZip +namespace SharpCompress.Common.SevenZip; + +public class SevenZipEntry : Entry { - public class SevenZipEntry : Entry + internal SevenZipEntry(SevenZipFilePart filePart) { - internal SevenZipEntry(SevenZipFilePart filePart) - { - FilePart = filePart; - } - - internal SevenZipFilePart FilePart { get; } - - public override CompressionType CompressionType => FilePart.CompressionType; - - public override long Crc => FilePart.Header.Crc ?? 0; - - public override string Key => FilePart.Header.Name; - - public override string? LinkTarget => null; - - public override long CompressedSize => 0; - - public override long Size => FilePart.Header.Size; - - public override DateTime? LastModifiedTime => FilePart.Header.MTime; - - public override DateTime? CreatedTime => null; - - public override DateTime? LastAccessedTime => null; - - public override DateTime? ArchivedTime => null; - - public override bool IsEncrypted => FilePart.IsEncrypted; - - public override bool IsDirectory => FilePart.Header.IsDir; - - public override bool IsSplitAfter => false; - - public override int? Attrib => - FilePart.Header.Attrib.HasValue ? (int?)FilePart.Header.Attrib.Value : null; - - internal override IEnumerable Parts => FilePart.AsEnumerable(); + FilePart = filePart; } + + internal SevenZipFilePart FilePart { get; } + + public override CompressionType CompressionType => FilePart.CompressionType; + + public override long Crc => FilePart.Header.Crc ?? 0; + + public override string Key => FilePart.Header.Name; + + public override string? LinkTarget => null; + + public override long CompressedSize => 0; + + public override long Size => FilePart.Header.Size; + + public override DateTime? LastModifiedTime => FilePart.Header.MTime; + + public override DateTime? CreatedTime => null; + + public override DateTime? LastAccessedTime => null; + + public override DateTime? ArchivedTime => null; + + public override bool IsEncrypted => FilePart.IsEncrypted; + + public override bool IsDirectory => FilePart.Header.IsDir; + + public override bool IsSplitAfter => false; + + public override int? Attrib => + FilePart.Header.Attrib.HasValue ? (int?)FilePart.Header.Attrib.Value : null; + + internal override IEnumerable Parts => FilePart.AsEnumerable(); } diff --git a/src/SharpCompress/Common/SevenZip/SevenZipFilePart.cs b/src/SharpCompress/Common/SevenZip/SevenZipFilePart.cs index e6927712..234d4a1d 100644 --- a/src/SharpCompress/Common/SevenZip/SevenZipFilePart.cs +++ b/src/SharpCompress/Common/SevenZip/SevenZipFilePart.cs @@ -3,117 +3,107 @@ using System.IO; using System.Linq; using SharpCompress.IO; -namespace SharpCompress.Common.SevenZip +namespace SharpCompress.Common.SevenZip; + +internal class SevenZipFilePart : FilePart { - internal class SevenZipFilePart : FilePart + private CompressionType? _type; + private readonly Stream _stream; + private readonly ArchiveDatabase _database; + + internal SevenZipFilePart( + Stream stream, + ArchiveDatabase database, + int index, + CFileItem fileEntry, + ArchiveEncoding archiveEncoding + ) : base(archiveEncoding) { - private CompressionType? _type; - private readonly Stream _stream; - private readonly ArchiveDatabase _database; - - internal SevenZipFilePart( - Stream stream, - ArchiveDatabase database, - int index, - CFileItem fileEntry, - ArchiveEncoding archiveEncoding - ) : base(archiveEncoding) + _stream = stream; + _database = database; + Index = index; + Header = fileEntry; + if (Header.HasStream) { - _stream = stream; - _database = database; - Index = index; - Header = fileEntry; - if (Header.HasStream) - { - Folder = database._folders[database._fileIndexToFolderIndexMap[index]]; - } + Folder = database._folders[database._fileIndexToFolderIndexMap[index]]; } - - internal CFileItem Header { get; } - internal CFolder? Folder { get; } - - internal override string FilePartName => Header.Name; - - internal override Stream? GetRawStream() - { - return null; - } - - internal override Stream GetCompressedStream() - { - if (!Header.HasStream) - { - return null!; - } - var folderStream = _database.GetFolderStream( - _stream, - Folder!, - _database.PasswordProvider - ); - - int firstFileIndex = _database._folderStartFileIndex[ - _database._folders.IndexOf(Folder!) - ]; - int skipCount = Index - firstFileIndex; - long skipSize = 0; - for (int i = 0; i < skipCount; i++) - { - skipSize += _database._files[firstFileIndex + i].Size; - } - if (skipSize > 0) - { - folderStream.Skip(skipSize); - } - return new ReadOnlySubStream(folderStream, Header.Size); - } - - public CompressionType CompressionType - { - get - { - if (_type is null) - { - _type = GetCompression(); - } - return _type.Value; - } - } - - //copied from DecoderRegistry - private const uint K_COPY = 0x0; - private const uint K_DELTA = 3; - private const uint K_LZMA2 = 0x21; - private const uint K_LZMA = 0x030101; - private const uint K_PPMD = 0x030401; - private const uint K_BCJ = 0x03030103; - private const uint K_BCJ2 = 0x0303011B; - private const uint K_DEFLATE = 0x040108; - private const uint K_B_ZIP2 = 0x040202; - - internal CompressionType GetCompression() - { - 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(); - } - } - - internal bool IsEncrypted => - Folder!._coders.FindIndex(c => c._methodId._id == CMethodId.K_AES_ID) != -1; } + + internal CFileItem Header { get; } + internal CFolder? Folder { get; } + + internal override string FilePartName => Header.Name; + + internal override Stream? GetRawStream() + { + return null; + } + + internal override Stream GetCompressedStream() + { + if (!Header.HasStream) + { + return null!; + } + var folderStream = _database.GetFolderStream( + _stream, + Folder!, + _database.PasswordProvider + ); + + var firstFileIndex = _database._folderStartFileIndex[ + _database._folders.IndexOf(Folder!) + ]; + var skipCount = Index - firstFileIndex; + long skipSize = 0; + for (var i = 0; i < skipCount; i++) + { + skipSize += _database._files[firstFileIndex + i].Size; + } + if (skipSize > 0) + { + folderStream.Skip(skipSize); + } + return new ReadOnlySubStream(folderStream, Header.Size); + } + + public CompressionType CompressionType + { + get + { + _type ??= GetCompression(); + return _type.Value; + } + } + + private const uint K_LZMA2 = 0x21; + private const uint K_LZMA = 0x030101; + private const uint K_PPMD = 0x030401; + private const uint K_B_ZIP2 = 0x040202; + + internal CompressionType GetCompression() + { + 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(); + } + } + + internal bool IsEncrypted => + Folder!._coders.FindIndex(c => c._methodId._id == CMethodId.K_AES_ID) != -1; } diff --git a/src/SharpCompress/Common/SevenZip/SevenZipVolume.cs b/src/SharpCompress/Common/SevenZip/SevenZipVolume.cs index 19e7b2f0..e4b330af 100644 --- a/src/SharpCompress/Common/SevenZip/SevenZipVolume.cs +++ b/src/SharpCompress/Common/SevenZip/SevenZipVolume.cs @@ -1,11 +1,10 @@ using System.IO; using SharpCompress.Readers; -namespace SharpCompress.Common.SevenZip +namespace SharpCompress.Common.SevenZip; + +public class SevenZipVolume : Volume { - public class SevenZipVolume : Volume - { - public SevenZipVolume(Stream stream, ReaderOptions readerFactoryOptions, int index = 0) - : base(stream, readerFactoryOptions, index) { } - } + public SevenZipVolume(Stream stream, ReaderOptions readerFactoryOptions, int index = 0) + : base(stream, readerFactoryOptions, index) { } } diff --git a/src/SharpCompress/Common/Tar/Headers/EntryType.cs b/src/SharpCompress/Common/Tar/Headers/EntryType.cs index feeaa6cc..3e6877c7 100644 --- a/src/SharpCompress/Common/Tar/Headers/EntryType.cs +++ b/src/SharpCompress/Common/Tar/Headers/EntryType.cs @@ -1,19 +1,18 @@ -namespace SharpCompress.Common.Tar.Headers +namespace SharpCompress.Common.Tar.Headers; + +internal enum EntryType : byte { - internal enum EntryType : byte - { - File = 0, - OldFile = (byte)'0', - HardLink = (byte)'1', - SymLink = (byte)'2', - CharDevice = (byte)'3', - BlockDevice = (byte)'4', - Directory = (byte)'5', - Fifo = (byte)'6', - LongLink = (byte)'K', - LongName = (byte)'L', - SparseFile = (byte)'S', - VolumeHeader = (byte)'V', - GlobalExtendedHeader = (byte)'g' - } + File = 0, + OldFile = (byte)'0', + HardLink = (byte)'1', + SymLink = (byte)'2', + CharDevice = (byte)'3', + BlockDevice = (byte)'4', + Directory = (byte)'5', + Fifo = (byte)'6', + LongLink = (byte)'K', + LongName = (byte)'L', + SparseFile = (byte)'S', + VolumeHeader = (byte)'V', + GlobalExtendedHeader = (byte)'g' } diff --git a/src/SharpCompress/Common/Tar/Headers/TarHeader.cs b/src/SharpCompress/Common/Tar/Headers/TarHeader.cs index e9b38971..78c2e0d9 100644 --- a/src/SharpCompress/Common/Tar/Headers/TarHeader.cs +++ b/src/SharpCompress/Common/Tar/Headers/TarHeader.cs @@ -1,322 +1,323 @@ -#nullable disable +#nullable disable using System; using System.Buffers.Binary; using System.IO; using System.Text; -namespace SharpCompress.Common.Tar.Headers +namespace SharpCompress.Common.Tar.Headers; + +internal sealed class TarHeader { - internal sealed class TarHeader + internal static readonly DateTime EPOCH = new DateTime( + 1970, + 1, + 1, + 0, + 0, + 0, + DateTimeKind.Utc + ); + + public TarHeader(ArchiveEncoding archiveEncoding) { - internal static readonly DateTime EPOCH = new DateTime( - 1970, - 1, - 1, - 0, - 0, - 0, - DateTimeKind.Utc - ); + ArchiveEncoding = archiveEncoding; + } - public TarHeader(ArchiveEncoding archiveEncoding) + internal string Name { get; set; } + internal string LinkName { get; set; } + + internal long Mode { get; set; } + internal long UserId { get; set; } + internal long GroupId { get; set; } + internal long Size { get; set; } + internal DateTime LastModifiedTime { get; set; } + internal EntryType EntryType { get; set; } + internal Stream PackedStream { get; set; } + internal ArchiveEncoding ArchiveEncoding { get; } + + internal const int BLOCK_SIZE = 512; + + internal void Write(Stream output) + { + var buffer = new byte[BLOCK_SIZE]; + + WriteOctalBytes(511, buffer, 100, 8); // file mode + WriteOctalBytes(0, buffer, 108, 8); // owner ID + WriteOctalBytes(0, buffer, 116, 8); // group ID + + //ArchiveEncoding.UTF8.GetBytes("magic").CopyTo(buffer, 257); + var nameByteCount = ArchiveEncoding.GetEncoding().GetByteCount(Name); + if (nameByteCount > 100) { - ArchiveEncoding = archiveEncoding; + // Set mock filename and filetype to indicate the next block is the actual name of the file + WriteStringBytes("././@LongLink", buffer, 0, 100); + buffer[156] = (byte)EntryType.LongName; + WriteOctalBytes(nameByteCount + 1, buffer, 124, 12); + } + else + { + WriteStringBytes(ArchiveEncoding.Encode(Name), buffer, 100); + WriteOctalBytes(Size, buffer, 124, 12); + var time = (long)(LastModifiedTime.ToUniversalTime() - EPOCH).TotalSeconds; + WriteOctalBytes(time, buffer, 136, 12); + buffer[156] = (byte)EntryType; + + if (Size >= 0x1FFFFFFFF) + { + Span bytes12 = stackalloc byte[12]; + BinaryPrimitives.WriteInt64BigEndian(bytes12.Slice(4), Size); + bytes12[0] |= 0x80; + bytes12.CopyTo(buffer.AsSpan(124)); + } } - internal string Name { get; set; } - internal string LinkName { get; set; } + var crc = RecalculateChecksum(buffer); + WriteOctalBytes(crc, buffer, 148, 8); - internal long Mode { get; set; } - internal long UserId { get; set; } - internal long GroupId { get; set; } - internal long Size { get; set; } - internal DateTime LastModifiedTime { get; set; } - internal EntryType EntryType { get; set; } - internal Stream PackedStream { get; set; } - internal ArchiveEncoding ArchiveEncoding { get; } + output.Write(buffer, 0, buffer.Length); - internal const int BLOCK_SIZE = 512; - - internal void Write(Stream output) + if (nameByteCount > 100) { - byte[] buffer = new byte[BLOCK_SIZE]; + WriteLongFilenameHeader(output); + // update to short name lower than 100 - [max bytes of one character]. + // subtracting bytes is needed because preventing infinite loop(example code is here). + // + // var bytes = Encoding.UTF8.GetBytes(new string(0x3042, 100)); + // var truncated = Encoding.UTF8.GetBytes(Encoding.UTF8.GetString(bytes, 0, 100)); + // + // and then infinite recursion is occured in WriteLongFilenameHeader because truncated.Length is 102. + Name = ArchiveEncoding.Decode( + ArchiveEncoding.Encode(Name), + 0, + 100 - ArchiveEncoding.GetEncoding().GetMaxByteCount(1) + ); + Write(output); + } + } - WriteOctalBytes(511, buffer, 100, 8); // file mode - WriteOctalBytes(0, buffer, 108, 8); // owner ID - WriteOctalBytes(0, buffer, 116, 8); // group ID + private void WriteLongFilenameHeader(Stream output) + { + var nameBytes = ArchiveEncoding.Encode(Name); + output.Write(nameBytes, 0, nameBytes.Length); - //ArchiveEncoding.UTF8.GetBytes("magic").CopyTo(buffer, 257); - var nameByteCount = ArchiveEncoding.GetEncoding().GetByteCount(Name); - if (nameByteCount > 100) + // pad to multiple of BlockSize bytes, and make sure a terminating null is added + var numPaddingBytes = BLOCK_SIZE - (nameBytes.Length % BLOCK_SIZE); + if (numPaddingBytes == 0) + { + numPaddingBytes = BLOCK_SIZE; + } + output.Write(stackalloc byte[numPaddingBytes]); + } + + internal bool Read(BinaryReader reader) + { + var buffer = ReadBlock(reader); + if (buffer.Length == 0) + { + return false; + } + + // for symlinks, additionally read the linkname + if (ReadEntryType(buffer) == EntryType.SymLink) + { + 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); + Size = ReadSize(buffer); + + Mode = ReadAsciiInt64Base8(buffer, 100, 7); + 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(); + + Magic = ArchiveEncoding.Decode(buffer, 257, 6).TrimNulls(); + + if (!string.IsNullOrEmpty(Magic) && "ustar".Equals(Magic)) + { + var namePrefix = ArchiveEncoding.Decode(buffer, 345, 157); + namePrefix = namePrefix.TrimNulls(); + if (!string.IsNullOrEmpty(namePrefix)) { - // Set mock filename and filetype to indicate the next block is the actual name of the file - WriteStringBytes("././@LongLink", buffer, 0, 100); - buffer[156] = (byte)EntryType.LongName; - WriteOctalBytes(nameByteCount + 1, buffer, 124, 12); + Name = namePrefix + "/" + Name; + } + } + if (EntryType != EntryType.LongName && Name.Length == 0) + { + return false; + } + return true; + } + + private string ReadLongName(BinaryReader reader, byte[] buffer) + { + var size = ReadSize(buffer); + var nameLength = (int)size; + var nameBytes = reader.ReadBytes(nameLength); + var remainingBytesToRead = BLOCK_SIZE - (nameLength % BLOCK_SIZE); + + // Read the rest of the block and discard the data + if (remainingBytesToRead < BLOCK_SIZE) + { + reader.ReadBytes(remainingBytesToRead); + } + return ArchiveEncoding.Decode(nameBytes, 0, nameBytes.Length).TrimNulls(); + } + + private static EntryType ReadEntryType(byte[] buffer) + { + return (EntryType)buffer[156]; + } + + private long ReadSize(byte[] buffer) + { + if ((buffer[124] & 0x80) == 0x80) // if size in binary + { + return BinaryPrimitives.ReadInt64BigEndian(buffer.AsSpan(0x80)); + } + + return ReadAsciiInt64Base8(buffer, 124, 11); + } + + private static byte[] ReadBlock(BinaryReader reader) + { + var buffer = reader.ReadBytes(BLOCK_SIZE); + + if (buffer.Length != 0 && buffer.Length < BLOCK_SIZE) + { + throw new InvalidOperationException("Buffer is invalid size"); + } + return buffer; + } + + private static void WriteStringBytes(ReadOnlySpan name, Span buffer, int length) + { + name.CopyTo(buffer); + var i = Math.Min(length, name.Length); + buffer.Slice(i, length - i).Clear(); + } + + private static void WriteStringBytes(string name, byte[] buffer, int offset, int length) + { + int i; + + for (i = 0; i < length && i < name.Length; ++i) + { + buffer[offset + i] = (byte)name[i]; + } + + for (; i < length; ++i) + { + buffer[offset + i] = 0; + } + } + + private static void WriteOctalBytes(long value, byte[] buffer, int offset, int length) + { + var val = Convert.ToString(value, 8); + var shift = length - val.Length - 1; + for (var i = 0; i < shift; i++) + { + buffer[offset + i] = (byte)' '; + } + for (var i = 0; i < val.Length; i++) + { + buffer[offset + i + shift] = (byte)val[i]; + } + } + + private static int ReadAsciiInt32Base8(byte[] buffer, int offset, int count) + { + var s = Encoding.UTF8.GetString(buffer, offset, count).TrimNulls(); + if (string.IsNullOrEmpty(s)) + { + return 0; + } + return Convert.ToInt32(s, 8); + } + + private static long ReadAsciiInt64Base8(byte[] buffer, int offset, int count) + { + 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(); + if (string.IsNullOrEmpty(s)) + { + return 0; + } + return Convert.ToInt64(s); + } + + private static readonly byte[] eightSpaces = + { + (byte)' ', + (byte)' ', + (byte)' ', + (byte)' ', + (byte)' ', + (byte)' ', + (byte)' ', + (byte)' ' + }; + + internal static int RecalculateChecksum(byte[] buf) + { + // Set default value for checksum. That is 8 spaces. + eightSpaces.CopyTo(buf, 148); + + // Calculate checksum + var headerChecksum = 0; + foreach (var b in buf) + { + headerChecksum += b; + } + return headerChecksum; + } + + internal static int RecalculateAltChecksum(byte[] buf) + { + eightSpaces.CopyTo(buf, 148); + var headerChecksum = 0; + foreach (var b in buf) + { + if ((b & 0x80) == 0x80) + { + headerChecksum -= b ^ 0x80; } else - { - WriteStringBytes(ArchiveEncoding.Encode(Name), buffer, 100); - WriteOctalBytes(Size, buffer, 124, 12); - var time = (long)(LastModifiedTime.ToUniversalTime() - EPOCH).TotalSeconds; - WriteOctalBytes(time, buffer, 136, 12); - buffer[156] = (byte)EntryType; - - if (Size >= 0x1FFFFFFFF) - { - Span bytes12 = stackalloc byte[12]; - BinaryPrimitives.WriteInt64BigEndian(bytes12.Slice(4), Size); - bytes12[0] |= 0x80; - bytes12.CopyTo(buffer.AsSpan(124)); - } - } - - int crc = RecalculateChecksum(buffer); - WriteOctalBytes(crc, buffer, 148, 8); - - output.Write(buffer, 0, buffer.Length); - - if (nameByteCount > 100) - { - WriteLongFilenameHeader(output); - // update to short name lower than 100 - [max bytes of one character]. - // subtracting bytes is needed because preventing infinite loop(example code is here). - // - // var bytes = Encoding.UTF8.GetBytes(new string(0x3042, 100)); - // var truncated = Encoding.UTF8.GetBytes(Encoding.UTF8.GetString(bytes, 0, 100)); - // - // and then infinite recursion is occured in WriteLongFilenameHeader because truncated.Length is 102. - Name = ArchiveEncoding.Decode( - ArchiveEncoding.Encode(Name), - 0, - 100 - ArchiveEncoding.GetEncoding().GetMaxByteCount(1) - ); - Write(output); - } - } - - private void WriteLongFilenameHeader(Stream output) - { - byte[] nameBytes = ArchiveEncoding.Encode(Name); - output.Write(nameBytes, 0, nameBytes.Length); - - // pad to multiple of BlockSize bytes, and make sure a terminating null is added - int numPaddingBytes = BLOCK_SIZE - (nameBytes.Length % BLOCK_SIZE); - if (numPaddingBytes == 0) - { - numPaddingBytes = BLOCK_SIZE; - } - output.Write(stackalloc byte[numPaddingBytes]); - } - - internal bool Read(BinaryReader reader) - { - var buffer = ReadBlock(reader); - if (buffer.Length == 0) - { - return false; - } - - // for symlinks, additionally read the linkname - if (ReadEntryType(buffer) == EntryType.SymLink) - { - 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); - Size = ReadSize(buffer); - - Mode = ReadAsciiInt64Base8(buffer, 100, 7); - if (EntryType == EntryType.Directory) - Mode |= 0b1_000_000_000; - - UserId = ReadAsciiInt64Base8(buffer, 108, 7); - GroupId = ReadAsciiInt64Base8(buffer, 116, 7); - long unixTimeStamp = ReadAsciiInt64Base8(buffer, 136, 11); - LastModifiedTime = EPOCH.AddSeconds(unixTimeStamp).ToLocalTime(); - - Magic = ArchiveEncoding.Decode(buffer, 257, 6).TrimNulls(); - - if (!string.IsNullOrEmpty(Magic) && "ustar".Equals(Magic)) - { - string namePrefix = ArchiveEncoding.Decode(buffer, 345, 157); - namePrefix = namePrefix.TrimNulls(); - if (!string.IsNullOrEmpty(namePrefix)) - { - Name = namePrefix + "/" + Name; - } - } - if (EntryType != EntryType.LongName && Name.Length == 0) - { - return false; - } - return true; - } - - private string ReadLongName(BinaryReader reader, byte[] buffer) - { - var size = ReadSize(buffer); - var nameLength = (int)size; - var nameBytes = reader.ReadBytes(nameLength); - var remainingBytesToRead = BLOCK_SIZE - (nameLength % BLOCK_SIZE); - - // Read the rest of the block and discard the data - if (remainingBytesToRead < BLOCK_SIZE) - { - reader.ReadBytes(remainingBytesToRead); - } - return ArchiveEncoding.Decode(nameBytes, 0, nameBytes.Length).TrimNulls(); - } - - private static EntryType ReadEntryType(byte[] buffer) - { - return (EntryType)buffer[156]; - } - - private long ReadSize(byte[] buffer) - { - if ((buffer[124] & 0x80) == 0x80) // if size in binary - { - return BinaryPrimitives.ReadInt64BigEndian(buffer.AsSpan(0x80)); - } - - return ReadAsciiInt64Base8(buffer, 124, 11); - } - - private static byte[] ReadBlock(BinaryReader reader) - { - byte[] buffer = reader.ReadBytes(BLOCK_SIZE); - - if (buffer.Length != 0 && buffer.Length < BLOCK_SIZE) - { - throw new InvalidOperationException("Buffer is invalid size"); - } - return buffer; - } - - private static void WriteStringBytes(ReadOnlySpan name, Span buffer, int length) - { - name.CopyTo(buffer); - int i = Math.Min(length, name.Length); - buffer.Slice(i, length - i).Clear(); - } - - private static void WriteStringBytes(string name, byte[] buffer, int offset, int length) - { - int i; - - for (i = 0; i < length && i < name.Length; ++i) - { - buffer[offset + i] = (byte)name[i]; - } - - for (; i < length; ++i) - { - buffer[offset + i] = 0; - } - } - - private static void WriteOctalBytes(long value, byte[] buffer, int offset, int length) - { - string val = Convert.ToString(value, 8); - int shift = length - val.Length - 1; - for (int i = 0; i < shift; i++) - { - buffer[offset + i] = (byte)' '; - } - for (int i = 0; i < val.Length; i++) - { - buffer[offset + i + shift] = (byte)val[i]; - } - } - - private static int ReadAsciiInt32Base8(byte[] buffer, int offset, int count) - { - string s = Encoding.UTF8.GetString(buffer, offset, count).TrimNulls(); - if (string.IsNullOrEmpty(s)) - { - return 0; - } - return Convert.ToInt32(s, 8); - } - - private static long ReadAsciiInt64Base8(byte[] buffer, int offset, int count) - { - string 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) - { - string s = Encoding.UTF8.GetString(buffer, offset, count).TrimNulls(); - if (string.IsNullOrEmpty(s)) - { - return 0; - } - return Convert.ToInt64(s); - } - - private static readonly byte[] eightSpaces = - { - (byte)' ', - (byte)' ', - (byte)' ', - (byte)' ', - (byte)' ', - (byte)' ', - (byte)' ', - (byte)' ' - }; - - internal static int RecalculateChecksum(byte[] buf) - { - // Set default value for checksum. That is 8 spaces. - eightSpaces.CopyTo(buf, 148); - - // Calculate checksum - int headerChecksum = 0; - foreach (byte b in buf) { headerChecksum += b; } - return headerChecksum; } - - internal static int RecalculateAltChecksum(byte[] buf) - { - eightSpaces.CopyTo(buf, 148); - int headerChecksum = 0; - foreach (byte b in buf) - { - if ((b & 0x80) == 0x80) - { - headerChecksum -= b ^ 0x80; - } - else - { - headerChecksum += b; - } - } - return headerChecksum; - } - - public long? DataStartPosition { get; set; } - - public string Magic { get; set; } + return headerChecksum; } + + public long? DataStartPosition { get; set; } + + public string Magic { get; set; } } diff --git a/src/SharpCompress/Common/Tar/TarEntry.cs b/src/SharpCompress/Common/Tar/TarEntry.cs index 59434661..7b5e4a05 100644 --- a/src/SharpCompress/Common/Tar/TarEntry.cs +++ b/src/SharpCompress/Common/Tar/TarEntry.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable using System; using System.Collections.Generic; @@ -6,71 +6,70 @@ using System.IO; using SharpCompress.Common.Tar.Headers; using SharpCompress.IO; -namespace SharpCompress.Common.Tar +namespace SharpCompress.Common.Tar; + +public class TarEntry : Entry { - public class TarEntry : Entry + private readonly TarFilePart _filePart; + + internal TarEntry(TarFilePart filePart, CompressionType type) { - private readonly TarFilePart _filePart; + _filePart = filePart; + CompressionType = type; + } - internal TarEntry(TarFilePart filePart, CompressionType type) + public override CompressionType CompressionType { get; } + + public override long Crc => 0; + + public override string Key => _filePart.Header.Name; + + public override string LinkTarget => _filePart.Header.LinkName; + + public override long CompressedSize => _filePart.Header.Size; + + public override long Size => _filePart.Header.Size; + + public override DateTime? LastModifiedTime => _filePart.Header.LastModifiedTime; + + public override DateTime? CreatedTime => null; + + public override DateTime? LastAccessedTime => null; + + public override DateTime? ArchivedTime => null; + + public override bool IsEncrypted => false; + + public override bool IsDirectory => _filePart.Header.EntryType == EntryType.Directory; + + public override bool IsSplitAfter => false; + + public long Mode => _filePart.Header.Mode; + + public long UserID => _filePart.Header.UserId; + + public long GroupId => _filePart.Header.GroupId; + + internal override IEnumerable Parts => _filePart.AsEnumerable(); + + internal static IEnumerable GetEntries( + StreamingMode mode, + Stream stream, + CompressionType compressionType, + ArchiveEncoding archiveEncoding + ) + { + foreach (var h in TarHeaderFactory.ReadHeader(mode, stream, archiveEncoding)) { - this._filePart = filePart; - CompressionType = type; - } - - public override CompressionType CompressionType { get; } - - public override long Crc => 0; - - public override string Key => _filePart.Header.Name; - - public override string LinkTarget => _filePart.Header.LinkName; - - public override long CompressedSize => _filePart.Header.Size; - - public override long Size => _filePart.Header.Size; - - public override DateTime? LastModifiedTime => _filePart.Header.LastModifiedTime; - - public override DateTime? CreatedTime => null; - - public override DateTime? LastAccessedTime => null; - - public override DateTime? ArchivedTime => null; - - public override bool IsEncrypted => false; - - public override bool IsDirectory => _filePart.Header.EntryType == EntryType.Directory; - - public override bool IsSplitAfter => false; - - public long Mode => _filePart.Header.Mode; - - public long UserID => _filePart.Header.UserId; - - public long GroupId => _filePart.Header.GroupId; - - internal override IEnumerable Parts => _filePart.AsEnumerable(); - - internal static IEnumerable GetEntries( - StreamingMode mode, - Stream stream, - CompressionType compressionType, - ArchiveEncoding archiveEncoding - ) - { - foreach (TarHeader h in TarHeaderFactory.ReadHeader(mode, stream, archiveEncoding)) + if (h != null) { - if (h != null) + if (mode == StreamingMode.Seekable) { - if (mode == StreamingMode.Seekable) - { - yield return new TarEntry(new TarFilePart(h, stream), compressionType); - } - else - { - yield return new TarEntry(new TarFilePart(h, null), compressionType); - } + yield return new TarEntry(new TarFilePart(h, stream), compressionType); + } + else + { + yield return new TarEntry(new TarFilePart(h, null), compressionType); } } } diff --git a/src/SharpCompress/Common/Tar/TarFilePart.cs b/src/SharpCompress/Common/Tar/TarFilePart.cs index f71a41a8..8fa6223f 100644 --- a/src/SharpCompress/Common/Tar/TarFilePart.cs +++ b/src/SharpCompress/Common/Tar/TarFilePart.cs @@ -1,36 +1,34 @@ -using System.IO; +using System.IO; using SharpCompress.Common.Tar.Headers; -using SharpCompress.IO; -namespace SharpCompress.Common.Tar +namespace SharpCompress.Common.Tar; + +internal sealed class TarFilePart : FilePart { - internal sealed class TarFilePart : FilePart + private readonly Stream _seekableStream; + + internal TarFilePart(TarHeader header, Stream seekableStream) : base(header.ArchiveEncoding) { - private readonly Stream _seekableStream; + _seekableStream = seekableStream; + Header = header; + } - internal TarFilePart(TarHeader header, Stream seekableStream) : base(header.ArchiveEncoding) + internal TarHeader Header { get; } + + internal override string FilePartName => Header.Name; + + internal override Stream GetCompressedStream() + { + if (_seekableStream != null) { - _seekableStream = seekableStream; - Header = header; + _seekableStream.Position = Header.DataStartPosition!.Value; + return new TarReadOnlySubStream(_seekableStream, Header.Size); } + return Header.PackedStream; + } - internal TarHeader Header { get; } - - internal override string FilePartName => Header.Name; - - internal override Stream GetCompressedStream() - { - if (_seekableStream != null) - { - _seekableStream.Position = Header.DataStartPosition!.Value; - return new TarReadOnlySubStream(_seekableStream, Header.Size); - } - return Header.PackedStream; - } - - internal override Stream? GetRawStream() - { - return null; - } + internal override Stream? GetRawStream() + { + return null; } } diff --git a/src/SharpCompress/Common/Tar/TarHeaderFactory.cs b/src/SharpCompress/Common/Tar/TarHeaderFactory.cs index 6a9e8327..0edb7463 100644 --- a/src/SharpCompress/Common/Tar/TarHeaderFactory.cs +++ b/src/SharpCompress/Common/Tar/TarHeaderFactory.cs @@ -1,69 +1,68 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.IO; using SharpCompress.Common.Tar.Headers; using SharpCompress.IO; -namespace SharpCompress.Common.Tar +namespace SharpCompress.Common.Tar; + +internal static class TarHeaderFactory { - internal static class TarHeaderFactory + internal static IEnumerable ReadHeader( + StreamingMode mode, + Stream stream, + ArchiveEncoding archiveEncoding + ) { - internal static IEnumerable ReadHeader( - StreamingMode mode, - Stream stream, - ArchiveEncoding archiveEncoding - ) + while (true) { - while (true) + TarHeader? header = null; + try { - TarHeader? header = null; - try + var reader = new BinaryReader(stream); + header = new TarHeader(archiveEncoding); + + if (!header.Read(reader)) { - BinaryReader reader = new BinaryReader(stream); - header = new TarHeader(archiveEncoding); + yield break; + } + switch (mode) + { + case StreamingMode.Seekable: - if (!header.Read(reader)) { - yield break; + header.DataStartPosition = reader.BaseStream.Position; + + //skip to nearest 512 + reader.BaseStream.Position += PadTo512(header.Size); } - switch (mode) + break; + case StreamingMode.Streaming: + { - case StreamingMode.Seekable: - - { - header.DataStartPosition = reader.BaseStream.Position; - - //skip to nearest 512 - reader.BaseStream.Position += PadTo512(header.Size); - } - break; - case StreamingMode.Streaming: - - { - header.PackedStream = new TarReadOnlySubStream(stream, header.Size); - } - break; - default: - { - throw new InvalidFormatException("Invalid StreamingMode"); - } + header.PackedStream = new TarReadOnlySubStream(stream, header.Size); + } + break; + default: + { + throw new InvalidFormatException("Invalid StreamingMode"); } } - catch - { - header = null; - } - yield return header; } - } - - private static long PadTo512(long size) - { - int zeros = (int)(size % 512); - if (zeros == 0) + catch { - return size; + header = null; } - return 512 - zeros + size; + yield return header; } } + + private static long PadTo512(long size) + { + var zeros = (int)(size % 512); + if (zeros == 0) + { + return size; + } + return 512 - zeros + size; + } } diff --git a/src/SharpCompress/Common/Tar/TarReadOnlySubStream.cs b/src/SharpCompress/Common/Tar/TarReadOnlySubStream.cs index bea2858f..2678ebee 100644 --- a/src/SharpCompress/Common/Tar/TarReadOnlySubStream.cs +++ b/src/SharpCompress/Common/Tar/TarReadOnlySubStream.cs @@ -1,4 +1,4 @@ -using SharpCompress.IO; +using SharpCompress.IO; using System; using System.IO; diff --git a/src/SharpCompress/Common/Tar/TarVolume.cs b/src/SharpCompress/Common/Tar/TarVolume.cs index 4b914920..da00886a 100644 --- a/src/SharpCompress/Common/Tar/TarVolume.cs +++ b/src/SharpCompress/Common/Tar/TarVolume.cs @@ -1,11 +1,10 @@ using System.IO; using SharpCompress.Readers; -namespace SharpCompress.Common.Tar +namespace SharpCompress.Common.Tar; + +public class TarVolume : Volume { - public class TarVolume : Volume - { - public TarVolume(Stream stream, ReaderOptions readerOptions, int index = 0) - : base(stream, readerOptions, index) { } - } + public TarVolume(Stream stream, ReaderOptions readerOptions, int index = 0) + : base(stream, readerOptions, index) { } } diff --git a/src/SharpCompress/Common/Volume.cs b/src/SharpCompress/Common/Volume.cs index ac716b67..1872e65d 100644 --- a/src/SharpCompress/Common/Volume.cs +++ b/src/SharpCompress/Common/Volume.cs @@ -3,57 +3,56 @@ using System.IO; using SharpCompress.IO; using SharpCompress.Readers; -namespace SharpCompress.Common +namespace SharpCompress.Common; + +public abstract class Volume : IVolume { - public abstract class Volume : IVolume + private readonly Stream _actualStream; + + internal Volume(Stream stream, ReaderOptions readerOptions, int index = 0) { - private readonly Stream _actualStream; - - internal Volume(Stream stream, ReaderOptions readerOptions, int index = 0) + Index = index; + ReaderOptions = readerOptions; + if (readerOptions.LeaveStreamOpen) { - Index = index; - ReaderOptions = readerOptions; - if (readerOptions.LeaveStreamOpen) - { - stream = NonDisposingStream.Create(stream); - } - _actualStream = stream; + stream = NonDisposingStream.Create(stream); } + _actualStream = stream; + } - internal Stream Stream => _actualStream; + internal Stream Stream => _actualStream; - protected ReaderOptions ReaderOptions { get; } + protected ReaderOptions ReaderOptions { get; } - /// - /// RarArchive is the first volume of a multi-part archive. - /// Only Rar 3.0 format and higher - /// - public virtual bool IsFirstVolume => true; + /// + /// RarArchive is the first volume of a multi-part archive. + /// Only Rar 3.0 format and higher + /// + public virtual bool IsFirstVolume => true; - public virtual int Index { get; internal set; } + public virtual int Index { get; internal set; } - public string FileName + public string FileName + { + get { return (_actualStream as FileStream)?.Name!; } + } + + /// + /// RarArchive is part of a multi-part archive. + /// + public virtual bool IsMultiVolume => true; + + protected virtual void Dispose(bool disposing) + { + if (disposing) { - get { return (_actualStream as FileStream)?.Name!; } - } - - /// - /// RarArchive is part of a multi-part archive. - /// - public virtual bool IsMultiVolume => true; - - protected virtual void Dispose(bool disposing) - { - if (disposing) - { - _actualStream.Dispose(); - } - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); + _actualStream.Dispose(); } } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } } diff --git a/src/SharpCompress/Common/Zip/Headers/DirectoryEndHeader.cs b/src/SharpCompress/Common/Zip/Headers/DirectoryEndHeader.cs index 42c8865c..943ae47c 100644 --- a/src/SharpCompress/Common/Zip/Headers/DirectoryEndHeader.cs +++ b/src/SharpCompress/Common/Zip/Headers/DirectoryEndHeader.cs @@ -1,42 +1,41 @@ -using System.IO; +using System.IO; -namespace SharpCompress.Common.Zip.Headers +namespace SharpCompress.Common.Zip.Headers; + +internal class DirectoryEndHeader : ZipHeader { - internal class DirectoryEndHeader : ZipHeader + public DirectoryEndHeader() : base(ZipHeaderType.DirectoryEnd) { } + + internal override void Read(BinaryReader reader) { - public DirectoryEndHeader() : base(ZipHeaderType.DirectoryEnd) { } - - internal override void Read(BinaryReader reader) - { - VolumeNumber = reader.ReadUInt16(); - FirstVolumeWithDirectory = reader.ReadUInt16(); - TotalNumberOfEntriesInDisk = reader.ReadUInt16(); - TotalNumberOfEntries = reader.ReadUInt16(); - DirectorySize = reader.ReadUInt32(); - DirectoryStartOffsetRelativeToDisk = reader.ReadUInt32(); - CommentLength = reader.ReadUInt16(); - Comment = reader.ReadBytes(CommentLength); - } - - public ushort VolumeNumber { get; private set; } - - public ushort FirstVolumeWithDirectory { get; private set; } - - public ushort TotalNumberOfEntriesInDisk { get; private set; } - - public uint DirectorySize { get; private set; } - - public uint DirectoryStartOffsetRelativeToDisk { get; private set; } - - public ushort CommentLength { get; private set; } - - public byte[]? Comment { get; private set; } - - public ushort TotalNumberOfEntries { get; private set; } - - public bool IsZip64 => - TotalNumberOfEntriesInDisk == ushort.MaxValue - || DirectorySize == uint.MaxValue - || DirectoryStartOffsetRelativeToDisk == uint.MaxValue; + VolumeNumber = reader.ReadUInt16(); + FirstVolumeWithDirectory = reader.ReadUInt16(); + TotalNumberOfEntriesInDisk = reader.ReadUInt16(); + TotalNumberOfEntries = reader.ReadUInt16(); + DirectorySize = reader.ReadUInt32(); + DirectoryStartOffsetRelativeToDisk = reader.ReadUInt32(); + CommentLength = reader.ReadUInt16(); + Comment = reader.ReadBytes(CommentLength); } + + public ushort VolumeNumber { get; private set; } + + public ushort FirstVolumeWithDirectory { get; private set; } + + public ushort TotalNumberOfEntriesInDisk { get; private set; } + + public uint DirectorySize { get; private set; } + + public uint DirectoryStartOffsetRelativeToDisk { get; private set; } + + public ushort CommentLength { get; private set; } + + public byte[]? Comment { get; private set; } + + public ushort TotalNumberOfEntries { get; private set; } + + public bool IsZip64 => + TotalNumberOfEntriesInDisk == ushort.MaxValue + || DirectorySize == uint.MaxValue + || DirectoryStartOffsetRelativeToDisk == uint.MaxValue; } diff --git a/src/SharpCompress/Common/Zip/Headers/DirectoryEntryHeader.cs b/src/SharpCompress/Common/Zip/Headers/DirectoryEntryHeader.cs index 0a28c602..dc566482 100644 --- a/src/SharpCompress/Common/Zip/Headers/DirectoryEntryHeader.cs +++ b/src/SharpCompress/Common/Zip/Headers/DirectoryEntryHeader.cs @@ -1,106 +1,105 @@ -using System.IO; +using System.IO; using System.Linq; -namespace SharpCompress.Common.Zip.Headers +namespace SharpCompress.Common.Zip.Headers; + +internal class DirectoryEntryHeader : ZipFileEntry { - internal class DirectoryEntryHeader : ZipFileEntry + public DirectoryEntryHeader(ArchiveEncoding archiveEncoding) + : base(ZipHeaderType.DirectoryEntry, archiveEncoding) { } + + internal override void Read(BinaryReader reader) { - public DirectoryEntryHeader(ArchiveEncoding archiveEncoding) - : base(ZipHeaderType.DirectoryEntry, archiveEncoding) { } + Version = reader.ReadUInt16(); + VersionNeededToExtract = reader.ReadUInt16(); + Flags = (HeaderFlags)reader.ReadUInt16(); + CompressionMethod = (ZipCompressionMethod)reader.ReadUInt16(); + LastModifiedTime = reader.ReadUInt16(); + LastModifiedDate = reader.ReadUInt16(); + Crc = reader.ReadUInt32(); + CompressedSize = reader.ReadUInt32(); + UncompressedSize = reader.ReadUInt32(); + var nameLength = reader.ReadUInt16(); + var extraLength = reader.ReadUInt16(); + var commentLength = reader.ReadUInt16(); + DiskNumberStart = reader.ReadUInt16(); + InternalFileAttributes = reader.ReadUInt16(); + ExternalFileAttributes = reader.ReadUInt32(); + RelativeOffsetOfEntryHeader = reader.ReadUInt32(); - internal override void Read(BinaryReader reader) + var name = reader.ReadBytes(nameLength); + var extra = reader.ReadBytes(extraLength); + var comment = reader.ReadBytes(commentLength); + + // According to .ZIP File Format Specification + // + // For example: https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT + // + // Bit 11: Language encoding flag (EFS). If this bit is set, + // the filename and comment fields for this file + // MUST be encoded using UTF-8. (see APPENDIX D) + + if (Flags.HasFlag(HeaderFlags.Efs)) { - Version = reader.ReadUInt16(); - VersionNeededToExtract = reader.ReadUInt16(); - Flags = (HeaderFlags)reader.ReadUInt16(); - CompressionMethod = (ZipCompressionMethod)reader.ReadUInt16(); - LastModifiedTime = reader.ReadUInt16(); - LastModifiedDate = reader.ReadUInt16(); - Crc = reader.ReadUInt32(); - CompressedSize = reader.ReadUInt32(); - UncompressedSize = reader.ReadUInt32(); - ushort nameLength = reader.ReadUInt16(); - ushort extraLength = reader.ReadUInt16(); - ushort commentLength = reader.ReadUInt16(); - DiskNumberStart = reader.ReadUInt16(); - InternalFileAttributes = reader.ReadUInt16(); - ExternalFileAttributes = reader.ReadUInt32(); - RelativeOffsetOfEntryHeader = reader.ReadUInt32(); - - byte[] name = reader.ReadBytes(nameLength); - byte[] extra = reader.ReadBytes(extraLength); - byte[] comment = reader.ReadBytes(commentLength); - - // According to .ZIP File Format Specification - // - // For example: https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT - // - // Bit 11: Language encoding flag (EFS). If this bit is set, - // the filename and comment fields for this file - // MUST be encoded using UTF-8. (see APPENDIX D) - - if (Flags.HasFlag(HeaderFlags.Efs)) - { - Name = ArchiveEncoding.DecodeUTF8(name); - Comment = ArchiveEncoding.DecodeUTF8(comment); - } - else - { - Name = ArchiveEncoding.Decode(name); - Comment = ArchiveEncoding.Decode(comment); - } - - LoadExtra(extra); - - var unicodePathExtra = Extra.FirstOrDefault( - u => u.Type == ExtraDataType.UnicodePathExtraField - ); - if (unicodePathExtra != null && ArchiveEncoding.Forced == null) - { - Name = ((ExtraUnicodePathExtraField)unicodePathExtra).UnicodeName; - } - - var zip64ExtraData = Extra - .OfType() - .FirstOrDefault(); - if (zip64ExtraData != null) - { - zip64ExtraData.Process( - UncompressedSize, - CompressedSize, - RelativeOffsetOfEntryHeader, - DiskNumberStart - ); - - if (CompressedSize == uint.MaxValue) - { - CompressedSize = zip64ExtraData.CompressedSize; - } - - if (UncompressedSize == uint.MaxValue) - { - UncompressedSize = zip64ExtraData.UncompressedSize; - } - - if (RelativeOffsetOfEntryHeader == uint.MaxValue) - { - RelativeOffsetOfEntryHeader = zip64ExtraData.RelativeOffsetOfEntryHeader; - } - } + Name = ArchiveEncoding.DecodeUTF8(name); + Comment = ArchiveEncoding.DecodeUTF8(comment); + } + else + { + Name = ArchiveEncoding.Decode(name); + Comment = ArchiveEncoding.Decode(comment); } - internal ushort Version { get; private set; } + LoadExtra(extra); - public ushort VersionNeededToExtract { get; set; } + var unicodePathExtra = Extra.FirstOrDefault( + u => u.Type == ExtraDataType.UnicodePathExtraField + ); + if (unicodePathExtra != null && ArchiveEncoding.Forced == null) + { + Name = ((ExtraUnicodePathExtraField)unicodePathExtra).UnicodeName; + } - public long RelativeOffsetOfEntryHeader { get; set; } + var zip64ExtraData = Extra + .OfType() + .FirstOrDefault(); + if (zip64ExtraData != null) + { + zip64ExtraData.Process( + UncompressedSize, + CompressedSize, + RelativeOffsetOfEntryHeader, + DiskNumberStart + ); - public uint ExternalFileAttributes { get; set; } + if (CompressedSize == uint.MaxValue) + { + CompressedSize = zip64ExtraData.CompressedSize; + } - public ushort InternalFileAttributes { get; set; } + if (UncompressedSize == uint.MaxValue) + { + UncompressedSize = zip64ExtraData.UncompressedSize; + } - public ushort DiskNumberStart { get; set; } - - public string? Comment { get; private set; } + if (RelativeOffsetOfEntryHeader == uint.MaxValue) + { + RelativeOffsetOfEntryHeader = zip64ExtraData.RelativeOffsetOfEntryHeader; + } + } } + + internal ushort Version { get; private set; } + + public ushort VersionNeededToExtract { get; set; } + + public long RelativeOffsetOfEntryHeader { get; set; } + + public uint ExternalFileAttributes { get; set; } + + public ushort InternalFileAttributes { get; set; } + + public ushort DiskNumberStart { get; set; } + + public string? Comment { get; private set; } } diff --git a/src/SharpCompress/Common/Zip/Headers/HeaderFlags.cs b/src/SharpCompress/Common/Zip/Headers/HeaderFlags.cs index 09cf7f29..5aef3394 100644 --- a/src/SharpCompress/Common/Zip/Headers/HeaderFlags.cs +++ b/src/SharpCompress/Common/Zip/Headers/HeaderFlags.cs @@ -1,18 +1,17 @@ -using System; +using System; -namespace SharpCompress.Common.Zip.Headers +namespace SharpCompress.Common.Zip.Headers; + +[Flags] +internal enum HeaderFlags : ushort { - [Flags] - internal enum HeaderFlags : ushort - { - None = 0, - Encrypted = 1, // http://www.pkware.com/documents/casestudies/APPNOTE.TXT - Bit1 = 2, - Bit2 = 4, - UsePostDataDescriptor = 8, - EnhancedDeflate = 16, + None = 0, + Encrypted = 1, // http://www.pkware.com/documents/casestudies/APPNOTE.TXT + Bit1 = 2, + Bit2 = 4, + UsePostDataDescriptor = 8, + EnhancedDeflate = 16, - //Bit 11: Language encoding flag - Efs = 2048 - } + //Bit 11: Language encoding flag + Efs = 2048 } diff --git a/src/SharpCompress/Common/Zip/Headers/IgnoreHeader.cs b/src/SharpCompress/Common/Zip/Headers/IgnoreHeader.cs index 6957f62f..4852228c 100644 --- a/src/SharpCompress/Common/Zip/Headers/IgnoreHeader.cs +++ b/src/SharpCompress/Common/Zip/Headers/IgnoreHeader.cs @@ -1,11 +1,10 @@ -using System.IO; +using System.IO; -namespace SharpCompress.Common.Zip.Headers +namespace SharpCompress.Common.Zip.Headers; + +internal class IgnoreHeader : ZipHeader { - internal class IgnoreHeader : ZipHeader - { - public IgnoreHeader(ZipHeaderType type) : base(type) { } + public IgnoreHeader(ZipHeaderType type) : base(type) { } - internal override void Read(BinaryReader reader) { } - } + internal override void Read(BinaryReader reader) { } } diff --git a/src/SharpCompress/Common/Zip/Headers/LocalEntryHeader.cs b/src/SharpCompress/Common/Zip/Headers/LocalEntryHeader.cs index e3fc8071..3cd8ce46 100644 --- a/src/SharpCompress/Common/Zip/Headers/LocalEntryHeader.cs +++ b/src/SharpCompress/Common/Zip/Headers/LocalEntryHeader.cs @@ -1,73 +1,72 @@ -using System.IO; +using System.IO; using System.Linq; -namespace SharpCompress.Common.Zip.Headers +namespace SharpCompress.Common.Zip.Headers; + +internal class LocalEntryHeader : ZipFileEntry { - internal class LocalEntryHeader : ZipFileEntry + public LocalEntryHeader(ArchiveEncoding archiveEncoding) + : base(ZipHeaderType.LocalEntry, archiveEncoding) { } + + internal override void Read(BinaryReader reader) { - public LocalEntryHeader(ArchiveEncoding archiveEncoding) - : base(ZipHeaderType.LocalEntry, archiveEncoding) { } + Version = reader.ReadUInt16(); + Flags = (HeaderFlags)reader.ReadUInt16(); + CompressionMethod = (ZipCompressionMethod)reader.ReadUInt16(); + LastModifiedTime = reader.ReadUInt16(); + LastModifiedDate = reader.ReadUInt16(); + Crc = reader.ReadUInt32(); + CompressedSize = reader.ReadUInt32(); + UncompressedSize = reader.ReadUInt32(); + var nameLength = reader.ReadUInt16(); + var extraLength = reader.ReadUInt16(); + var name = reader.ReadBytes(nameLength); + var extra = reader.ReadBytes(extraLength); - internal override void Read(BinaryReader reader) + // According to .ZIP File Format Specification + // + // For example: https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT + // + // Bit 11: Language encoding flag (EFS). If this bit is set, + // the filename and comment fields for this file + // MUST be encoded using UTF-8. (see APPENDIX D) + + if (Flags.HasFlag(HeaderFlags.Efs)) { - Version = reader.ReadUInt16(); - Flags = (HeaderFlags)reader.ReadUInt16(); - CompressionMethod = (ZipCompressionMethod)reader.ReadUInt16(); - LastModifiedTime = reader.ReadUInt16(); - LastModifiedDate = reader.ReadUInt16(); - Crc = reader.ReadUInt32(); - CompressedSize = reader.ReadUInt32(); - UncompressedSize = reader.ReadUInt32(); - ushort nameLength = reader.ReadUInt16(); - ushort extraLength = reader.ReadUInt16(); - byte[] name = reader.ReadBytes(nameLength); - byte[] extra = reader.ReadBytes(extraLength); - - // According to .ZIP File Format Specification - // - // For example: https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT - // - // Bit 11: Language encoding flag (EFS). If this bit is set, - // the filename and comment fields for this file - // MUST be encoded using UTF-8. (see APPENDIX D) - - if (Flags.HasFlag(HeaderFlags.Efs)) - { - Name = ArchiveEncoding.DecodeUTF8(name); - } - else - { - Name = ArchiveEncoding.Decode(name); - } - - LoadExtra(extra); - - var unicodePathExtra = Extra.FirstOrDefault( - u => u.Type == ExtraDataType.UnicodePathExtraField - ); - if (unicodePathExtra != null && ArchiveEncoding.Forced == null) - { - Name = ((ExtraUnicodePathExtraField)unicodePathExtra).UnicodeName; - } - - var zip64ExtraData = Extra - .OfType() - .FirstOrDefault(); - if (zip64ExtraData != null) - { - zip64ExtraData.Process(UncompressedSize, CompressedSize, 0, 0); - - if (CompressedSize == uint.MaxValue) - { - CompressedSize = zip64ExtraData.CompressedSize; - } - if (UncompressedSize == uint.MaxValue) - { - UncompressedSize = zip64ExtraData.UncompressedSize; - } - } + Name = ArchiveEncoding.DecodeUTF8(name); + } + else + { + Name = ArchiveEncoding.Decode(name); } - internal ushort Version { get; private set; } + LoadExtra(extra); + + var unicodePathExtra = Extra.FirstOrDefault( + u => u.Type == ExtraDataType.UnicodePathExtraField + ); + if (unicodePathExtra != null && ArchiveEncoding.Forced == null) + { + Name = ((ExtraUnicodePathExtraField)unicodePathExtra).UnicodeName; + } + + var zip64ExtraData = Extra + .OfType() + .FirstOrDefault(); + if (zip64ExtraData != null) + { + zip64ExtraData.Process(UncompressedSize, CompressedSize, 0, 0); + + if (CompressedSize == uint.MaxValue) + { + CompressedSize = zip64ExtraData.CompressedSize; + } + if (UncompressedSize == uint.MaxValue) + { + UncompressedSize = zip64ExtraData.UncompressedSize; + } + } } + + 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 74d1b224..4920ca36 100644 --- a/src/SharpCompress/Common/Zip/Headers/LocalEntryHeaderExtraFactory.cs +++ b/src/SharpCompress/Common/Zip/Headers/LocalEntryHeaderExtraFactory.cs @@ -1,169 +1,168 @@ -using System; +using System; using System.Buffers.Binary; using System.Text; -namespace SharpCompress.Common.Zip.Headers +namespace SharpCompress.Common.Zip.Headers; + +internal enum ExtraDataType : ushort { - internal enum ExtraDataType : ushort + WinZipAes = 0x9901, + + NotImplementedExtraData = 0xFFFF, + + // Third Party Mappings + // -Info-ZIP Unicode Path Extra Field + UnicodePathExtraField = 0x7075, + Zip64ExtendedInformationExtraField = 0x0001 +} + +internal class ExtraData +{ + public ExtraData(ExtraDataType type, ushort length, byte[] dataBytes) { - WinZipAes = 0x9901, - - NotImplementedExtraData = 0xFFFF, - - // Third Party Mappings - // -Info-ZIP Unicode Path Extra Field - UnicodePathExtraField = 0x7075, - Zip64ExtendedInformationExtraField = 0x0001 + Type = type; + Length = length; + DataBytes = dataBytes; } - internal class ExtraData + internal ExtraDataType Type { get; } + internal ushort Length { get; } + internal byte[] DataBytes { get; } +} + +internal sealed class ExtraUnicodePathExtraField : ExtraData +{ + public ExtraUnicodePathExtraField(ExtraDataType type, ushort length, byte[] dataBytes) + : base(type, length, dataBytes) { } + + internal byte Version => DataBytes[0]; + + internal byte[] NameCrc32 { - public ExtraData(ExtraDataType type, ushort length, byte[] dataBytes) + get { - Type = type; - Length = length; - DataBytes = dataBytes; - } - - internal ExtraDataType Type { get; } - internal ushort Length { get; } - internal byte[] DataBytes { get; } - } - - internal sealed class ExtraUnicodePathExtraField : ExtraData - { - public ExtraUnicodePathExtraField(ExtraDataType type, ushort length, byte[] dataBytes) - : base(type, length, dataBytes) { } - - internal byte Version => DataBytes[0]; - - internal byte[] NameCrc32 - { - get - { - var crc = new byte[4]; - Buffer.BlockCopy(DataBytes, 1, crc, 0, 4); - return crc; - } - } - - internal string UnicodeName - { - get - { - // PathNamelength = dataLength - Version(1 byte) - NameCRC32(4 bytes) - var length = Length - 5; - var nameStr = Encoding.UTF8.GetString(DataBytes, 5, length); - return nameStr; - } + var crc = new byte[4]; + Buffer.BlockCopy(DataBytes, 1, crc, 0, 4); + return crc; } } - internal sealed class Zip64ExtendedInformationExtraField : ExtraData + internal string UnicodeName { - public Zip64ExtendedInformationExtraField( - ExtraDataType type, - ushort length, - byte[] dataBytes - ) : base(type, length, dataBytes) { } - - // From the spec, values are only in the extradata if the standard - // value is set to 0xFFFFFFFF (or 0xFFFF for the Disk Start Number). - // Values, if present, must appear in the following order: - // - Original Size - // - Compressed Size - // - Relative Header Offset - // - Disk Start Number - public void Process( - long uncompressedFileSize, - long compressedFileSize, - long relativeHeaderOffset, - ushort diskNumber - ) + get { - var bytesRequired = - ((uncompressedFileSize == uint.MaxValue) ? 8 : 0) - + ((compressedFileSize == uint.MaxValue) ? 8 : 0) - + ((relativeHeaderOffset == uint.MaxValue) ? 8 : 0) - + ((diskNumber == ushort.MaxValue) ? 4 : 0); - var currentIndex = 0; - - if (bytesRequired > DataBytes.Length) - { - throw new ArchiveException( - "Zip64 extended information extra field is not large enough for the required information" - ); - } - - if (uncompressedFileSize == uint.MaxValue) - { - UncompressedSize = BinaryPrimitives.ReadInt64LittleEndian( - DataBytes.AsSpan(currentIndex) - ); - currentIndex += 8; - } - - if (compressedFileSize == uint.MaxValue) - { - CompressedSize = BinaryPrimitives.ReadInt64LittleEndian( - DataBytes.AsSpan(currentIndex) - ); - currentIndex += 8; - } - - if (relativeHeaderOffset == uint.MaxValue) - { - RelativeOffsetOfEntryHeader = BinaryPrimitives.ReadInt64LittleEndian( - DataBytes.AsSpan(currentIndex) - ); - currentIndex += 8; - } - - if (diskNumber == ushort.MaxValue) - { - VolumeNumber = BinaryPrimitives.ReadUInt32LittleEndian( - DataBytes.AsSpan(currentIndex) - ); - } - } - - /// - /// Uncompressed file size. Only valid after has been called and if the - /// original entry header had a corresponding 0xFFFFFFFF value. - /// - public long UncompressedSize { get; private set; } - - /// - /// Compressed file size. Only valid after has been called and if the - /// original entry header had a corresponding 0xFFFFFFFF value. - /// - public long CompressedSize { get; private set; } - - /// - /// Relative offset of the entry header. Only valid after has been called and if the - /// original entry header had a corresponding 0xFFFFFFFF value. - /// - public long RelativeOffsetOfEntryHeader { get; private set; } - - /// - /// Volume number. Only valid after has been called and if the - /// original entry header had a corresponding 0xFFFF value. - /// - public uint VolumeNumber { get; private set; } - } - - internal static class LocalEntryHeaderExtraFactory - { - internal static ExtraData Create(ExtraDataType type, ushort length, byte[] extraData) - { - return type switch - { - ExtraDataType.UnicodePathExtraField - => new ExtraUnicodePathExtraField(type, length, extraData), - ExtraDataType.Zip64ExtendedInformationExtraField - => new Zip64ExtendedInformationExtraField(type, length, extraData), - _ => new ExtraData(type, length, extraData) - }; + // PathNamelength = dataLength - Version(1 byte) - NameCRC32(4 bytes) + var length = Length - 5; + var nameStr = Encoding.UTF8.GetString(DataBytes, 5, length); + return nameStr; } } } + +internal sealed class Zip64ExtendedInformationExtraField : ExtraData +{ + public Zip64ExtendedInformationExtraField( + ExtraDataType type, + ushort length, + byte[] dataBytes + ) : base(type, length, dataBytes) { } + + // From the spec, values are only in the extradata if the standard + // value is set to 0xFFFFFFFF (or 0xFFFF for the Disk Start Number). + // Values, if present, must appear in the following order: + // - Original Size + // - Compressed Size + // - Relative Header Offset + // - Disk Start Number + public void Process( + long uncompressedFileSize, + long compressedFileSize, + long relativeHeaderOffset, + ushort diskNumber + ) + { + var bytesRequired = + ((uncompressedFileSize == uint.MaxValue) ? 8 : 0) + + ((compressedFileSize == uint.MaxValue) ? 8 : 0) + + ((relativeHeaderOffset == uint.MaxValue) ? 8 : 0) + + ((diskNumber == ushort.MaxValue) ? 4 : 0); + var currentIndex = 0; + + if (bytesRequired > DataBytes.Length) + { + throw new ArchiveException( + "Zip64 extended information extra field is not large enough for the required information" + ); + } + + if (uncompressedFileSize == uint.MaxValue) + { + UncompressedSize = BinaryPrimitives.ReadInt64LittleEndian( + DataBytes.AsSpan(currentIndex) + ); + currentIndex += 8; + } + + if (compressedFileSize == uint.MaxValue) + { + CompressedSize = BinaryPrimitives.ReadInt64LittleEndian( + DataBytes.AsSpan(currentIndex) + ); + currentIndex += 8; + } + + if (relativeHeaderOffset == uint.MaxValue) + { + RelativeOffsetOfEntryHeader = BinaryPrimitives.ReadInt64LittleEndian( + DataBytes.AsSpan(currentIndex) + ); + currentIndex += 8; + } + + if (diskNumber == ushort.MaxValue) + { + VolumeNumber = BinaryPrimitives.ReadUInt32LittleEndian( + DataBytes.AsSpan(currentIndex) + ); + } + } + + /// + /// Uncompressed file size. Only valid after has been called and if the + /// original entry header had a corresponding 0xFFFFFFFF value. + /// + public long UncompressedSize { get; private set; } + + /// + /// Compressed file size. Only valid after has been called and if the + /// original entry header had a corresponding 0xFFFFFFFF value. + /// + public long CompressedSize { get; private set; } + + /// + /// Relative offset of the entry header. Only valid after has been called and if the + /// original entry header had a corresponding 0xFFFFFFFF value. + /// + public long RelativeOffsetOfEntryHeader { get; private set; } + + /// + /// Volume number. Only valid after has been called and if the + /// original entry header had a corresponding 0xFFFF value. + /// + public uint VolumeNumber { get; private set; } +} + +internal static class LocalEntryHeaderExtraFactory +{ + internal static ExtraData Create(ExtraDataType type, ushort length, byte[] extraData) + { + return type switch + { + ExtraDataType.UnicodePathExtraField + => new ExtraUnicodePathExtraField(type, length, extraData), + ExtraDataType.Zip64ExtendedInformationExtraField + => new Zip64ExtendedInformationExtraField(type, length, extraData), + _ => new ExtraData(type, length, extraData) + }; + } +} diff --git a/src/SharpCompress/Common/Zip/Headers/SplitHeader.cs b/src/SharpCompress/Common/Zip/Headers/SplitHeader.cs index 7a20430c..1e98517b 100644 --- a/src/SharpCompress/Common/Zip/Headers/SplitHeader.cs +++ b/src/SharpCompress/Common/Zip/Headers/SplitHeader.cs @@ -1,15 +1,14 @@ -using System; +using System; using System.IO; -namespace SharpCompress.Common.Zip.Headers -{ - internal class SplitHeader : ZipHeader - { - public SplitHeader() : base(ZipHeaderType.Split) { } +namespace SharpCompress.Common.Zip.Headers; - internal override void Read(BinaryReader reader) - { - throw new NotImplementedException(); - } +internal class SplitHeader : ZipHeader +{ + public SplitHeader() : base(ZipHeaderType.Split) { } + + internal override void Read(BinaryReader reader) + { + throw new NotImplementedException(); } } diff --git a/src/SharpCompress/Common/Zip/Headers/Zip64DirectoryEndHeader.cs b/src/SharpCompress/Common/Zip/Headers/Zip64DirectoryEndHeader.cs index fffbbabf..0356c48c 100644 --- a/src/SharpCompress/Common/Zip/Headers/Zip64DirectoryEndHeader.cs +++ b/src/SharpCompress/Common/Zip/Headers/Zip64DirectoryEndHeader.cs @@ -1,50 +1,49 @@ -using System.IO; +using System.IO; -namespace SharpCompress.Common.Zip.Headers +namespace SharpCompress.Common.Zip.Headers; + +internal class Zip64DirectoryEndHeader : ZipHeader { - internal class Zip64DirectoryEndHeader : ZipHeader + public Zip64DirectoryEndHeader() : base(ZipHeaderType.Zip64DirectoryEnd) { } + + internal override void Read(BinaryReader reader) { - public Zip64DirectoryEndHeader() : base(ZipHeaderType.Zip64DirectoryEnd) { } - - internal override void Read(BinaryReader reader) - { - SizeOfDirectoryEndRecord = (long)reader.ReadUInt64(); - VersionMadeBy = reader.ReadUInt16(); - VersionNeededToExtract = reader.ReadUInt16(); - VolumeNumber = reader.ReadUInt32(); - FirstVolumeWithDirectory = reader.ReadUInt32(); - TotalNumberOfEntriesInDisk = (long)reader.ReadUInt64(); - TotalNumberOfEntries = (long)reader.ReadUInt64(); - DirectorySize = (long)reader.ReadUInt64(); - DirectoryStartOffsetRelativeToDisk = (long)reader.ReadUInt64(); - DataSector = reader.ReadBytes( - (int)( - SizeOfDirectoryEndRecord - - SIZE_OF_FIXED_HEADER_DATA_EXCEPT_SIGNATURE_AND_SIZE_FIELDS - ) - ); - } - - private const int SIZE_OF_FIXED_HEADER_DATA_EXCEPT_SIGNATURE_AND_SIZE_FIELDS = 44; - - public long SizeOfDirectoryEndRecord { get; private set; } - - public ushort VersionMadeBy { get; private set; } - - public ushort VersionNeededToExtract { get; private set; } - - public uint VolumeNumber { get; private set; } - - public uint FirstVolumeWithDirectory { get; private set; } - - public long TotalNumberOfEntriesInDisk { get; private set; } - - public long TotalNumberOfEntries { get; private set; } - - public long DirectorySize { get; private set; } - - public long DirectoryStartOffsetRelativeToDisk { get; private set; } - - public byte[]? DataSector { get; private set; } + SizeOfDirectoryEndRecord = (long)reader.ReadUInt64(); + VersionMadeBy = reader.ReadUInt16(); + VersionNeededToExtract = reader.ReadUInt16(); + VolumeNumber = reader.ReadUInt32(); + FirstVolumeWithDirectory = reader.ReadUInt32(); + TotalNumberOfEntriesInDisk = (long)reader.ReadUInt64(); + TotalNumberOfEntries = (long)reader.ReadUInt64(); + DirectorySize = (long)reader.ReadUInt64(); + DirectoryStartOffsetRelativeToDisk = (long)reader.ReadUInt64(); + DataSector = reader.ReadBytes( + (int)( + SizeOfDirectoryEndRecord + - SIZE_OF_FIXED_HEADER_DATA_EXCEPT_SIGNATURE_AND_SIZE_FIELDS + ) + ); } + + private const int SIZE_OF_FIXED_HEADER_DATA_EXCEPT_SIGNATURE_AND_SIZE_FIELDS = 44; + + public long SizeOfDirectoryEndRecord { get; private set; } + + public ushort VersionMadeBy { get; private set; } + + public ushort VersionNeededToExtract { get; private set; } + + public uint VolumeNumber { get; private set; } + + public uint FirstVolumeWithDirectory { get; private set; } + + public long TotalNumberOfEntriesInDisk { get; private set; } + + public long TotalNumberOfEntries { get; private set; } + + public long DirectorySize { get; private set; } + + public long DirectoryStartOffsetRelativeToDisk { get; private set; } + + public byte[]? DataSector { get; private set; } } diff --git a/src/SharpCompress/Common/Zip/Headers/Zip64DirectoryEndLocatorHeader.cs b/src/SharpCompress/Common/Zip/Headers/Zip64DirectoryEndLocatorHeader.cs index 16724668..9bbf2670 100644 --- a/src/SharpCompress/Common/Zip/Headers/Zip64DirectoryEndLocatorHeader.cs +++ b/src/SharpCompress/Common/Zip/Headers/Zip64DirectoryEndLocatorHeader.cs @@ -1,22 +1,21 @@ using System.IO; -namespace SharpCompress.Common.Zip.Headers +namespace SharpCompress.Common.Zip.Headers; + +internal class Zip64DirectoryEndLocatorHeader : ZipHeader { - internal class Zip64DirectoryEndLocatorHeader : ZipHeader + public Zip64DirectoryEndLocatorHeader() : base(ZipHeaderType.Zip64DirectoryEndLocator) { } + + internal override void Read(BinaryReader reader) { - public Zip64DirectoryEndLocatorHeader() : base(ZipHeaderType.Zip64DirectoryEndLocator) { } - - internal override void Read(BinaryReader reader) - { - FirstVolumeWithDirectory = reader.ReadUInt32(); - RelativeOffsetOfTheEndOfDirectoryRecord = (long)reader.ReadUInt64(); - TotalNumberOfVolumes = reader.ReadUInt32(); - } - - public uint FirstVolumeWithDirectory { get; private set; } - - public long RelativeOffsetOfTheEndOfDirectoryRecord { get; private set; } - - public uint TotalNumberOfVolumes { get; private set; } + FirstVolumeWithDirectory = reader.ReadUInt32(); + RelativeOffsetOfTheEndOfDirectoryRecord = (long)reader.ReadUInt64(); + TotalNumberOfVolumes = reader.ReadUInt32(); } + + public uint FirstVolumeWithDirectory { get; private set; } + + public long RelativeOffsetOfTheEndOfDirectoryRecord { get; private set; } + + public uint TotalNumberOfVolumes { get; private set; } } diff --git a/src/SharpCompress/Common/Zip/Headers/ZipFileEntry.cs b/src/SharpCompress/Common/Zip/Headers/ZipFileEntry.cs index 40d5c313..7ac43a07 100644 --- a/src/SharpCompress/Common/Zip/Headers/ZipFileEntry.cs +++ b/src/SharpCompress/Common/Zip/Headers/ZipFileEntry.cs @@ -1,109 +1,108 @@ -#nullable disable +#nullable disable using System; using System.Buffers.Binary; using System.Collections.Generic; using System.IO; -namespace SharpCompress.Common.Zip.Headers +namespace SharpCompress.Common.Zip.Headers; + +internal abstract class ZipFileEntry : ZipHeader { - internal abstract class ZipFileEntry : ZipHeader + protected ZipFileEntry(ZipHeaderType type, ArchiveEncoding archiveEncoding) : base(type) { - protected ZipFileEntry(ZipHeaderType type, ArchiveEncoding archiveEncoding) : base(type) - { - Extra = new List(); - ArchiveEncoding = archiveEncoding; - } - - internal bool IsDirectory - { - get - { - if (Name.EndsWith('/')) - { - return true; - } - - //.NET Framework 4.5 : System.IO.Compression::CreateFromDirectory() probably writes backslashes to headers - return CompressedSize == 0 && UncompressedSize == 0 && Name.EndsWith('\\'); - } - } - - internal Stream PackedStream { get; set; } - - internal ArchiveEncoding ArchiveEncoding { get; } - - internal string Name { get; set; } - - internal HeaderFlags Flags { get; set; } - - internal ZipCompressionMethod CompressionMethod { get; set; } - - internal long CompressedSize { get; set; } - - internal long? DataStartPosition { get; set; } - - internal long UncompressedSize { get; set; } - - internal List Extra { get; set; } - - public string Password { get; set; } - - internal PkwareTraditionalEncryptionData ComposeEncryptionData(Stream archiveStream) - { - if (archiveStream is null) - { - throw new ArgumentNullException(nameof(archiveStream)); - } - - var buffer = new byte[12]; - archiveStream.ReadFully(buffer); - - PkwareTraditionalEncryptionData encryptionData = - PkwareTraditionalEncryptionData.ForRead(Password!, this, buffer); - - return encryptionData; - } - - internal WinzipAesEncryptionData WinzipAesEncryptionData { get; set; } - - internal ushort LastModifiedDate { get; set; } - - internal ushort LastModifiedTime { get; set; } - - internal uint Crc { get; set; } - - protected void LoadExtra(byte[] extra) - { - for (int i = 0; i < extra.Length - 4; ) - { - ExtraDataType type = (ExtraDataType) - BinaryPrimitives.ReadUInt16LittleEndian(extra.AsSpan(i)); - if (!Enum.IsDefined(typeof(ExtraDataType), type)) - { - type = ExtraDataType.NotImplementedExtraData; - } - - ushort length = BinaryPrimitives.ReadUInt16LittleEndian(extra.AsSpan(i + 2)); - - // 7zip has this same kind of check to ignore extras blocks that don't conform to the standard 2-byte ID, 2-byte length, N-byte value. - // CPP/7Zip/Zip/ZipIn.cpp: CInArchive::ReadExtra - if (length > extra.Length) - { - // bad extras block - return; - } - - byte[] data = new byte[length]; - Buffer.BlockCopy(extra, i + 4, data, 0, length); - Extra.Add(LocalEntryHeaderExtraFactory.Create(type, length, data)); - - i += length + 4; - } - } - - internal ZipFilePart Part { get; set; } - - internal bool IsZip64 => CompressedSize >= uint.MaxValue; + Extra = new List(); + ArchiveEncoding = archiveEncoding; } + + internal bool IsDirectory + { + get + { + if (Name.EndsWith('/')) + { + return true; + } + + //.NET Framework 4.5 : System.IO.Compression::CreateFromDirectory() probably writes backslashes to headers + return CompressedSize == 0 && UncompressedSize == 0 && Name.EndsWith('\\'); + } + } + + internal Stream PackedStream { get; set; } + + internal ArchiveEncoding ArchiveEncoding { get; } + + internal string Name { get; set; } + + internal HeaderFlags Flags { get; set; } + + internal ZipCompressionMethod CompressionMethod { get; set; } + + internal long CompressedSize { get; set; } + + internal long? DataStartPosition { get; set; } + + internal long UncompressedSize { get; set; } + + internal List Extra { get; set; } + + public string Password { get; set; } + + internal PkwareTraditionalEncryptionData ComposeEncryptionData(Stream archiveStream) + { + if (archiveStream is null) + { + throw new ArgumentNullException(nameof(archiveStream)); + } + + var buffer = new byte[12]; + archiveStream.ReadFully(buffer); + + var encryptionData = + PkwareTraditionalEncryptionData.ForRead(Password!, this, buffer); + + return encryptionData; + } + + internal WinzipAesEncryptionData WinzipAesEncryptionData { get; set; } + + internal ushort LastModifiedDate { get; set; } + + internal ushort LastModifiedTime { get; set; } + + internal uint Crc { get; set; } + + protected void LoadExtra(byte[] extra) + { + for (var i = 0; i < extra.Length - 4;) + { + var type = (ExtraDataType) + BinaryPrimitives.ReadUInt16LittleEndian(extra.AsSpan(i)); + if (!Enum.IsDefined(typeof(ExtraDataType), type)) + { + type = ExtraDataType.NotImplementedExtraData; + } + + var length = BinaryPrimitives.ReadUInt16LittleEndian(extra.AsSpan(i + 2)); + + // 7zip has this same kind of check to ignore extras blocks that don't conform to the standard 2-byte ID, 2-byte length, N-byte value. + // CPP/7Zip/Zip/ZipIn.cpp: CInArchive::ReadExtra + if (length > extra.Length) + { + // bad extras block + return; + } + + var data = new byte[length]; + Buffer.BlockCopy(extra, i + 4, data, 0, length); + Extra.Add(LocalEntryHeaderExtraFactory.Create(type, length, data)); + + i += length + 4; + } + } + + internal ZipFilePart Part { get; set; } + + internal bool IsZip64 => CompressedSize >= uint.MaxValue; } diff --git a/src/SharpCompress/Common/Zip/Headers/ZipHeader.cs b/src/SharpCompress/Common/Zip/Headers/ZipHeader.cs index 43042630..36d40a82 100644 --- a/src/SharpCompress/Common/Zip/Headers/ZipHeader.cs +++ b/src/SharpCompress/Common/Zip/Headers/ZipHeader.cs @@ -1,19 +1,18 @@ -using System.IO; +using System.IO; -namespace SharpCompress.Common.Zip.Headers +namespace SharpCompress.Common.Zip.Headers; + +internal abstract class ZipHeader { - internal abstract class ZipHeader + protected ZipHeader(ZipHeaderType type) { - protected ZipHeader(ZipHeaderType type) - { - ZipHeaderType = type; - HasData = true; - } - - internal ZipHeaderType ZipHeaderType { get; } - - internal abstract void Read(BinaryReader reader); - - internal bool HasData { get; set; } + ZipHeaderType = type; + HasData = true; } + + internal ZipHeaderType ZipHeaderType { get; } + + internal abstract void Read(BinaryReader reader); + + internal bool HasData { get; set; } } diff --git a/src/SharpCompress/Common/Zip/Headers/ZipHeaderType.cs b/src/SharpCompress/Common/Zip/Headers/ZipHeaderType.cs index 85f6c3b6..62c29d89 100644 --- a/src/SharpCompress/Common/Zip/Headers/ZipHeaderType.cs +++ b/src/SharpCompress/Common/Zip/Headers/ZipHeaderType.cs @@ -1,13 +1,12 @@ -namespace SharpCompress.Common.Zip.Headers +namespace SharpCompress.Common.Zip.Headers; + +internal enum ZipHeaderType { - internal enum ZipHeaderType - { - Ignore, - LocalEntry, - DirectoryEntry, - DirectoryEnd, - Split, - Zip64DirectoryEnd, - Zip64DirectoryEndLocator - } + Ignore, + LocalEntry, + DirectoryEntry, + DirectoryEnd, + Split, + Zip64DirectoryEnd, + Zip64DirectoryEndLocator } diff --git a/src/SharpCompress/Common/Zip/PkwareTraditionalCryptoStream.cs b/src/SharpCompress/Common/Zip/PkwareTraditionalCryptoStream.cs index 71556292..6ca28fc6 100644 --- a/src/SharpCompress/Common/Zip/PkwareTraditionalCryptoStream.cs +++ b/src/SharpCompress/Common/Zip/PkwareTraditionalCryptoStream.cs @@ -1,116 +1,115 @@ -using System; +using System; using System.IO; -namespace SharpCompress.Common.Zip +namespace SharpCompress.Common.Zip; + +internal enum CryptoMode { - internal enum CryptoMode + Encrypt, + Decrypt +} + +internal class PkwareTraditionalCryptoStream : Stream +{ + private readonly PkwareTraditionalEncryptionData _encryptor; + private readonly CryptoMode _mode; + private readonly Stream _stream; + private bool _isDisposed; + + public PkwareTraditionalCryptoStream( + Stream stream, + PkwareTraditionalEncryptionData encryptor, + CryptoMode mode + ) { - Encrypt, - Decrypt + _encryptor = encryptor; + _stream = stream; + _mode = mode; } - internal class PkwareTraditionalCryptoStream : Stream + public override bool CanRead => (_mode == CryptoMode.Decrypt); + + public override bool CanSeek => false; + + public override bool CanWrite => (_mode == CryptoMode.Encrypt); + + public override long Length => throw new NotSupportedException(); + + public override long Position { - private readonly PkwareTraditionalEncryptionData _encryptor; - private readonly CryptoMode _mode; - private readonly Stream _stream; - private bool _isDisposed; + get => throw new NotSupportedException(); + set => throw new NotSupportedException(); + } - public PkwareTraditionalCryptoStream( - Stream stream, - PkwareTraditionalEncryptionData encryptor, - CryptoMode mode - ) + public override int Read(byte[] buffer, int offset, int count) + { + if (_mode == CryptoMode.Encrypt) { - this._encryptor = encryptor; - this._stream = stream; - this._mode = mode; + throw new NotSupportedException("This stream does not encrypt via Read()"); } - public override bool CanRead => (_mode == CryptoMode.Decrypt); - - public override bool CanSeek => false; - - public override bool CanWrite => (_mode == CryptoMode.Encrypt); - - public override long Length => throw new NotSupportedException(); - - public override long Position + if (buffer is null) { - get => throw new NotSupportedException(); - set => throw new NotSupportedException(); + throw new ArgumentNullException(nameof(buffer)); } - public override int Read(byte[] buffer, int offset, int count) + var temp = new byte[count]; + var readBytes = _stream.Read(temp, 0, count); + var decrypted = _encryptor.Decrypt(temp, readBytes); + Buffer.BlockCopy(decrypted, 0, buffer, offset, readBytes); + return readBytes; + } + + public override void Write(byte[] buffer, int offset, int count) + { + if (_mode == CryptoMode.Decrypt) { - if (_mode == CryptoMode.Encrypt) - { - throw new NotSupportedException("This stream does not encrypt via Read()"); - } - - if (buffer is null) - { - throw new ArgumentNullException(nameof(buffer)); - } - - byte[] temp = new byte[count]; - int readBytes = _stream.Read(temp, 0, count); - byte[] decrypted = _encryptor.Decrypt(temp, readBytes); - Buffer.BlockCopy(decrypted, 0, buffer, offset, readBytes); - return readBytes; + throw new NotSupportedException("This stream does not Decrypt via Write()"); } - public override void Write(byte[] buffer, int offset, int count) + if (count == 0) { - if (_mode == CryptoMode.Decrypt) - { - throw new NotSupportedException("This stream does not Decrypt via Write()"); - } - - if (count == 0) - { - return; - } - - byte[] plaintext; - if (offset != 0) - { - plaintext = new byte[count]; - Buffer.BlockCopy(buffer, offset, plaintext, 0, count); - } - else - { - plaintext = buffer; - } - - byte[] encrypted = _encryptor.Encrypt(plaintext, count); - _stream.Write(encrypted, 0, encrypted.Length); + return; } - public override void Flush() + byte[] plaintext; + if (offset != 0) { - //throw new NotSupportedException(); + plaintext = new byte[count]; + Buffer.BlockCopy(buffer, offset, plaintext, 0, count); + } + else + { + plaintext = buffer; } - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } + var encrypted = _encryptor.Encrypt(plaintext, count); + _stream.Write(encrypted, 0, encrypted.Length); + } - public override void SetLength(long value) - { - throw new NotSupportedException(); - } + public override void Flush() + { + //throw new NotSupportedException(); + } - protected override void Dispose(bool disposing) + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } + + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + protected override void Dispose(bool disposing) + { + if (_isDisposed) { - if (_isDisposed) - { - return; - } - _isDisposed = true; - base.Dispose(disposing); - _stream.Dispose(); + return; } + _isDisposed = true; + base.Dispose(disposing); + _stream.Dispose(); } } diff --git a/src/SharpCompress/Common/Zip/PkwareTraditionalEncryptionData.cs b/src/SharpCompress/Common/Zip/PkwareTraditionalEncryptionData.cs index 96a88e94..353000d8 100644 --- a/src/SharpCompress/Common/Zip/PkwareTraditionalEncryptionData.cs +++ b/src/SharpCompress/Common/Zip/PkwareTraditionalEncryptionData.cs @@ -1,118 +1,117 @@ -using System; +using System; using SharpCompress.Common.Zip.Headers; using SharpCompress.Compressors.Deflate; -namespace SharpCompress.Common.Zip +namespace SharpCompress.Common.Zip; + +internal class PkwareTraditionalEncryptionData { - internal class PkwareTraditionalEncryptionData + private static readonly CRC32 CRC32 = new CRC32(); + private readonly uint[] _keys = { 0x12345678, 0x23456789, 0x34567890 }; + private readonly ArchiveEncoding _archiveEncoding; + + private PkwareTraditionalEncryptionData(string password, ArchiveEncoding archiveEncoding) { - private static readonly CRC32 CRC32 = new CRC32(); - private readonly UInt32[] _keys = { 0x12345678, 0x23456789, 0x34567890 }; - private readonly ArchiveEncoding _archiveEncoding; + _archiveEncoding = archiveEncoding; + Initialize(password); + } - private PkwareTraditionalEncryptionData(string password, ArchiveEncoding archiveEncoding) + private byte MagicByte + { + get { - _archiveEncoding = archiveEncoding; - Initialize(password); - } - - private byte MagicByte - { - get - { - ushort t = (ushort)((ushort)(_keys[2] & 0xFFFF) | 2); - return (byte)((t * (t ^ 1)) >> 8); - } - } - - public static PkwareTraditionalEncryptionData ForRead( - string password, - ZipFileEntry header, - byte[] encryptionHeader - ) - { - var encryptor = new PkwareTraditionalEncryptionData(password, header.ArchiveEncoding); - byte[] plainTextHeader = encryptor.Decrypt(encryptionHeader, encryptionHeader.Length); - if (plainTextHeader[11] != (byte)((header.Crc >> 24) & 0xff)) - { - if (!FlagUtility.HasFlag(header.Flags, HeaderFlags.UsePostDataDescriptor)) - { - throw new CryptographicException("The password did not match."); - } - if (plainTextHeader[11] != (byte)((header.LastModifiedTime >> 8) & 0xff)) - { - throw new CryptographicException("The password did not match."); - } - } - return encryptor; - } - - public byte[] Decrypt(byte[] cipherText, int length) - { - if (length > cipherText.Length) - { - throw new ArgumentOutOfRangeException( - nameof(length), - "Bad length during Decryption: the length parameter must be smaller than or equal to the size of the destination array." - ); - } - - var plainText = new byte[length]; - for (int i = 0; i < length; i++) - { - var c = (byte)(cipherText[i] ^ MagicByte); - UpdateKeys(c); - plainText[i] = c; - } - return plainText; - } - - public byte[] Encrypt(byte[] plainText, int length) - { - if (plainText is null) - { - throw new ArgumentNullException(nameof(plainText)); - } - - if (length > plainText.Length) - { - throw new ArgumentOutOfRangeException( - nameof(length), - "Bad length during Encryption: The length parameter must be smaller than or equal to the size of the destination array." - ); - } - - var cipherText = new byte[length]; - for (int i = 0; i < length; i++) - { - byte c = plainText[i]; - cipherText[i] = (byte)(plainText[i] ^ MagicByte); - UpdateKeys(c); - } - return cipherText; - } - - private void Initialize(string password) - { - byte[] p = StringToByteArray(password); - for (int i = 0; i < password.Length; i++) - { - UpdateKeys(p[i]); - } - } - - internal byte[] StringToByteArray(string value) - { - byte[] a = _archiveEncoding.Password.GetBytes(value); - return a; - } - - private void UpdateKeys(byte byteValue) - { - _keys[0] = (UInt32)CRC32.ComputeCrc32((int)_keys[0], byteValue); - _keys[1] = _keys[1] + (byte)_keys[0]; - _keys[1] = _keys[1] * 0x08088405 + 1; - _keys[2] = (UInt32)CRC32.ComputeCrc32((int)_keys[2], (byte)(_keys[1] >> 24)); + var t = (ushort)((ushort)(_keys[2] & 0xFFFF) | 2); + return (byte)((t * (t ^ 1)) >> 8); } } + + public static PkwareTraditionalEncryptionData ForRead( + string password, + ZipFileEntry header, + byte[] encryptionHeader + ) + { + var encryptor = new PkwareTraditionalEncryptionData(password, header.ArchiveEncoding); + var plainTextHeader = encryptor.Decrypt(encryptionHeader, encryptionHeader.Length); + if (plainTextHeader[11] != (byte)((header.Crc >> 24) & 0xff)) + { + if (!FlagUtility.HasFlag(header.Flags, HeaderFlags.UsePostDataDescriptor)) + { + throw new CryptographicException("The password did not match."); + } + if (plainTextHeader[11] != (byte)((header.LastModifiedTime >> 8) & 0xff)) + { + throw new CryptographicException("The password did not match."); + } + } + return encryptor; + } + + public byte[] Decrypt(byte[] cipherText, int length) + { + if (length > cipherText.Length) + { + throw new ArgumentOutOfRangeException( + nameof(length), + "Bad length during Decryption: the length parameter must be smaller than or equal to the size of the destination array." + ); + } + + var plainText = new byte[length]; + for (var i = 0; i < length; i++) + { + var c = (byte)(cipherText[i] ^ MagicByte); + UpdateKeys(c); + plainText[i] = c; + } + return plainText; + } + + public byte[] Encrypt(byte[] plainText, int length) + { + if (plainText is null) + { + throw new ArgumentNullException(nameof(plainText)); + } + + if (length > plainText.Length) + { + throw new ArgumentOutOfRangeException( + nameof(length), + "Bad length during Encryption: The length parameter must be smaller than or equal to the size of the destination array." + ); + } + + var cipherText = new byte[length]; + for (var i = 0; i < length; i++) + { + var c = plainText[i]; + cipherText[i] = (byte)(plainText[i] ^ MagicByte); + UpdateKeys(c); + } + return cipherText; + } + + private void Initialize(string password) + { + var p = StringToByteArray(password); + for (var i = 0; i < password.Length; i++) + { + UpdateKeys(p[i]); + } + } + + internal byte[] StringToByteArray(string value) + { + var a = _archiveEncoding.Password.GetBytes(value); + return a; + } + + private void UpdateKeys(byte byteValue) + { + _keys[0] = (uint)CRC32.ComputeCrc32((int)_keys[0], byteValue); + _keys[1] = _keys[1] + (byte)_keys[0]; + _keys[1] = (_keys[1] * 0x08088405) + 1; + _keys[2] = (uint)CRC32.ComputeCrc32((int)_keys[2], (byte)(_keys[1] >> 24)); + } } diff --git a/src/SharpCompress/Common/Zip/SeekableZipFilePart.cs b/src/SharpCompress/Common/Zip/SeekableZipFilePart.cs index 02a40c38..dc7e4783 100644 --- a/src/SharpCompress/Common/Zip/SeekableZipFilePart.cs +++ b/src/SharpCompress/Common/Zip/SeekableZipFilePart.cs @@ -1,59 +1,58 @@ -using System.IO; +using System.IO; using SharpCompress.Common.Zip.Headers; using SharpCompress.IO; -namespace SharpCompress.Common.Zip +namespace SharpCompress.Common.Zip; + +internal class SeekableZipFilePart : ZipFilePart { - internal class SeekableZipFilePart : ZipFilePart + private bool _isLocalHeaderLoaded; + private readonly SeekableZipHeaderFactory _headerFactory; + private readonly DirectoryEntryHeader _directoryEntryHeader; + + internal SeekableZipFilePart( + SeekableZipHeaderFactory headerFactory, + DirectoryEntryHeader header, + Stream stream + ) : base(header, stream) { - private bool _isLocalHeaderLoaded; - private readonly SeekableZipHeaderFactory _headerFactory; - private readonly DirectoryEntryHeader _directoryEntryHeader; + _headerFactory = headerFactory; + _directoryEntryHeader = header; + } - internal SeekableZipFilePart( - SeekableZipHeaderFactory headerFactory, - DirectoryEntryHeader header, - Stream stream - ) : base(header, stream) + internal override Stream GetCompressedStream() + { + if (!_isLocalHeaderLoaded) { - _headerFactory = headerFactory; - _directoryEntryHeader = header; + LoadLocalHeader(); + _isLocalHeaderLoaded = true; + } + return base.GetCompressedStream(); + } + + internal string? Comment => ((DirectoryEntryHeader)Header).Comment; + + private void LoadLocalHeader() + { + var hasData = Header.HasData; + Header = _headerFactory.GetLocalHeader(BaseStream, ((DirectoryEntryHeader)Header)); + Header.HasData = hasData; + } + + protected override Stream CreateBaseStream() + { + BaseStream.Position = Header.DataStartPosition!.Value; + + if ( + (Header.CompressedSize == 0) + && FlagUtility.HasFlag(Header.Flags, HeaderFlags.UsePostDataDescriptor) + && (_directoryEntryHeader?.HasData == true) + && (_directoryEntryHeader?.CompressedSize != 0) + ) + { + return new ReadOnlySubStream(BaseStream, _directoryEntryHeader!.CompressedSize); } - internal override Stream GetCompressedStream() - { - if (!_isLocalHeaderLoaded) - { - LoadLocalHeader(); - _isLocalHeaderLoaded = true; - } - return base.GetCompressedStream(); - } - - internal string? Comment => ((DirectoryEntryHeader)Header).Comment; - - private void LoadLocalHeader() - { - bool hasData = Header.HasData; - Header = _headerFactory.GetLocalHeader(BaseStream, ((DirectoryEntryHeader)Header)); - Header.HasData = hasData; - } - - protected override Stream CreateBaseStream() - { - BaseStream.Position = Header.DataStartPosition!.Value; - - if ( - (Header.CompressedSize == 0) - && FlagUtility.HasFlag(Header.Flags, HeaderFlags.UsePostDataDescriptor) - && (_directoryEntryHeader?.HasData == true) - && (_directoryEntryHeader?.CompressedSize != 0) - ) - { - return new ReadOnlySubStream(BaseStream, _directoryEntryHeader!.CompressedSize); - } - - return BaseStream; - } + return BaseStream; } } diff --git a/src/SharpCompress/Common/Zip/SeekableZipHeaderFactory.cs b/src/SharpCompress/Common/Zip/SeekableZipHeaderFactory.cs index ab730bf5..b99d0e2b 100644 --- a/src/SharpCompress/Common/Zip/SeekableZipHeaderFactory.cs +++ b/src/SharpCompress/Common/Zip/SeekableZipHeaderFactory.cs @@ -1,156 +1,154 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using SharpCompress.Common.Zip.Headers; using SharpCompress.IO; -namespace SharpCompress.Common.Zip +namespace SharpCompress.Common.Zip; + +internal sealed class SeekableZipHeaderFactory : ZipHeaderFactory { - internal sealed class SeekableZipHeaderFactory : ZipHeaderFactory + private const int MINIMUM_EOCD_LENGTH = 22; + private const int ZIP64_EOCD_LENGTH = 20; + + // Comment may be within 64kb + structure 22 bytes + private const int MAX_SEARCH_LENGTH_FOR_EOCD = 65557; + private bool _zip64; + + internal SeekableZipHeaderFactory(string? password, ArchiveEncoding archiveEncoding) + : base(StreamingMode.Seekable, password, archiveEncoding) { } + + internal IEnumerable ReadSeekableHeader(Stream stream) { - private const int MINIMUM_EOCD_LENGTH = 22; - private const int ZIP64_EOCD_LENGTH = 20; + var reader = new BinaryReader(stream); - // Comment may be within 64kb + structure 22 bytes - private const int MAX_SEARCH_LENGTH_FOR_EOCD = 65557; - private bool _zip64; + SeekBackToHeader(stream, reader); - internal SeekableZipHeaderFactory(string? password, ArchiveEncoding archiveEncoding) - : base(StreamingMode.Seekable, password, archiveEncoding) { } + var eocd_location = stream.Position; + var entry = new DirectoryEndHeader(); + entry.Read(reader); - internal IEnumerable ReadSeekableHeader(Stream stream) + if (entry.IsZip64) { - var reader = new BinaryReader(stream); + _zip64 = true; - SeekBackToHeader(stream, reader); - - var eocd_location = stream.Position; - var entry = new DirectoryEndHeader(); - entry.Read(reader); - - if (entry.IsZip64) + // ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR should be before the EOCD + stream.Seek(eocd_location - ZIP64_EOCD_LENGTH - 4, SeekOrigin.Begin); + var zip64_locator = reader.ReadUInt32(); + if (zip64_locator != ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR) { - _zip64 = true; - - // ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR should be before the EOCD - stream.Seek(eocd_location - ZIP64_EOCD_LENGTH - 4, SeekOrigin.Begin); - uint zip64_locator = reader.ReadUInt32(); - if (zip64_locator != ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR) - { - throw new ArchiveException("Failed to locate the Zip64 Directory Locator"); - } - - var zip64Locator = new Zip64DirectoryEndLocatorHeader(); - zip64Locator.Read(reader); - - stream.Seek(zip64Locator.RelativeOffsetOfTheEndOfDirectoryRecord, SeekOrigin.Begin); - uint zip64Signature = reader.ReadUInt32(); - if (zip64Signature != ZIP64_END_OF_CENTRAL_DIRECTORY) - { - throw new ArchiveException("Failed to locate the Zip64 Header"); - } - - var zip64Entry = new Zip64DirectoryEndHeader(); - zip64Entry.Read(reader); - stream.Seek(zip64Entry.DirectoryStartOffsetRelativeToDisk, SeekOrigin.Begin); - } - else - { - stream.Seek(entry.DirectoryStartOffsetRelativeToDisk, SeekOrigin.Begin); + throw new ArchiveException("Failed to locate the Zip64 Directory Locator"); } - long position = stream.Position; - while (true) + var zip64Locator = new Zip64DirectoryEndLocatorHeader(); + zip64Locator.Read(reader); + + stream.Seek(zip64Locator.RelativeOffsetOfTheEndOfDirectoryRecord, SeekOrigin.Begin); + var zip64Signature = reader.ReadUInt32(); + if (zip64Signature != ZIP64_END_OF_CENTRAL_DIRECTORY) { - stream.Position = position; - uint signature = reader.ReadUInt32(); - var nextHeader = ReadHeader(signature, reader, _zip64); - position = stream.Position; - - if (nextHeader is null) - { - yield break; - } - - if (nextHeader is DirectoryEntryHeader entryHeader) - { - //entry could be zero bytes so we need to know that. - entryHeader.HasData = entryHeader.CompressedSize != 0; - yield return entryHeader; - } - else if (nextHeader is DirectoryEndHeader endHeader) - { - yield return endHeader; - } + throw new ArchiveException("Failed to locate the Zip64 Header"); } + + var zip64Entry = new Zip64DirectoryEndHeader(); + zip64Entry.Read(reader); + stream.Seek(zip64Entry.DirectoryStartOffsetRelativeToDisk, SeekOrigin.Begin); + } + else + { + stream.Seek(entry.DirectoryStartOffsetRelativeToDisk, SeekOrigin.Begin); } - private static bool IsMatch(byte[] haystack, int position, byte[] needle) + var position = stream.Position; + while (true) { - for (int i = 0; i < needle.Length; i++) + stream.Position = position; + var signature = reader.ReadUInt32(); + var nextHeader = ReadHeader(signature, reader, _zip64); + position = stream.Position; + + if (nextHeader is null) { - if (haystack[position + i] != needle[i]) - { - return false; - } + yield break; } - return true; - } - - private static void SeekBackToHeader(Stream stream, BinaryReader reader) - { - // Minimum EOCD length - if (stream.Length < MINIMUM_EOCD_LENGTH) + if (nextHeader is DirectoryEntryHeader entryHeader) { - throw new ArchiveException( - "Could not find Zip file Directory at the end of the file. File may be corrupted." - ); + //entry could be zero bytes so we need to know that. + entryHeader.HasData = entryHeader.CompressedSize != 0; + yield return entryHeader; } - - int len = - stream.Length < MAX_SEARCH_LENGTH_FOR_EOCD - ? (int)stream.Length - : MAX_SEARCH_LENGTH_FOR_EOCD; - // We search for marker in reverse to find the first occurance - byte[] needle = { 0x06, 0x05, 0x4b, 0x50 }; - - stream.Seek(-len, SeekOrigin.End); - - byte[] seek = reader.ReadBytes(len); - - // Search in reverse - Array.Reverse(seek); - - // don't exclude the minimum eocd region, otherwise you fail to locate the header in empty zip files - var max_search_area = len; // - MINIMUM_EOCD_LENGTH; - - for (int pos_from_end = 0; pos_from_end < max_search_area; ++pos_from_end) + else if (nextHeader is DirectoryEndHeader endHeader) { - if (IsMatch(seek, pos_from_end, needle)) - { - stream.Seek(-pos_from_end, SeekOrigin.End); - return; - } + yield return endHeader; } - - throw new ArchiveException("Failed to locate the Zip Header"); - } - - internal LocalEntryHeader GetLocalHeader( - Stream stream, - DirectoryEntryHeader directoryEntryHeader - ) - { - stream.Seek(directoryEntryHeader.RelativeOffsetOfEntryHeader, SeekOrigin.Begin); - BinaryReader reader = new BinaryReader(stream); - uint signature = reader.ReadUInt32(); - var localEntryHeader = ReadHeader(signature, reader, _zip64) as LocalEntryHeader; - if (localEntryHeader is null) - { - throw new InvalidOperationException(); - } - return localEntryHeader; } } + + private static bool IsMatch(byte[] haystack, int position, byte[] needle) + { + for (var i = 0; i < needle.Length; i++) + { + if (haystack[position + i] != needle[i]) + { + return false; + } + } + + return true; + } + + private static void SeekBackToHeader(Stream stream, BinaryReader reader) + { + // Minimum EOCD length + if (stream.Length < MINIMUM_EOCD_LENGTH) + { + throw new ArchiveException( + "Could not find Zip file Directory at the end of the file. File may be corrupted." + ); + } + + var len = + stream.Length < MAX_SEARCH_LENGTH_FOR_EOCD + ? (int)stream.Length + : MAX_SEARCH_LENGTH_FOR_EOCD; + // We search for marker in reverse to find the first occurance + byte[] needle = { 0x06, 0x05, 0x4b, 0x50 }; + + stream.Seek(-len, SeekOrigin.End); + + var seek = reader.ReadBytes(len); + + // Search in reverse + Array.Reverse(seek); + + // don't exclude the minimum eocd region, otherwise you fail to locate the header in empty zip files + var max_search_area = len; // - MINIMUM_EOCD_LENGTH; + + for (var pos_from_end = 0; pos_from_end < max_search_area; ++pos_from_end) + { + if (IsMatch(seek, pos_from_end, needle)) + { + stream.Seek(-pos_from_end, SeekOrigin.End); + return; + } + } + + throw new ArchiveException("Failed to locate the Zip Header"); + } + + internal LocalEntryHeader GetLocalHeader( + Stream stream, + DirectoryEntryHeader directoryEntryHeader + ) + { + stream.Seek(directoryEntryHeader.RelativeOffsetOfEntryHeader, SeekOrigin.Begin); + var reader = new BinaryReader(stream); + var signature = reader.ReadUInt32(); + if (ReadHeader(signature, reader, _zip64) is not LocalEntryHeader localEntryHeader) + { + throw new InvalidOperationException(); + } + return localEntryHeader; + } } diff --git a/src/SharpCompress/Common/Zip/StreamingZipFilePart.cs b/src/SharpCompress/Common/Zip/StreamingZipFilePart.cs index 4dabc14d..1aaffe81 100644 --- a/src/SharpCompress/Common/Zip/StreamingZipFilePart.cs +++ b/src/SharpCompress/Common/Zip/StreamingZipFilePart.cs @@ -3,100 +3,99 @@ using SharpCompress.Common.Zip.Headers; using SharpCompress.Compressors.Deflate; using SharpCompress.IO; -namespace SharpCompress.Common.Zip +namespace SharpCompress.Common.Zip; + +internal sealed class StreamingZipFilePart : ZipFilePart { - internal sealed class StreamingZipFilePart : ZipFilePart + private Stream? _decompressionStream; + + internal StreamingZipFilePart(ZipFileEntry header, Stream stream) : base(header, stream) { } + + protected override Stream CreateBaseStream() { - private Stream? _decompressionStream; + return Header.PackedStream; + } - internal StreamingZipFilePart(ZipFileEntry header, Stream stream) : base(header, stream) { } - - protected override Stream CreateBaseStream() + internal override Stream GetCompressedStream() + { + if (!Header.HasData) { - return Header.PackedStream; + return Stream.Null; } - - internal override Stream GetCompressedStream() + _decompressionStream = CreateDecompressionStream( + GetCryptoStream(CreateBaseStream()), + Header.CompressionMethod + ); + if (LeaveStreamOpen) { - if (!Header.HasData) - { - return Stream.Null; - } - _decompressionStream = CreateDecompressionStream( - GetCryptoStream(CreateBaseStream()), - Header.CompressionMethod - ); - if (LeaveStreamOpen) - { - return NonDisposingStream.Create(_decompressionStream); - } - return _decompressionStream; + return NonDisposingStream.Create(_decompressionStream); } + return _decompressionStream; + } - internal BinaryReader FixStreamedFileLocation(ref RewindableStream rewindableStream) + internal BinaryReader FixStreamedFileLocation(ref RewindableStream rewindableStream) + { + if (Header.IsDirectory) { - if (Header.IsDirectory) - { - return new BinaryReader(rewindableStream); - } - if (Header.HasData && !Skipped) - { - _decompressionStream ??= GetCompressedStream(); + return new BinaryReader(rewindableStream); + } + if (Header.HasData && !Skipped) + { + _decompressionStream ??= GetCompressedStream(); - if (Header.CompressionMethod != ZipCompressionMethod.None) + if (Header.CompressionMethod != ZipCompressionMethod.None) + { + _decompressionStream.Skip(); + + // If we had TotalIn / TotalOut we could have used them + Header.CompressedSize = _decompressionStream.Position; + + if (_decompressionStream is DeflateStream deflateStream) { - _decompressionStream.Skip(); - - // If we had TotalIn / TotalOut we could have used them - Header.CompressedSize = _decompressionStream.Position; - - if (_decompressionStream is DeflateStream deflateStream) - { - rewindableStream.Rewind(deflateStream.InputBuffer); - } + rewindableStream.Rewind(deflateStream.InputBuffer); } - else - { - // We would need to search for the magic word - rewindableStream.Position -= 4; - var pos = rewindableStream.Position; - while (Utility.Find(rewindableStream, new byte[] { 0x50, 0x4b, 0x07, 0x08 })) - { - // We should probably check CRC32 for positive matching as well - var size = rewindableStream.Position - pos; - var br = new BinaryReader(rewindableStream); - br.ReadUInt32(); - br.ReadUInt32(); // CRC32 - var compressed_size = br.ReadUInt32(); - var uncompressed_size = br.ReadUInt32(); - var uncompressed_64bit = br.ReadInt64(); - - long test_64bit = (long)uncompressed_size << 32 | (long)compressed_size; - - if (test_64bit == size && test_64bit == uncompressed_64bit) - { - Header.CompressedSize = test_64bit; - Header.UncompressedSize = uncompressed_64bit; - rewindableStream.Position -= 24; - break; - } - - if (compressed_size == size && compressed_size == uncompressed_size) - { - Header.CompressedSize = compressed_size; - Header.UncompressedSize = uncompressed_size; - rewindableStream.Position -= 24; - break; - } - rewindableStream.Position -= 20; - } - } - - Skipped = true; } - var reader = new BinaryReader(rewindableStream); - _decompressionStream = null; - return reader; + else + { + // We would need to search for the magic word + rewindableStream.Position -= 4; + var pos = rewindableStream.Position; + while (Utility.Find(rewindableStream, new byte[] { 0x50, 0x4b, 0x07, 0x08 })) + { + // We should probably check CRC32 for positive matching as well + var size = rewindableStream.Position - pos; + var br = new BinaryReader(rewindableStream); + br.ReadUInt32(); + br.ReadUInt32(); // CRC32 + var compressed_size = br.ReadUInt32(); + var uncompressed_size = br.ReadUInt32(); + var uncompressed_64bit = br.ReadInt64(); + + var test_64bit = ((long)uncompressed_size << 32) | compressed_size; + + if (test_64bit == size && test_64bit == uncompressed_64bit) + { + Header.CompressedSize = test_64bit; + Header.UncompressedSize = uncompressed_64bit; + rewindableStream.Position -= 24; + break; + } + + if (compressed_size == size && compressed_size == uncompressed_size) + { + Header.CompressedSize = compressed_size; + Header.UncompressedSize = uncompressed_size; + rewindableStream.Position -= 24; + break; + } + rewindableStream.Position -= 20; + } + } + + Skipped = true; } + var reader = new BinaryReader(rewindableStream); + _decompressionStream = null; + return reader; } } diff --git a/src/SharpCompress/Common/Zip/StreamingZipHeaderFactory.cs b/src/SharpCompress/Common/Zip/StreamingZipHeaderFactory.cs index 620e3885..485ad901 100644 --- a/src/SharpCompress/Common/Zip/StreamingZipHeaderFactory.cs +++ b/src/SharpCompress/Common/Zip/StreamingZipHeaderFactory.cs @@ -3,118 +3,117 @@ using System.IO; using SharpCompress.Common.Zip.Headers; using SharpCompress.IO; -namespace SharpCompress.Common.Zip +namespace SharpCompress.Common.Zip; + +internal class StreamingZipHeaderFactory : ZipHeaderFactory { - internal class StreamingZipHeaderFactory : ZipHeaderFactory + internal StreamingZipHeaderFactory(string? password, ArchiveEncoding archiveEncoding) + : base(StreamingMode.Streaming, password, archiveEncoding) { } + + internal IEnumerable ReadStreamHeader(Stream stream) { - internal StreamingZipHeaderFactory(string? password, ArchiveEncoding archiveEncoding) - : base(StreamingMode.Streaming, password, archiveEncoding) { } + RewindableStream rewindableStream; - internal IEnumerable ReadStreamHeader(Stream stream) + if (stream is RewindableStream rs) { - RewindableStream rewindableStream; - - if (stream is RewindableStream rs) - { - rewindableStream = rs; - } - else - { - rewindableStream = new RewindableStream(stream); - } - while (true) - { - ZipHeader? header; - BinaryReader reader = new BinaryReader(rewindableStream); - uint headerBytes = 0; - if ( - _lastEntryHeader != null - && ( - FlagUtility.HasFlag( - _lastEntryHeader.Flags, - HeaderFlags.UsePostDataDescriptor - ) || _lastEntryHeader.IsZip64 - ) + rewindableStream = rs; + } + else + { + rewindableStream = new RewindableStream(stream); + } + while (true) + { + ZipHeader? header; + var reader = new BinaryReader(rewindableStream); + uint headerBytes = 0; + if ( + _lastEntryHeader != null + && ( + FlagUtility.HasFlag( + _lastEntryHeader.Flags, + HeaderFlags.UsePostDataDescriptor + ) || _lastEntryHeader.IsZip64 ) + ) + { + reader = ((StreamingZipFilePart)_lastEntryHeader.Part).FixStreamedFileLocation( + ref rewindableStream + ); + var pos = rewindableStream.CanSeek ? (long?)rewindableStream.Position : null; + var crc = reader.ReadUInt32(); + if (crc == POST_DATA_DESCRIPTOR) { - reader = ((StreamingZipFilePart)_lastEntryHeader.Part).FixStreamedFileLocation( - ref rewindableStream - ); - long? pos = rewindableStream.CanSeek ? (long?)rewindableStream.Position : null; - uint crc = reader.ReadUInt32(); - if (crc == POST_DATA_DESCRIPTOR) - { - crc = reader.ReadUInt32(); - } - _lastEntryHeader.Crc = crc; + crc = reader.ReadUInt32(); + } + _lastEntryHeader.Crc = crc; - // The DataDescriptor can be either 64bit or 32bit - var compressed_size = reader.ReadUInt32(); - var uncompressed_size = reader.ReadUInt32(); + // 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 + // Check if we have header or 64bit DataDescriptor + headerBytes = reader.ReadUInt32(); + 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(); - bool test_header = !(headerBytes == 0x04034b50 || headerBytes == 0x02014b50); - - long test_64bit = (long)uncompressed_size << 32 | (long)compressed_size; - if (test_64bit == _lastEntryHeader.CompressedSize && test_header) - { - _lastEntryHeader.UncompressedSize = - (long)reader.ReadUInt32() << 32 | (long)headerBytes; - headerBytes = reader.ReadUInt32(); - } - else - { - _lastEntryHeader.UncompressedSize = uncompressed_size; - } - - if (pos.HasValue) - { - _lastEntryHeader.DataStartPosition = pos - _lastEntryHeader.CompressedSize; - } } else { - headerBytes = reader.ReadUInt32(); + _lastEntryHeader.UncompressedSize = uncompressed_size; } - _lastEntryHeader = null; - header = ReadHeader(headerBytes, reader); - if (header is null) + if (pos.HasValue) { - yield break; + _lastEntryHeader.DataStartPosition = pos - _lastEntryHeader.CompressedSize; } - - //entry could be zero bytes so we need to know that. - if (header.ZipHeaderType == ZipHeaderType.LocalEntry) - { - var local_header = ((LocalEntryHeader)header); - - // If we have CompressedSize, there is data to be read - if (local_header.CompressedSize > 0) - { - header.HasData = true; - } // Check if zip is streaming ( Length is 0 and is declared in PostDataDescriptor ) - else if (local_header.Flags.HasFlag(HeaderFlags.UsePostDataDescriptor)) - { - bool isRecording = rewindableStream.IsRecording; - if (!isRecording) - { - rewindableStream.StartRecording(); - } - uint nextHeaderBytes = reader.ReadUInt32(); - - // Check if next data is PostDataDescriptor, streamed file with 0 length - header.HasData = !IsHeader(nextHeaderBytes); - rewindableStream.Rewind(!isRecording); - } - else // We are not streaming and compressed size is 0, we have no data - { - header.HasData = false; - } - } - yield return header; } + else + { + headerBytes = reader.ReadUInt32(); + } + + _lastEntryHeader = null; + header = ReadHeader(headerBytes, reader); + if (header is null) + { + yield break; + } + + //entry could be zero bytes so we need to know that. + if (header.ZipHeaderType == ZipHeaderType.LocalEntry) + { + var local_header = ((LocalEntryHeader)header); + + // If we have CompressedSize, there is data to be read + if (local_header.CompressedSize > 0) + { + header.HasData = true; + } // Check if zip is streaming ( Length is 0 and is declared in PostDataDescriptor ) + else if (local_header.Flags.HasFlag(HeaderFlags.UsePostDataDescriptor)) + { + var isRecording = rewindableStream.IsRecording; + if (!isRecording) + { + rewindableStream.StartRecording(); + } + var nextHeaderBytes = reader.ReadUInt32(); + + // Check if next data is PostDataDescriptor, streamed file with 0 length + header.HasData = !IsHeader(nextHeaderBytes); + rewindableStream.Rewind(!isRecording); + } + else // We are not streaming and compressed size is 0, we have no data + { + header.HasData = false; + } + } + yield return header; } } } diff --git a/src/SharpCompress/Common/Zip/WinzipAesCryptoStream.cs b/src/SharpCompress/Common/Zip/WinzipAesCryptoStream.cs index 00345a47..4425af1d 100644 --- a/src/SharpCompress/Common/Zip/WinzipAesCryptoStream.cs +++ b/src/SharpCompress/Common/Zip/WinzipAesCryptoStream.cs @@ -3,180 +3,179 @@ using System.Buffers.Binary; using System.IO; using System.Security.Cryptography; -namespace SharpCompress.Common.Zip +namespace SharpCompress.Common.Zip; + +internal class WinzipAesCryptoStream : Stream { - internal class WinzipAesCryptoStream : Stream + private const int BLOCK_SIZE_IN_BYTES = 16; + private readonly SymmetricAlgorithm _cipher; + private readonly byte[] _counter = new byte[BLOCK_SIZE_IN_BYTES]; + private readonly Stream _stream; + private readonly ICryptoTransform _transform; + private int _nonce = 1; + private byte[] _counterOut = new byte[BLOCK_SIZE_IN_BYTES]; + private bool _isFinalBlock; + private long _totalBytesLeftToRead; + private bool _isDisposed; + + internal WinzipAesCryptoStream( + Stream stream, + WinzipAesEncryptionData winzipAesEncryptionData, + long length + ) { - private const int BLOCK_SIZE_IN_BYTES = 16; - private readonly SymmetricAlgorithm _cipher; - private readonly byte[] _counter = new byte[BLOCK_SIZE_IN_BYTES]; - private readonly Stream _stream; - private readonly ICryptoTransform _transform; - private int _nonce = 1; - private byte[] _counterOut = new byte[BLOCK_SIZE_IN_BYTES]; - private bool _isFinalBlock; - private long _totalBytesLeftToRead; - private bool _isDisposed; + _stream = stream; + _totalBytesLeftToRead = length; - internal WinzipAesCryptoStream( - Stream stream, - WinzipAesEncryptionData winzipAesEncryptionData, - long length - ) + _cipher = CreateCipher(winzipAesEncryptionData); + + var iv = new byte[BLOCK_SIZE_IN_BYTES]; + _transform = _cipher.CreateEncryptor(winzipAesEncryptionData.KeyBytes, iv); + } + + private SymmetricAlgorithm CreateCipher(WinzipAesEncryptionData winzipAesEncryptionData) + { + var cipher = Aes.Create(); + cipher.BlockSize = BLOCK_SIZE_IN_BYTES * 8; + cipher.KeySize = winzipAesEncryptionData.KeyBytes.Length * 8; + cipher.Mode = CipherMode.ECB; + cipher.Padding = PaddingMode.None; + return cipher; + } + + public override bool CanRead + { + get { return true; } + } + + public override bool CanSeek + { + get { return false; } + } + + public override bool CanWrite + { + get { return false; } + } + + public override long Length + { + get { throw new NotSupportedException(); } + } + + public override long Position + { + get { throw new NotSupportedException(); } + set { throw new NotSupportedException(); } + } + + protected override void Dispose(bool disposing) + { + if (_isDisposed) { - this._stream = stream; - _totalBytesLeftToRead = length; - - _cipher = CreateCipher(winzipAesEncryptionData); - - var iv = new byte[BLOCK_SIZE_IN_BYTES]; - _transform = _cipher.CreateEncryptor(winzipAesEncryptionData.KeyBytes, iv); + return; } - - private SymmetricAlgorithm CreateCipher(WinzipAesEncryptionData winzipAesEncryptionData) + _isDisposed = true; + if (disposing) { - var cipher = Aes.Create(); - cipher.BlockSize = BLOCK_SIZE_IN_BYTES * 8; - cipher.KeySize = winzipAesEncryptionData.KeyBytes.Length * 8; - cipher.Mode = CipherMode.ECB; - cipher.Padding = PaddingMode.None; - return cipher; - } - - public override bool CanRead - { - get { return true; } - } - - public override bool CanSeek - { - get { return false; } - } - - public override bool CanWrite - { - get { return false; } - } - - public override long Length - { - get { throw new NotSupportedException(); } - } - - public override long Position - { - get { throw new NotSupportedException(); } - set { throw new NotSupportedException(); } - } - - protected override void Dispose(bool disposing) - { - if (_isDisposed) - { - return; - } - _isDisposed = true; - if (disposing) - { - //read out last 10 auth bytes - Span ten = stackalloc byte[10]; - _stream.ReadFully(ten); - _stream.Dispose(); - } - } - - public override void Flush() - { - throw new NotSupportedException(); - } - - public override int Read(byte[] buffer, int offset, int count) - { - if (_totalBytesLeftToRead == 0) - { - return 0; - } - int bytesToRead = count; - if (count > _totalBytesLeftToRead) - { - bytesToRead = (int)_totalBytesLeftToRead; - } - int read = _stream.Read(buffer, offset, bytesToRead); - _totalBytesLeftToRead -= read; - - ReadTransformBlocks(buffer, offset, read); - - return read; - } - - private int ReadTransformOneBlock(byte[] buffer, int offset, int last) - { - if (_isFinalBlock) - { - throw new InvalidOperationException(); - } - - int bytesRemaining = last - offset; - int bytesToRead = - (bytesRemaining > BLOCK_SIZE_IN_BYTES) ? BLOCK_SIZE_IN_BYTES : bytesRemaining; - - // update the counter - BinaryPrimitives.WriteInt32LittleEndian(_counter, _nonce++); - - // Determine if this is the final block - if ((bytesToRead == bytesRemaining) && (_totalBytesLeftToRead == 0)) - { - _counterOut = _transform.TransformFinalBlock(_counter, 0, BLOCK_SIZE_IN_BYTES); - _isFinalBlock = true; - } - else - { - _transform.TransformBlock( - _counter, - 0, // offset - BLOCK_SIZE_IN_BYTES, - _counterOut, - 0 - ); // offset - } - - XorInPlace(buffer, offset, bytesToRead); - return bytesToRead; - } - - private void XorInPlace(byte[] buffer, int offset, int count) - { - for (int i = 0; i < count; i++) - { - buffer[offset + i] = (byte)(_counterOut[i] ^ buffer[offset + i]); - } - } - - private void ReadTransformBlocks(byte[] buffer, int offset, int count) - { - int posn = offset; - int last = count + offset; - - while (posn < buffer.Length && posn < last) - { - int n = ReadTransformOneBlock(buffer, posn, last); - posn += n; - } - } - - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } - - public override void SetLength(long value) - { - throw new NotSupportedException(); - } - - public override void Write(byte[] buffer, int offset, int count) - { - throw new NotSupportedException(); + //read out last 10 auth bytes + Span ten = stackalloc byte[10]; + _stream.ReadFully(ten); + _stream.Dispose(); } } + + public override void Flush() + { + throw new NotSupportedException(); + } + + public override int Read(byte[] buffer, int offset, int count) + { + if (_totalBytesLeftToRead == 0) + { + return 0; + } + var bytesToRead = count; + if (count > _totalBytesLeftToRead) + { + bytesToRead = (int)_totalBytesLeftToRead; + } + var read = _stream.Read(buffer, offset, bytesToRead); + _totalBytesLeftToRead -= read; + + ReadTransformBlocks(buffer, offset, read); + + return read; + } + + private int ReadTransformOneBlock(byte[] buffer, int offset, int last) + { + if (_isFinalBlock) + { + throw new InvalidOperationException(); + } + + var bytesRemaining = last - offset; + var bytesToRead = + (bytesRemaining > BLOCK_SIZE_IN_BYTES) ? BLOCK_SIZE_IN_BYTES : bytesRemaining; + + // update the counter + BinaryPrimitives.WriteInt32LittleEndian(_counter, _nonce++); + + // Determine if this is the final block + if ((bytesToRead == bytesRemaining) && (_totalBytesLeftToRead == 0)) + { + _counterOut = _transform.TransformFinalBlock(_counter, 0, BLOCK_SIZE_IN_BYTES); + _isFinalBlock = true; + } + else + { + _transform.TransformBlock( + _counter, + 0, // offset + BLOCK_SIZE_IN_BYTES, + _counterOut, + 0 + ); // offset + } + + XorInPlace(buffer, offset, bytesToRead); + return bytesToRead; + } + + private void XorInPlace(byte[] buffer, int offset, int count) + { + for (var i = 0; i < count; i++) + { + buffer[offset + i] = (byte)(_counterOut[i] ^ buffer[offset + i]); + } + } + + private void ReadTransformBlocks(byte[] buffer, int offset, int count) + { + var posn = offset; + var last = count + offset; + + while (posn < buffer.Length && posn < last) + { + var n = ReadTransformOneBlock(buffer, posn, last); + posn += n; + } + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } + + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + public override void Write(byte[] buffer, int offset, int count) + { + throw new NotSupportedException(); + } } diff --git a/src/SharpCompress/Common/Zip/WinzipAesEncryptionData.cs b/src/SharpCompress/Common/Zip/WinzipAesEncryptionData.cs index cd5314c4..ce31eed9 100644 --- a/src/SharpCompress/Common/Zip/WinzipAesEncryptionData.cs +++ b/src/SharpCompress/Common/Zip/WinzipAesEncryptionData.cs @@ -4,78 +4,77 @@ using System; using System.Buffers.Binary; using System.Security.Cryptography; -namespace SharpCompress.Common.Zip +namespace SharpCompress.Common.Zip; + +internal class WinzipAesEncryptionData { - 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, + byte[] salt, + byte[] passwordVerifyValue, + string password + ) { - private const int RFC2898_ITERATIONS = 1000; + _keySize = keySize; + _salt = salt; + _passwordVerifyValue = passwordVerifyValue; + _password = password; + Initialize(); + } - private readonly byte[] _salt; - private readonly WinzipAesKeySize _keySize; - private readonly byte[] _passwordVerifyValue; - private readonly string _password; + internal byte[] IvBytes { get; set; } - private byte[] _generatedVerifyValue; + internal byte[] KeyBytes { get; set; } - internal WinzipAesEncryptionData( - WinzipAesKeySize keySize, - byte[] salt, - byte[] passwordVerifyValue, - string password - ) + private int KeySizeInBytes + { + get { return KeyLengthInBytes(_keySize); } + } + + internal static int KeyLengthInBytes(WinzipAesKeySize keySize) + { + return keySize switch { - this._keySize = keySize; - this._salt = salt; - this._passwordVerifyValue = passwordVerifyValue; - this._password = password; - Initialize(); - } + WinzipAesKeySize.KeySize128 => 16, + WinzipAesKeySize.KeySize192 => 24, + WinzipAesKeySize.KeySize256 => 32, + _ => throw new InvalidOperationException(), + }; + } - internal byte[] IvBytes { get; set; } - - internal byte[] KeyBytes { get; set; } - - private int KeySizeInBytes - { - get { return KeyLengthInBytes(_keySize); } - } - - internal static int KeyLengthInBytes(WinzipAesKeySize keySize) - { - return keySize switch - { - WinzipAesKeySize.KeySize128 => 16, - WinzipAesKeySize.KeySize192 => 24, - WinzipAesKeySize.KeySize256 => 32, - _ => throw new InvalidOperationException(), - }; - } - - private void Initialize() - { + private void Initialize() + { #if NET7_0 - var rfc2898 = new Rfc2898DeriveBytes( - _password, - _salt, - RFC2898_ITERATIONS, - HashAlgorithmName.SHA1 - ); + var rfc2898 = new Rfc2898DeriveBytes( + _password, + _salt, + RFC2898_ITERATIONS, + HashAlgorithmName.SHA1 + ); #else - var rfc2898 = new Rfc2898DeriveBytes(_password, _salt, RFC2898_ITERATIONS); + 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); + KeyBytes = rfc2898.GetBytes(KeySizeInBytes); // 16 or 24 or 32 ??? + IvBytes = rfc2898.GetBytes(KeySizeInBytes); + _generatedVerifyValue = rfc2898.GetBytes(2); - short verify = BinaryPrimitives.ReadInt16LittleEndian(_passwordVerifyValue); - if (_password != null) + var verify = BinaryPrimitives.ReadInt16LittleEndian(_passwordVerifyValue); + if (_password != null) + { + var generated = BinaryPrimitives.ReadInt16LittleEndian(_generatedVerifyValue); + if (verify != generated) { - short generated = BinaryPrimitives.ReadInt16LittleEndian(_generatedVerifyValue); - if (verify != generated) - { - throw new InvalidFormatException("bad password"); - } + throw new InvalidFormatException("bad password"); } } } diff --git a/src/SharpCompress/Common/Zip/WinzipAesKeySize.cs b/src/SharpCompress/Common/Zip/WinzipAesKeySize.cs index 07602338..7772bcaa 100644 --- a/src/SharpCompress/Common/Zip/WinzipAesKeySize.cs +++ b/src/SharpCompress/Common/Zip/WinzipAesKeySize.cs @@ -1,9 +1,8 @@ -namespace SharpCompress.Common.Zip +namespace SharpCompress.Common.Zip; + +internal enum WinzipAesKeySize { - internal enum WinzipAesKeySize - { - KeySize128 = 1, - KeySize192 = 2, - KeySize256 = 3 - } + KeySize128 = 1, + KeySize192 = 2, + KeySize256 = 3 } diff --git a/src/SharpCompress/Common/Zip/ZipCompressionMethod.cs b/src/SharpCompress/Common/Zip/ZipCompressionMethod.cs index 87135269..599b1ee1 100644 --- a/src/SharpCompress/Common/Zip/ZipCompressionMethod.cs +++ b/src/SharpCompress/Common/Zip/ZipCompressionMethod.cs @@ -1,13 +1,12 @@ -namespace SharpCompress.Common.Zip +namespace SharpCompress.Common.Zip; + +internal enum ZipCompressionMethod { - internal enum ZipCompressionMethod - { - None = 0, - Deflate = 8, - Deflate64 = 9, - BZip2 = 12, - LZMA = 14, - PPMd = 98, - WinzipAes = 0x63 //http://www.winzip.com/aes_info.htm - } + None = 0, + Deflate = 8, + Deflate64 = 9, + BZip2 = 12, + LZMA = 14, + PPMd = 98, + WinzipAes = 0x63 //http://www.winzip.com/aes_info.htm } diff --git a/src/SharpCompress/Common/Zip/ZipEntry.cs b/src/SharpCompress/Common/Zip/ZipEntry.cs index f77f397d..2c544b94 100644 --- a/src/SharpCompress/Common/Zip/ZipEntry.cs +++ b/src/SharpCompress/Common/Zip/ZipEntry.cs @@ -1,90 +1,89 @@ -#nullable disable +#nullable disable using System; using System.Collections.Generic; using SharpCompress.Common.Zip.Headers; -namespace SharpCompress.Common.Zip +namespace SharpCompress.Common.Zip; + +public class ZipEntry : Entry { - public class ZipEntry : Entry + private readonly ZipFilePart _filePart; + + internal ZipEntry(ZipFilePart filePart) { - private readonly ZipFilePart _filePart; - - internal ZipEntry(ZipFilePart filePart) + if (filePart != null) { - if (filePart != null) - { - this._filePart = filePart; - LastModifiedTime = Utility.DosDateToDateTime( - filePart.Header.LastModifiedDate, - filePart.Header.LastModifiedTime - ); - } + _filePart = filePart; + LastModifiedTime = Utility.DosDateToDateTime( + filePart.Header.LastModifiedDate, + filePart.Header.LastModifiedTime + ); } + } - public override CompressionType CompressionType + public override CompressionType CompressionType + { + get { - get + switch (_filePart.Header.CompressionMethod) { - switch (_filePart.Header.CompressionMethod) + case ZipCompressionMethod.BZip2: { - 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; - } + 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; } } } - - public override long Crc => _filePart.Header.Crc; - - public override string Key => _filePart.Header.Name; - - public override string LinkTarget => null; - - public override long CompressedSize => _filePart.Header.CompressedSize; - - public override long Size => _filePart.Header.UncompressedSize; - - public override DateTime? LastModifiedTime { get; } - - public override DateTime? CreatedTime => null; - - public override DateTime? LastAccessedTime => null; - - public override DateTime? ArchivedTime => null; - - public override bool IsEncrypted => - FlagUtility.HasFlag(_filePart.Header.Flags, HeaderFlags.Encrypted); - - public override bool IsDirectory => _filePart.Header.IsDirectory; - - public override bool IsSplitAfter => false; - - internal override IEnumerable Parts => _filePart.AsEnumerable(); } + + public override long Crc => _filePart.Header.Crc; + + public override string Key => _filePart.Header.Name; + + public override string LinkTarget => null; + + public override long CompressedSize => _filePart.Header.CompressedSize; + + public override long Size => _filePart.Header.UncompressedSize; + + public override DateTime? LastModifiedTime { get; } + + public override DateTime? CreatedTime => null; + + public override DateTime? LastAccessedTime => null; + + public override DateTime? ArchivedTime => null; + + public override bool IsEncrypted => + FlagUtility.HasFlag(_filePart.Header.Flags, HeaderFlags.Encrypted); + + public override bool IsDirectory => _filePart.Header.IsDirectory; + + public override bool IsSplitAfter => false; + + internal override IEnumerable Parts => _filePart.AsEnumerable(); } diff --git a/src/SharpCompress/Common/Zip/ZipFilePart.cs b/src/SharpCompress/Common/Zip/ZipFilePart.cs index c87ac3f1..54c64d16 100644 --- a/src/SharpCompress/Common/Zip/ZipFilePart.cs +++ b/src/SharpCompress/Common/Zip/ZipFilePart.cs @@ -11,207 +11,206 @@ using SharpCompress.Compressors.LZMA; using SharpCompress.Compressors.PPMd; using SharpCompress.IO; -namespace SharpCompress.Common.Zip +namespace SharpCompress.Common.Zip; + +internal abstract class ZipFilePart : FilePart { - internal abstract class ZipFilePart : FilePart + internal ZipFilePart(ZipFileEntry header, Stream stream) : base(header.ArchiveEncoding) { - internal ZipFilePart(ZipFileEntry header, Stream stream) : base(header.ArchiveEncoding) + Header = header; + header.Part = this; + BaseStream = stream; + } + + internal Stream BaseStream { get; } + internal ZipFileEntry Header { get; set; } + + internal override string FilePartName => Header.Name; + + internal override Stream GetCompressedStream() + { + if (!Header.HasData) { - Header = header; - header.Part = this; - BaseStream = stream; + return Stream.Null; } - - internal Stream BaseStream { get; } - internal ZipFileEntry Header { get; set; } - - internal override string FilePartName => Header.Name; - - internal override Stream GetCompressedStream() + var decompressionStream = CreateDecompressionStream( + GetCryptoStream(CreateBaseStream()), + Header.CompressionMethod + ); + if (LeaveStreamOpen) { - if (!Header.HasData) - { - return Stream.Null; - } - Stream decompressionStream = CreateDecompressionStream( - GetCryptoStream(CreateBaseStream()), - Header.CompressionMethod - ); - if (LeaveStreamOpen) - { - return NonDisposingStream.Create(decompressionStream); - } - return decompressionStream; + return NonDisposingStream.Create(decompressionStream); } + return decompressionStream; + } - internal override Stream GetRawStream() + internal override Stream GetRawStream() + { + if (!Header.HasData) { - if (!Header.HasData) - { - return Stream.Null; - } - return CreateBaseStream(); + return Stream.Null; } + return CreateBaseStream(); + } - protected abstract Stream CreateBaseStream(); + protected abstract Stream CreateBaseStream(); - protected bool LeaveStreamOpen => - FlagUtility.HasFlag(Header.Flags, HeaderFlags.UsePostDataDescriptor) || Header.IsZip64; + protected bool LeaveStreamOpen => + FlagUtility.HasFlag(Header.Flags, HeaderFlags.UsePostDataDescriptor) || Header.IsZip64; - protected Stream CreateDecompressionStream(Stream stream, ZipCompressionMethod method) + protected Stream CreateDecompressionStream(Stream stream, ZipCompressionMethod method) + { + switch (method) { - switch (method) + case ZipCompressionMethod.None: { - case ZipCompressionMethod.None: - { - return stream; - } - case ZipCompressionMethod.Deflate: - { - return new DeflateStream(stream, CompressionMode.Decompress); - } - case ZipCompressionMethod.Deflate64: - { - return new Deflate64Stream(stream, CompressionMode.Decompress); - } - case ZipCompressionMethod.BZip2: - { - return new BZip2Stream(stream, CompressionMode.Decompress, false); - } - case ZipCompressionMethod.LZMA: - { - if (FlagUtility.HasFlag(Header.Flags, HeaderFlags.Encrypted)) - { - throw new NotSupportedException("LZMA with pkware encryption."); - } - var reader = new BinaryReader(stream); - reader.ReadUInt16(); //LZMA version - var props = new byte[reader.ReadUInt16()]; - reader.Read(props, 0, props.Length); - return new LzmaStream( - props, - stream, - Header.CompressedSize > 0 ? Header.CompressedSize - 4 - props.Length : -1, - FlagUtility.HasFlag(Header.Flags, HeaderFlags.Bit1) - ? -1 - : (long)Header.UncompressedSize - ); - } - case ZipCompressionMethod.PPMd: - { - Span props = stackalloc byte[2]; - stream.ReadFully(props); - return new PpmdStream(new PpmdProperties(props), stream, false); - } - case ZipCompressionMethod.WinzipAes: - { - ExtraData? data = Header.Extra.SingleOrDefault( - x => x.Type == ExtraDataType.WinZipAes - ); - if (data is null) - { - throw new InvalidFormatException("No Winzip AES extra data found."); - } - if (data.Length != 7) - { - throw new InvalidFormatException("Winzip data length is not 7."); - } - ushort compressedMethod = BinaryPrimitives.ReadUInt16LittleEndian( - data.DataBytes - ); - - if (compressedMethod != 0x01 && compressedMethod != 0x02) - { - throw new InvalidFormatException( - "Unexpected vendor version number for WinZip AES metadata" - ); - } - - ushort vendorId = BinaryPrimitives.ReadUInt16LittleEndian( - data.DataBytes.AsSpan(2) - ); - if (vendorId != 0x4541) - { - throw new InvalidFormatException( - "Unexpected vendor ID for WinZip AES metadata" - ); - } - return CreateDecompressionStream( - stream, - (ZipCompressionMethod) - BinaryPrimitives.ReadUInt16LittleEndian(data.DataBytes.AsSpan(5)) - ); - } - default: - { - throw new NotSupportedException( - "CompressionMethod: " + Header.CompressionMethod - ); - } + return stream; } - } - - protected Stream GetCryptoStream(Stream plainStream) - { - bool isFileEncrypted = FlagUtility.HasFlag(Header.Flags, HeaderFlags.Encrypted); - - if (Header.CompressedSize == 0 && isFileEncrypted) + case ZipCompressionMethod.Deflate: { - throw new NotSupportedException("Cannot encrypt file with unknown size at start."); + return new DeflateStream(stream, CompressionMode.Decompress); } - - if ( - ( - Header.CompressedSize == 0 - && FlagUtility.HasFlag(Header.Flags, HeaderFlags.UsePostDataDescriptor) - ) || Header.IsZip64 - ) + case ZipCompressionMethod.Deflate64: { - plainStream = NonDisposingStream.Create(plainStream); //make sure AES doesn't close + return new Deflate64Stream(stream, CompressionMode.Decompress); } - else + case ZipCompressionMethod.BZip2: { - plainStream = new ReadOnlySubStream(plainStream, Header.CompressedSize); //make sure AES doesn't close + return new BZip2Stream(stream, CompressionMode.Decompress, false); } - - if (isFileEncrypted) + case ZipCompressionMethod.LZMA: { - switch (Header.CompressionMethod) + if (FlagUtility.HasFlag(Header.Flags, HeaderFlags.Encrypted)) { - case ZipCompressionMethod.None: - case ZipCompressionMethod.Deflate: - case ZipCompressionMethod.Deflate64: - case ZipCompressionMethod.BZip2: - case ZipCompressionMethod.LZMA: - case ZipCompressionMethod.PPMd: - { - return new PkwareTraditionalCryptoStream( - plainStream, - Header.ComposeEncryptionData(plainStream), - CryptoMode.Decrypt - ); - } - - case ZipCompressionMethod.WinzipAes: - { - if (Header.WinzipAesEncryptionData != null) - { - return new WinzipAesCryptoStream( - plainStream, - Header.WinzipAesEncryptionData, - Header.CompressedSize - 10 - ); - } - return plainStream; - } - - default: - { - throw new InvalidOperationException("Header.CompressionMethod is invalid"); - } + throw new NotSupportedException("LZMA with pkware encryption."); } + var reader = new BinaryReader(stream); + reader.ReadUInt16(); //LZMA version + var props = new byte[reader.ReadUInt16()]; + reader.Read(props, 0, props.Length); + return new LzmaStream( + props, + stream, + Header.CompressedSize > 0 ? Header.CompressedSize - 4 - props.Length : -1, + FlagUtility.HasFlag(Header.Flags, HeaderFlags.Bit1) + ? -1 + : Header.UncompressedSize + ); + } + case ZipCompressionMethod.PPMd: + { + Span props = stackalloc byte[2]; + stream.ReadFully(props); + return new PpmdStream(new PpmdProperties(props), stream, false); + } + case ZipCompressionMethod.WinzipAes: + { + var data = Header.Extra.SingleOrDefault( + x => x.Type == ExtraDataType.WinZipAes + ); + if (data is null) + { + throw new InvalidFormatException("No Winzip AES extra data found."); + } + if (data.Length != 7) + { + throw new InvalidFormatException("Winzip data length is not 7."); + } + var compressedMethod = BinaryPrimitives.ReadUInt16LittleEndian( + data.DataBytes + ); + + if (compressedMethod != 0x01 && compressedMethod != 0x02) + { + throw new InvalidFormatException( + "Unexpected vendor version number for WinZip AES metadata" + ); + } + + var vendorId = BinaryPrimitives.ReadUInt16LittleEndian( + data.DataBytes.AsSpan(2) + ); + if (vendorId != 0x4541) + { + throw new InvalidFormatException( + "Unexpected vendor ID for WinZip AES metadata" + ); + } + return CreateDecompressionStream( + stream, + (ZipCompressionMethod) + BinaryPrimitives.ReadUInt16LittleEndian(data.DataBytes.AsSpan(5)) + ); + } + default: + { + throw new NotSupportedException( + "CompressionMethod: " + Header.CompressionMethod + ); } - return plainStream; } } + + protected Stream GetCryptoStream(Stream plainStream) + { + var isFileEncrypted = FlagUtility.HasFlag(Header.Flags, HeaderFlags.Encrypted); + + if (Header.CompressedSize == 0 && isFileEncrypted) + { + throw new NotSupportedException("Cannot encrypt file with unknown size at start."); + } + + if ( + ( + Header.CompressedSize == 0 + && FlagUtility.HasFlag(Header.Flags, HeaderFlags.UsePostDataDescriptor) + ) || Header.IsZip64 + ) + { + plainStream = NonDisposingStream.Create(plainStream); //make sure AES doesn't close + } + else + { + plainStream = new ReadOnlySubStream(plainStream, Header.CompressedSize); //make sure AES doesn't close + } + + if (isFileEncrypted) + { + switch (Header.CompressionMethod) + { + case ZipCompressionMethod.None: + case ZipCompressionMethod.Deflate: + case ZipCompressionMethod.Deflate64: + case ZipCompressionMethod.BZip2: + case ZipCompressionMethod.LZMA: + case ZipCompressionMethod.PPMd: + { + return new PkwareTraditionalCryptoStream( + plainStream, + Header.ComposeEncryptionData(plainStream), + CryptoMode.Decrypt + ); + } + + case ZipCompressionMethod.WinzipAes: + { + if (Header.WinzipAesEncryptionData != null) + { + return new WinzipAesCryptoStream( + plainStream, + Header.WinzipAesEncryptionData, + Header.CompressedSize - 10 + ); + } + return plainStream; + } + + default: + { + throw new InvalidOperationException("Header.CompressionMethod is invalid"); + } + } + } + return plainStream; + } } diff --git a/src/SharpCompress/Common/Zip/ZipHeaderFactory.cs b/src/SharpCompress/Common/Zip/ZipHeaderFactory.cs index bc490c7e..e7737cec 100644 --- a/src/SharpCompress/Common/Zip/ZipHeaderFactory.cs +++ b/src/SharpCompress/Common/Zip/ZipHeaderFactory.cs @@ -1,208 +1,207 @@ -using System; +using System; using System.IO; using System.Linq; using SharpCompress.Common.Zip.Headers; using SharpCompress.IO; -namespace SharpCompress.Common.Zip +namespace SharpCompress.Common.Zip; + +internal class ZipHeaderFactory { - internal class ZipHeaderFactory + internal const uint ENTRY_HEADER_BYTES = 0x04034b50; + internal const uint POST_DATA_DESCRIPTOR = 0x08074b50; + internal const uint DIRECTORY_START_HEADER_BYTES = 0x02014b50; + internal const uint DIRECTORY_END_HEADER_BYTES = 0x06054b50; + internal const uint DIGITAL_SIGNATURE = 0x05054b50; + internal const uint SPLIT_ARCHIVE_HEADER_BYTES = 0x30304b50; + + internal const uint ZIP64_END_OF_CENTRAL_DIRECTORY = 0x06064b50; + internal const uint ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR = 0x07064b50; + + protected LocalEntryHeader? _lastEntryHeader; + private readonly string? _password; + private readonly StreamingMode _mode; + private readonly ArchiveEncoding _archiveEncoding; + + protected ZipHeaderFactory( + StreamingMode mode, + string? password, + ArchiveEncoding archiveEncoding + ) { - internal const uint ENTRY_HEADER_BYTES = 0x04034b50; - internal const uint POST_DATA_DESCRIPTOR = 0x08074b50; - internal const uint DIRECTORY_START_HEADER_BYTES = 0x02014b50; - internal const uint DIRECTORY_END_HEADER_BYTES = 0x06054b50; - internal const uint DIGITAL_SIGNATURE = 0x05054b50; - internal const uint SPLIT_ARCHIVE_HEADER_BYTES = 0x30304b50; + _mode = mode; + _password = password; + _archiveEncoding = archiveEncoding; + } - internal const uint ZIP64_END_OF_CENTRAL_DIRECTORY = 0x06064b50; - internal const uint ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR = 0x07064b50; - - protected LocalEntryHeader? _lastEntryHeader; - private readonly string? _password; - private readonly StreamingMode _mode; - private readonly ArchiveEncoding _archiveEncoding; - - protected ZipHeaderFactory( - StreamingMode mode, - string? password, - ArchiveEncoding archiveEncoding - ) + protected ZipHeader? ReadHeader(uint headerBytes, BinaryReader reader, bool zip64 = false) + { + switch (headerBytes) { - this._mode = mode; - this._password = password; - this._archiveEncoding = archiveEncoding; - } - - protected ZipHeader? ReadHeader(uint headerBytes, BinaryReader reader, bool zip64 = false) - { - switch (headerBytes) + case ENTRY_HEADER_BYTES: { - case ENTRY_HEADER_BYTES: - { - var entryHeader = new LocalEntryHeader(_archiveEncoding); - entryHeader.Read(reader); - LoadHeader(entryHeader, reader.BaseStream); + var entryHeader = new LocalEntryHeader(_archiveEncoding); + entryHeader.Read(reader); + LoadHeader(entryHeader, reader.BaseStream); - _lastEntryHeader = entryHeader; - return entryHeader; - } - case DIRECTORY_START_HEADER_BYTES: - { - var entry = new DirectoryEntryHeader(_archiveEncoding); - entry.Read(reader); - return entry; - } - case POST_DATA_DESCRIPTOR: - { - if ( - FlagUtility.HasFlag( - _lastEntryHeader!.Flags, - HeaderFlags.UsePostDataDescriptor - ) - ) - { - _lastEntryHeader.Crc = reader.ReadUInt32(); - _lastEntryHeader.CompressedSize = zip64 - ? (long)reader.ReadUInt64() - : reader.ReadUInt32(); - _lastEntryHeader.UncompressedSize = zip64 - ? (long)reader.ReadUInt64() - : reader.ReadUInt32(); - } - else - { - reader.ReadBytes(zip64 ? 20 : 12); - } - return null; - } - case DIGITAL_SIGNATURE: - return null; - case DIRECTORY_END_HEADER_BYTES: - { - var entry = new DirectoryEndHeader(); - entry.Read(reader); - return entry; - } - case SPLIT_ARCHIVE_HEADER_BYTES: - { - return new SplitHeader(); - } - case ZIP64_END_OF_CENTRAL_DIRECTORY: - { - var entry = new Zip64DirectoryEndHeader(); - entry.Read(reader); - return entry; - } - case ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR: - { - var entry = new Zip64DirectoryEndLocatorHeader(); - entry.Read(reader); - return entry; - } - default: - return null; + _lastEntryHeader = entryHeader; + return entryHeader; } - } - - internal static bool IsHeader(uint headerBytes) - { - switch (headerBytes) + case DIRECTORY_START_HEADER_BYTES: { - case ENTRY_HEADER_BYTES: - case DIRECTORY_START_HEADER_BYTES: - case POST_DATA_DESCRIPTOR: - case DIGITAL_SIGNATURE: - case DIRECTORY_END_HEADER_BYTES: - case SPLIT_ARCHIVE_HEADER_BYTES: - case ZIP64_END_OF_CENTRAL_DIRECTORY: - case ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR: - return true; - default: - return false; + var entry = new DirectoryEntryHeader(_archiveEncoding); + entry.Read(reader); + return entry; } - } - - private void LoadHeader(ZipFileEntry entryHeader, Stream stream) - { - if (FlagUtility.HasFlag(entryHeader.Flags, HeaderFlags.Encrypted)) + case POST_DATA_DESCRIPTOR: { if ( - !entryHeader.IsDirectory - && entryHeader.CompressedSize == 0 - && FlagUtility.HasFlag(entryHeader.Flags, HeaderFlags.UsePostDataDescriptor) + FlagUtility.HasFlag( + _lastEntryHeader!.Flags, + HeaderFlags.UsePostDataDescriptor + ) ) { - throw new NotSupportedException( - "SharpCompress cannot currently read non-seekable Zip Streams with encrypted data that has been written in a non-seekable manner." - ); + _lastEntryHeader.Crc = reader.ReadUInt32(); + _lastEntryHeader.CompressedSize = zip64 + ? (long)reader.ReadUInt64() + : reader.ReadUInt32(); + _lastEntryHeader.UncompressedSize = zip64 + ? (long)reader.ReadUInt64() + : reader.ReadUInt32(); } - - if (_password is null) + else { - throw new CryptographicException("No password supplied for encrypted zip."); - } - - entryHeader.Password = _password; - - if (entryHeader.CompressionMethod == ZipCompressionMethod.WinzipAes) - { - ExtraData? data = entryHeader.Extra.SingleOrDefault( - x => x.Type == ExtraDataType.WinZipAes - ); - if (data != null) - { - var keySize = (WinzipAesKeySize)data.DataBytes[4]; - - var salt = new byte[WinzipAesEncryptionData.KeyLengthInBytes(keySize) / 2]; - var passwordVerifyValue = new byte[2]; - stream.Read(salt, 0, salt.Length); - stream.Read(passwordVerifyValue, 0, 2); - entryHeader.WinzipAesEncryptionData = new WinzipAesEncryptionData( - keySize, - salt, - passwordVerifyValue, - _password - ); - - entryHeader.CompressedSize -= (uint)(salt.Length + 2); - } + reader.ReadBytes(zip64 ? 20 : 12); } + return null; } - - if (entryHeader.IsDirectory) + case DIGITAL_SIGNATURE: + return null; + case DIRECTORY_END_HEADER_BYTES: { - return; + var entry = new DirectoryEndHeader(); + entry.Read(reader); + return entry; } - - //if (FlagUtility.HasFlag(entryHeader.Flags, HeaderFlags.UsePostDataDescriptor)) - //{ - // entryHeader.PackedStream = new ReadOnlySubStream(stream); - //} - //else - //{ - switch (_mode) + case SPLIT_ARCHIVE_HEADER_BYTES: { - case StreamingMode.Seekable: - { - entryHeader.DataStartPosition = stream.Position; - stream.Position += entryHeader.CompressedSize; - break; - } - - case StreamingMode.Streaming: - { - entryHeader.PackedStream = stream; - break; - } - - default: - { - throw new InvalidFormatException("Invalid StreamingMode"); - } + return new SplitHeader(); } - - //} + case ZIP64_END_OF_CENTRAL_DIRECTORY: + { + var entry = new Zip64DirectoryEndHeader(); + entry.Read(reader); + return entry; + } + case ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR: + { + var entry = new Zip64DirectoryEndLocatorHeader(); + entry.Read(reader); + return entry; + } + default: + return null; } } + + internal static bool IsHeader(uint headerBytes) + { + switch (headerBytes) + { + case ENTRY_HEADER_BYTES: + case DIRECTORY_START_HEADER_BYTES: + case POST_DATA_DESCRIPTOR: + case DIGITAL_SIGNATURE: + case DIRECTORY_END_HEADER_BYTES: + case SPLIT_ARCHIVE_HEADER_BYTES: + case ZIP64_END_OF_CENTRAL_DIRECTORY: + case ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR: + return true; + default: + return false; + } + } + + private void LoadHeader(ZipFileEntry entryHeader, Stream stream) + { + if (FlagUtility.HasFlag(entryHeader.Flags, HeaderFlags.Encrypted)) + { + if ( + !entryHeader.IsDirectory + && entryHeader.CompressedSize == 0 + && FlagUtility.HasFlag(entryHeader.Flags, HeaderFlags.UsePostDataDescriptor) + ) + { + throw new NotSupportedException( + "SharpCompress cannot currently read non-seekable Zip Streams with encrypted data that has been written in a non-seekable manner." + ); + } + + if (_password is null) + { + throw new CryptographicException("No password supplied for encrypted zip."); + } + + entryHeader.Password = _password; + + if (entryHeader.CompressionMethod == ZipCompressionMethod.WinzipAes) + { + var data = entryHeader.Extra.SingleOrDefault( + x => x.Type == ExtraDataType.WinZipAes + ); + if (data != null) + { + var keySize = (WinzipAesKeySize)data.DataBytes[4]; + + var salt = new byte[WinzipAesEncryptionData.KeyLengthInBytes(keySize) / 2]; + var passwordVerifyValue = new byte[2]; + stream.Read(salt, 0, salt.Length); + stream.Read(passwordVerifyValue, 0, 2); + entryHeader.WinzipAesEncryptionData = new WinzipAesEncryptionData( + keySize, + salt, + passwordVerifyValue, + _password + ); + + entryHeader.CompressedSize -= (uint)(salt.Length + 2); + } + } + } + + if (entryHeader.IsDirectory) + { + return; + } + + //if (FlagUtility.HasFlag(entryHeader.Flags, HeaderFlags.UsePostDataDescriptor)) + //{ + // entryHeader.PackedStream = new ReadOnlySubStream(stream); + //} + //else + //{ + switch (_mode) + { + case StreamingMode.Seekable: + { + entryHeader.DataStartPosition = stream.Position; + stream.Position += entryHeader.CompressedSize; + break; + } + + case StreamingMode.Streaming: + { + entryHeader.PackedStream = stream; + break; + } + + default: + { + throw new InvalidFormatException("Invalid StreamingMode"); + } + } + + //} + } } diff --git a/src/SharpCompress/Common/Zip/ZipVolume.cs b/src/SharpCompress/Common/Zip/ZipVolume.cs index f8843305..26d471fe 100644 --- a/src/SharpCompress/Common/Zip/ZipVolume.cs +++ b/src/SharpCompress/Common/Zip/ZipVolume.cs @@ -1,13 +1,12 @@ using System.IO; using SharpCompress.Readers; -namespace SharpCompress.Common.Zip -{ - public class ZipVolume : Volume - { - public ZipVolume(Stream stream, ReaderOptions readerOptions, int index = 0) - : base(stream, readerOptions, index) { } +namespace SharpCompress.Common.Zip; - public string? Comment { get; internal set; } - } +public class ZipVolume : Volume +{ + public ZipVolume(Stream stream, ReaderOptions readerOptions, int index = 0) + : base(stream, readerOptions, index) { } + + public string? Comment { get; internal set; } } diff --git a/src/SharpCompress/Compressors/ADC/ADCBase.cs b/src/SharpCompress/Compressors/ADC/ADCBase.cs index f8241b2f..0ee2f1bb 100644 --- a/src/SharpCompress/Compressors/ADC/ADCBase.cs +++ b/src/SharpCompress/Compressors/ADC/ADCBase.cs @@ -1,4 +1,4 @@ -// +// // ADC.cs // // Author: @@ -26,185 +26,184 @@ using System; using System.IO; -namespace SharpCompress.Compressors.ADC +namespace SharpCompress.Compressors.ADC; + +/// +/// Provides static methods for decompressing Apple Data Compression data +/// +public static class ADCBase { - /// - /// Provides static methods for decompressing Apple Data Compression data - /// - public static class ADCBase + private const int PLAIN = 1; + private const int TWO_BYTE = 2; + private const int THREE_BYTE = 3; + + private static int GetChunkType(byte byt) { - private const int PLAIN = 1; - private const int TWO_BYTE = 2; - private const int THREE_BYTE = 3; - - private static int GetChunkType(byte byt) + if ((byt & 0x80) == 0x80) { - if ((byt & 0x80) == 0x80) - { - return PLAIN; - } - if ((byt & 0x40) == 0x40) - { - return THREE_BYTE; - } - return TWO_BYTE; + return PLAIN; + } + if ((byt & 0x40) == 0x40) + { + return THREE_BYTE; + } + return TWO_BYTE; + } + + private static int GetChunkSize(byte byt) + { + return GetChunkType(byt) switch + { + PLAIN => (byt & 0x7F) + 1, + TWO_BYTE => ((byt & 0x3F) >> 2) + 3, + THREE_BYTE => (byt & 0x3F) + 4, + _ => -1, + }; + } + + private static int GetOffset(ReadOnlySpan chunk) + { + return GetChunkType(chunk[0]) switch + { + PLAIN => 0, + TWO_BYTE => ((chunk[0] & 0x03) << 8) + chunk[1], + THREE_BYTE => (chunk[1] << 8) + chunk[2], + _ => -1, + }; + } + + /// + /// Decompresses a byte buffer that's compressed with ADC + /// + /// Compressed buffer + /// Buffer to hold decompressed data + /// Max size for decompressed data + /// How many bytes are stored on + public static int Decompress(byte[] input, out byte[]? output, int bufferSize = 262144) + { + return Decompress(new MemoryStream(input), out output, bufferSize); + } + + /// + /// Decompresses a stream that's compressed with ADC + /// + /// Stream containing compressed data + /// Buffer to hold decompressed data + /// Max size for decompressed data + /// How many bytes are stored on + public static int Decompress(Stream input, out byte[]? output, int bufferSize = 262144) + { + output = null; + + if (input is null || input.Length == 0) + { + return 0; } - private static int GetChunkSize(byte byt) + var start = (int)input.Position; + var position = (int)input.Position; + int chunkSize; + int offset; + int chunkType; + var buffer = new byte[bufferSize]; + var outPosition = 0; + var full = false; + Span temp = stackalloc byte[3]; + + while (position < input.Length) { - return GetChunkType(byt) switch + var readByte = input.ReadByte(); + if (readByte == -1) { - PLAIN => (byt & 0x7F) + 1, - TWO_BYTE => ((byt & 0x3F) >> 2) + 3, - THREE_BYTE => (byt & 0x3F) + 4, - _ => -1, - }; - } - - private static int GetOffset(ReadOnlySpan chunk) - { - return GetChunkType(chunk[0]) switch - { - PLAIN => 0, - TWO_BYTE => ((chunk[0] & 0x03) << 8) + chunk[1], - THREE_BYTE => (chunk[1] << 8) + chunk[2], - _ => -1, - }; - } - - /// - /// Decompresses a byte buffer that's compressed with ADC - /// - /// Compressed buffer - /// Buffer to hold decompressed data - /// Max size for decompressed data - /// How many bytes are stored on - public static int Decompress(byte[] input, out byte[]? output, int bufferSize = 262144) - { - return Decompress(new MemoryStream(input), out output, bufferSize); - } - - /// - /// Decompresses a stream that's compressed with ADC - /// - /// Stream containing compressed data - /// Buffer to hold decompressed data - /// Max size for decompressed data - /// How many bytes are stored on - public static int Decompress(Stream input, out byte[]? output, int bufferSize = 262144) - { - output = null; - - if (input is null || input.Length == 0) - { - return 0; + break; } - int start = (int)input.Position; - int position = (int)input.Position; - int chunkSize; - int offset; - int chunkType; - byte[] buffer = new byte[bufferSize]; - int outPosition = 0; - bool full = false; - Span temp = stackalloc byte[3]; + chunkType = GetChunkType((byte)readByte); - while (position < input.Length) + switch (chunkType) { - int readByte = input.ReadByte(); - if (readByte == -1) - { + case PLAIN: + chunkSize = GetChunkSize((byte)readByte); + if (outPosition + chunkSize > bufferSize) + { + full = true; + break; + } + input.Read(buffer, outPosition, chunkSize); + outPosition += chunkSize; + position += chunkSize + 1; break; - } - - chunkType = GetChunkType((byte)readByte); - - switch (chunkType) - { - case PLAIN: - chunkSize = GetChunkSize((byte)readByte); - if (outPosition + chunkSize > bufferSize) - { - full = true; - break; - } - input.Read(buffer, outPosition, chunkSize); - outPosition += chunkSize; - position += chunkSize + 1; + case TWO_BYTE: + chunkSize = GetChunkSize((byte)readByte); + temp[0] = (byte)readByte; + temp[1] = (byte)input.ReadByte(); + offset = GetOffset(temp); + if (outPosition + chunkSize > bufferSize) + { + full = true; break; - case TWO_BYTE: - chunkSize = GetChunkSize((byte)readByte); - temp[0] = (byte)readByte; - temp[1] = (byte)input.ReadByte(); - offset = GetOffset(temp); - if (outPosition + chunkSize > bufferSize) + } + if (offset == 0) + { + var lastByte = buffer[outPosition - 1]; + for (var i = 0; i < chunkSize; i++) { - full = true; - break; + buffer[outPosition] = lastByte; + outPosition++; } - if (offset == 0) + position += 2; + } + else + { + for (var i = 0; i < chunkSize; i++) { - byte lastByte = buffer[outPosition - 1]; - for (int i = 0; i < chunkSize; i++) - { - buffer[outPosition] = lastByte; - outPosition++; - } - position += 2; + buffer[outPosition] = buffer[outPosition - offset - 1]; + outPosition++; } - else - { - for (int i = 0; i < chunkSize; i++) - { - buffer[outPosition] = buffer[outPosition - offset - 1]; - outPosition++; - } - position += 2; - } - break; - case THREE_BYTE: - chunkSize = GetChunkSize((byte)readByte); - temp[0] = (byte)readByte; - temp[1] = (byte)input.ReadByte(); - temp[2] = (byte)input.ReadByte(); - offset = GetOffset(temp); - if (outPosition + chunkSize > bufferSize) - { - full = true; - break; - } - if (offset == 0) - { - byte lastByte = buffer[outPosition - 1]; - for (int i = 0; i < chunkSize; i++) - { - buffer[outPosition] = lastByte; - outPosition++; - } - position += 3; - } - else - { - for (int i = 0; i < chunkSize; i++) - { - buffer[outPosition] = buffer[outPosition - offset - 1]; - outPosition++; - } - position += 3; - } - break; - } - - if (full) - { + position += 2; + } + break; + case THREE_BYTE: + chunkSize = GetChunkSize((byte)readByte); + temp[0] = (byte)readByte; + temp[1] = (byte)input.ReadByte(); + temp[2] = (byte)input.ReadByte(); + offset = GetOffset(temp); + if (outPosition + chunkSize > bufferSize) + { + full = true; + break; + } + if (offset == 0) + { + var lastByte = buffer[outPosition - 1]; + for (var i = 0; i < chunkSize; i++) + { + buffer[outPosition] = lastByte; + outPosition++; + } + position += 3; + } + else + { + for (var i = 0; i < chunkSize; i++) + { + buffer[outPosition] = buffer[outPosition - offset - 1]; + outPosition++; + } + position += 3; + } break; - } } - output = new byte[outPosition]; - Array.Copy(buffer, output, outPosition); - return position - start; + if (full) + { + break; + } } + + output = new byte[outPosition]; + Array.Copy(buffer, output, outPosition); + return position - start; } } diff --git a/src/SharpCompress/Compressors/ADC/ADCStream.cs b/src/SharpCompress/Compressors/ADC/ADCStream.cs index 02337d8f..9d57d1d7 100644 --- a/src/SharpCompress/Compressors/ADC/ADCStream.cs +++ b/src/SharpCompress/Compressors/ADC/ADCStream.cs @@ -1,4 +1,4 @@ -// +// // ADC.cs // // Author: @@ -29,153 +29,152 @@ using System; using System.IO; -namespace SharpCompress.Compressors.ADC +namespace SharpCompress.Compressors.ADC; + +/// +/// Provides a forward readable only stream that decompresses ADC data +/// +public sealed class ADCStream : Stream { /// - /// Provides a forward readable only stream that decompresses ADC data + /// This stream holds the compressed data /// - public sealed class ADCStream : Stream + private readonly Stream _stream; + + /// + /// Is this instance disposed? + /// + private bool _isDisposed; + + /// + /// Position in decompressed data + /// + private long _position; + + /// + /// Buffer with currently used chunk of decompressed data + /// + private byte[] _outBuffer; + + /// + /// Position in buffer of decompressed data + /// + private int _outPosition; + + /// + /// Initializates a stream that decompresses ADC data on the fly + /// + /// Stream that contains the compressed data + /// Must be set to because compression is not implemented + public ADCStream( + Stream stream, + CompressionMode compressionMode = CompressionMode.Decompress + ) { - /// - /// This stream holds the compressed data - /// - private readonly Stream _stream; - - /// - /// Is this instance disposed? - /// - private bool _isDisposed; - - /// - /// Position in decompressed data - /// - private long _position; - - /// - /// Buffer with currently used chunk of decompressed data - /// - private byte[] _outBuffer; - - /// - /// Position in buffer of decompressed data - /// - private int _outPosition; - - /// - /// Initializates a stream that decompresses ADC data on the fly - /// - /// Stream that contains the compressed data - /// Must be set to because compression is not implemented - public ADCStream( - Stream stream, - CompressionMode compressionMode = CompressionMode.Decompress - ) - { - if (compressionMode == CompressionMode.Compress) - { - throw new NotSupportedException(); - } - - _stream = stream; - } - - public override bool CanRead => _stream.CanRead; - - public override bool CanSeek => false; - - public override bool CanWrite => false; - - public override long Length => throw new NotSupportedException(); - - public override long Position - { - get => _position; - set => throw new NotSupportedException(); - } - - public override void Flush() { } - - protected override void Dispose(bool disposing) - { - if (_isDisposed) - { - return; - } - _isDisposed = true; - base.Dispose(disposing); - } - - public override int Read(byte[] buffer, int offset, int count) - { - if (count == 0) - { - return 0; - } - if (buffer is null) - { - throw new ArgumentNullException(nameof(buffer)); - } - if (count < 0) - { - throw new ArgumentOutOfRangeException(nameof(count)); - } - if (offset < buffer.GetLowerBound(0)) - { - throw new ArgumentOutOfRangeException(nameof(offset)); - } - if ((offset + count) > buffer.GetLength(0)) - { - throw new ArgumentOutOfRangeException(nameof(count)); - } - - int size = -1; - - if (_outBuffer is null) - { - size = ADCBase.Decompress(_stream, out _outBuffer); - _outPosition = 0; - } - - int inPosition = offset; - int toCopy = count; - int copied = 0; - - while (_outPosition + toCopy >= _outBuffer.Length) - { - int piece = _outBuffer.Length - _outPosition; - Array.Copy(_outBuffer, _outPosition, buffer, inPosition, piece); - inPosition += piece; - copied += piece; - _position += piece; - toCopy -= piece; - size = ADCBase.Decompress(_stream, out _outBuffer); - _outPosition = 0; - if (size == 0 || _outBuffer is null || _outBuffer.Length == 0) - { - return copied; - } - } - - Array.Copy(_outBuffer, _outPosition, buffer, inPosition, toCopy); - _outPosition += toCopy; - _position += toCopy; - copied += toCopy; - return copied; - } - - public override long Seek(long offset, SeekOrigin origin) + if (compressionMode == CompressionMode.Compress) { throw new NotSupportedException(); } - public override void SetLength(long value) + _stream = stream; + } + + public override bool CanRead => _stream.CanRead; + + public override bool CanSeek => false; + + public override bool CanWrite => false; + + public override long Length => throw new NotSupportedException(); + + public override long Position + { + get => _position; + set => throw new NotSupportedException(); + } + + public override void Flush() { } + + protected override void Dispose(bool disposing) + { + if (_isDisposed) { - throw new NotSupportedException(); + return; + } + _isDisposed = true; + base.Dispose(disposing); + } + + public override int Read(byte[] buffer, int offset, int count) + { + if (count == 0) + { + return 0; + } + if (buffer is null) + { + throw new ArgumentNullException(nameof(buffer)); + } + if (count < 0) + { + throw new ArgumentOutOfRangeException(nameof(count)); + } + if (offset < buffer.GetLowerBound(0)) + { + throw new ArgumentOutOfRangeException(nameof(offset)); + } + if ((offset + count) > buffer.GetLength(0)) + { + throw new ArgumentOutOfRangeException(nameof(count)); } - public override void Write(byte[] buffer, int offset, int count) + var size = -1; + + if (_outBuffer is null) { - throw new NotSupportedException(); + size = ADCBase.Decompress(_stream, out _outBuffer); + _outPosition = 0; } + + var inPosition = offset; + var toCopy = count; + var copied = 0; + + while (_outPosition + toCopy >= _outBuffer.Length) + { + var piece = _outBuffer.Length - _outPosition; + Array.Copy(_outBuffer, _outPosition, buffer, inPosition, piece); + inPosition += piece; + copied += piece; + _position += piece; + toCopy -= piece; + size = ADCBase.Decompress(_stream, out _outBuffer); + _outPosition = 0; + if (size == 0 || _outBuffer is null || _outBuffer.Length == 0) + { + return copied; + } + } + + Array.Copy(_outBuffer, _outPosition, buffer, inPosition, toCopy); + _outPosition += toCopy; + _position += toCopy; + copied += toCopy; + return copied; + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } + + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + public override void Write(byte[] buffer, int offset, int count) + { + throw new NotSupportedException(); } } diff --git a/src/SharpCompress/Compressors/BZip2/BZip2Constants.cs b/src/SharpCompress/Compressors/BZip2/BZip2Constants.cs index 6644c278..cfeb02e4 100644 --- a/src/SharpCompress/Compressors/BZip2/BZip2Constants.cs +++ b/src/SharpCompress/Compressors/BZip2/BZip2Constants.cs @@ -1,4 +1,4 @@ -/* +/* * Copyright 2001,2004-2005 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,542 +20,541 @@ * great code. */ -namespace SharpCompress.Compressors.BZip2 +namespace SharpCompress.Compressors.BZip2; + +/** +* Base class for both the compress and decompress classes. +* Holds common arrays, and static data. +* +* @author Keiron Liddle +*/ + +internal class BZip2Constants { - /** - * Base class for both the compress and decompress classes. - * Holds common arrays, and static data. - * - * @author Keiron Liddle - */ + public const int baseBlockSize = 100000; + public const int MAX_ALPHA_SIZE = 258; + public const int MAX_CODE_LEN = 23; + public const int RUNA = 0; + public const int RUNB = 1; + public const int N_GROUPS = 6; + public const int G_SIZE = 50; + public const int N_ITERS = 4; + public const int MAX_SELECTORS = (2 + (900000 / G_SIZE)); + public const int NUM_OVERSHOOT_BYTES = 20; - internal class BZip2Constants + public static int[] rNums = { - public const int baseBlockSize = 100000; - public const int MAX_ALPHA_SIZE = 258; - public const int MAX_CODE_LEN = 23; - public const int RUNA = 0; - public const int RUNB = 1; - public const int N_GROUPS = 6; - public const int G_SIZE = 50; - public const int N_ITERS = 4; - public const int MAX_SELECTORS = (2 + (900000 / G_SIZE)); - public const int NUM_OVERSHOOT_BYTES = 20; - - public static int[] rNums = - { - 619, - 720, - 127, - 481, - 931, - 816, - 813, - 233, - 566, - 247, - 985, - 724, - 205, - 454, - 863, - 491, - 741, - 242, - 949, - 214, - 733, - 859, - 335, - 708, - 621, - 574, - 73, - 654, - 730, - 472, - 419, - 436, - 278, - 496, - 867, - 210, - 399, - 680, - 480, - 51, - 878, - 465, - 811, - 169, - 869, - 675, - 611, - 697, - 867, - 561, - 862, - 687, - 507, - 283, - 482, - 129, - 807, - 591, - 733, - 623, - 150, - 238, - 59, - 379, - 684, - 877, - 625, - 169, - 643, - 105, - 170, - 607, - 520, - 932, - 727, - 476, - 693, - 425, - 174, - 647, - 73, - 122, - 335, - 530, - 442, - 853, - 695, - 249, - 445, - 515, - 909, - 545, - 703, - 919, - 874, - 474, - 882, - 500, - 594, - 612, - 641, - 801, - 220, - 162, - 819, - 984, - 589, - 513, - 495, - 799, - 161, - 604, - 958, - 533, - 221, - 400, - 386, - 867, - 600, - 782, - 382, - 596, - 414, - 171, - 516, - 375, - 682, - 485, - 911, - 276, - 98, - 553, - 163, - 354, - 666, - 933, - 424, - 341, - 533, - 870, - 227, - 730, - 475, - 186, - 263, - 647, - 537, - 686, - 600, - 224, - 469, - 68, - 770, - 919, - 190, - 373, - 294, - 822, - 808, - 206, - 184, - 943, - 795, - 384, - 383, - 461, - 404, - 758, - 839, - 887, - 715, - 67, - 618, - 276, - 204, - 918, - 873, - 777, - 604, - 560, - 951, - 160, - 578, - 722, - 79, - 804, - 96, - 409, - 713, - 940, - 652, - 934, - 970, - 447, - 318, - 353, - 859, - 672, - 112, - 785, - 645, - 863, - 803, - 350, - 139, - 93, - 354, - 99, - 820, - 908, - 609, - 772, - 154, - 274, - 580, - 184, - 79, - 626, - 630, - 742, - 653, - 282, - 762, - 623, - 680, - 81, - 927, - 626, - 789, - 125, - 411, - 521, - 938, - 300, - 821, - 78, - 343, - 175, - 128, - 250, - 170, - 774, - 972, - 275, - 999, - 639, - 495, - 78, - 352, - 126, - 857, - 956, - 358, - 619, - 580, - 124, - 737, - 594, - 701, - 612, - 669, - 112, - 134, - 694, - 363, - 992, - 809, - 743, - 168, - 974, - 944, - 375, - 748, - 52, - 600, - 747, - 642, - 182, - 862, - 81, - 344, - 805, - 988, - 739, - 511, - 655, - 814, - 334, - 249, - 515, - 897, - 955, - 664, - 981, - 649, - 113, - 974, - 459, - 893, - 228, - 433, - 837, - 553, - 268, - 926, - 240, - 102, - 654, - 459, - 51, - 686, - 754, - 806, - 760, - 493, - 403, - 415, - 394, - 687, - 700, - 946, - 670, - 656, - 610, - 738, - 392, - 760, - 799, - 887, - 653, - 978, - 321, - 576, - 617, - 626, - 502, - 894, - 679, - 243, - 440, - 680, - 879, - 194, - 572, - 640, - 724, - 926, - 56, - 204, - 700, - 707, - 151, - 457, - 449, - 797, - 195, - 791, - 558, - 945, - 679, - 297, - 59, - 87, - 824, - 713, - 663, - 412, - 693, - 342, - 606, - 134, - 108, - 571, - 364, - 631, - 212, - 174, - 643, - 304, - 329, - 343, - 97, - 430, - 751, - 497, - 314, - 983, - 374, - 822, - 928, - 140, - 206, - 73, - 263, - 980, - 736, - 876, - 478, - 430, - 305, - 170, - 514, - 364, - 692, - 829, - 82, - 855, - 953, - 676, - 246, - 369, - 970, - 294, - 750, - 807, - 827, - 150, - 790, - 288, - 923, - 804, - 378, - 215, - 828, - 592, - 281, - 565, - 555, - 710, - 82, - 896, - 831, - 547, - 261, - 524, - 462, - 293, - 465, - 502, - 56, - 661, - 821, - 976, - 991, - 658, - 869, - 905, - 758, - 745, - 193, - 768, - 550, - 608, - 933, - 378, - 286, - 215, - 979, - 792, - 961, - 61, - 688, - 793, - 644, - 986, - 403, - 106, - 366, - 905, - 644, - 372, - 567, - 466, - 434, - 645, - 210, - 389, - 550, - 919, - 135, - 780, - 773, - 635, - 389, - 707, - 100, - 626, - 958, - 165, - 504, - 920, - 176, - 193, - 713, - 857, - 265, - 203, - 50, - 668, - 108, - 645, - 990, - 626, - 197, - 510, - 357, - 358, - 850, - 858, - 364, - 936, - 638 - }; - } + 619, + 720, + 127, + 481, + 931, + 816, + 813, + 233, + 566, + 247, + 985, + 724, + 205, + 454, + 863, + 491, + 741, + 242, + 949, + 214, + 733, + 859, + 335, + 708, + 621, + 574, + 73, + 654, + 730, + 472, + 419, + 436, + 278, + 496, + 867, + 210, + 399, + 680, + 480, + 51, + 878, + 465, + 811, + 169, + 869, + 675, + 611, + 697, + 867, + 561, + 862, + 687, + 507, + 283, + 482, + 129, + 807, + 591, + 733, + 623, + 150, + 238, + 59, + 379, + 684, + 877, + 625, + 169, + 643, + 105, + 170, + 607, + 520, + 932, + 727, + 476, + 693, + 425, + 174, + 647, + 73, + 122, + 335, + 530, + 442, + 853, + 695, + 249, + 445, + 515, + 909, + 545, + 703, + 919, + 874, + 474, + 882, + 500, + 594, + 612, + 641, + 801, + 220, + 162, + 819, + 984, + 589, + 513, + 495, + 799, + 161, + 604, + 958, + 533, + 221, + 400, + 386, + 867, + 600, + 782, + 382, + 596, + 414, + 171, + 516, + 375, + 682, + 485, + 911, + 276, + 98, + 553, + 163, + 354, + 666, + 933, + 424, + 341, + 533, + 870, + 227, + 730, + 475, + 186, + 263, + 647, + 537, + 686, + 600, + 224, + 469, + 68, + 770, + 919, + 190, + 373, + 294, + 822, + 808, + 206, + 184, + 943, + 795, + 384, + 383, + 461, + 404, + 758, + 839, + 887, + 715, + 67, + 618, + 276, + 204, + 918, + 873, + 777, + 604, + 560, + 951, + 160, + 578, + 722, + 79, + 804, + 96, + 409, + 713, + 940, + 652, + 934, + 970, + 447, + 318, + 353, + 859, + 672, + 112, + 785, + 645, + 863, + 803, + 350, + 139, + 93, + 354, + 99, + 820, + 908, + 609, + 772, + 154, + 274, + 580, + 184, + 79, + 626, + 630, + 742, + 653, + 282, + 762, + 623, + 680, + 81, + 927, + 626, + 789, + 125, + 411, + 521, + 938, + 300, + 821, + 78, + 343, + 175, + 128, + 250, + 170, + 774, + 972, + 275, + 999, + 639, + 495, + 78, + 352, + 126, + 857, + 956, + 358, + 619, + 580, + 124, + 737, + 594, + 701, + 612, + 669, + 112, + 134, + 694, + 363, + 992, + 809, + 743, + 168, + 974, + 944, + 375, + 748, + 52, + 600, + 747, + 642, + 182, + 862, + 81, + 344, + 805, + 988, + 739, + 511, + 655, + 814, + 334, + 249, + 515, + 897, + 955, + 664, + 981, + 649, + 113, + 974, + 459, + 893, + 228, + 433, + 837, + 553, + 268, + 926, + 240, + 102, + 654, + 459, + 51, + 686, + 754, + 806, + 760, + 493, + 403, + 415, + 394, + 687, + 700, + 946, + 670, + 656, + 610, + 738, + 392, + 760, + 799, + 887, + 653, + 978, + 321, + 576, + 617, + 626, + 502, + 894, + 679, + 243, + 440, + 680, + 879, + 194, + 572, + 640, + 724, + 926, + 56, + 204, + 700, + 707, + 151, + 457, + 449, + 797, + 195, + 791, + 558, + 945, + 679, + 297, + 59, + 87, + 824, + 713, + 663, + 412, + 693, + 342, + 606, + 134, + 108, + 571, + 364, + 631, + 212, + 174, + 643, + 304, + 329, + 343, + 97, + 430, + 751, + 497, + 314, + 983, + 374, + 822, + 928, + 140, + 206, + 73, + 263, + 980, + 736, + 876, + 478, + 430, + 305, + 170, + 514, + 364, + 692, + 829, + 82, + 855, + 953, + 676, + 246, + 369, + 970, + 294, + 750, + 807, + 827, + 150, + 790, + 288, + 923, + 804, + 378, + 215, + 828, + 592, + 281, + 565, + 555, + 710, + 82, + 896, + 831, + 547, + 261, + 524, + 462, + 293, + 465, + 502, + 56, + 661, + 821, + 976, + 991, + 658, + 869, + 905, + 758, + 745, + 193, + 768, + 550, + 608, + 933, + 378, + 286, + 215, + 979, + 792, + 961, + 61, + 688, + 793, + 644, + 986, + 403, + 106, + 366, + 905, + 644, + 372, + 567, + 466, + 434, + 645, + 210, + 389, + 550, + 919, + 135, + 780, + 773, + 635, + 389, + 707, + 100, + 626, + 958, + 165, + 504, + 920, + 176, + 193, + 713, + 857, + 265, + 203, + 50, + 668, + 108, + 645, + 990, + 626, + 197, + 510, + 357, + 358, + 850, + 858, + 364, + 936, + 638 + }; } diff --git a/src/SharpCompress/Compressors/BZip2/BZip2Stream.cs b/src/SharpCompress/Compressors/BZip2/BZip2Stream.cs index ea54e7e9..1c7aaeb4 100644 --- a/src/SharpCompress/Compressors/BZip2/BZip2Stream.cs +++ b/src/SharpCompress/Compressors/BZip2/BZip2Stream.cs @@ -1,132 +1,131 @@ -using System; +using System; using System.IO; -namespace SharpCompress.Compressors.BZip2 +namespace SharpCompress.Compressors.BZip2; + +public sealed class BZip2Stream : Stream { - public sealed class BZip2Stream : Stream + private readonly Stream stream; + private bool isDisposed; + + /// + /// Create a BZip2Stream + /// + /// The stream to read from + /// Compression Mode + /// Decompress Concatenated + public BZip2Stream( + Stream stream, + CompressionMode compressionMode, + bool decompressConcatenated + ) { - private readonly Stream stream; - private bool isDisposed; - - /// - /// Create a BZip2Stream - /// - /// The stream to read from - /// Compression Mode - /// Decompress Concatenated - public BZip2Stream( - Stream stream, - CompressionMode compressionMode, - bool decompressConcatenated - ) + Mode = compressionMode; + if (Mode == CompressionMode.Compress) { - Mode = compressionMode; - if (Mode == CompressionMode.Compress) - { - this.stream = new CBZip2OutputStream(stream); - } - else - { - this.stream = new CBZip2InputStream(stream, decompressConcatenated); - } + this.stream = new CBZip2OutputStream(stream); } - - public void Finish() + else { - (stream as CBZip2OutputStream)?.Finish(); + this.stream = new CBZip2InputStream(stream, decompressConcatenated); } + } - protected override void Dispose(bool disposing) + public void Finish() + { + (stream as CBZip2OutputStream)?.Finish(); + } + + protected override void Dispose(bool disposing) + { + if (isDisposed) { - if (isDisposed) - { - return; - } - isDisposed = true; - if (disposing) - { - stream.Dispose(); - } + return; } - - public CompressionMode Mode { get; } - - public override bool CanRead => stream.CanRead; - - public override bool CanSeek => stream.CanSeek; - - public override bool CanWrite => stream.CanWrite; - - public override void Flush() + isDisposed = true; + if (disposing) { - stream.Flush(); + stream.Dispose(); } + } - public override long Length => stream.Length; + public CompressionMode Mode { get; } - public override long Position - { - get => stream.Position; - set => stream.Position = value; - } + public override bool CanRead => stream.CanRead; - public override int Read(byte[] buffer, int offset, int count) - { - return stream.Read(buffer, offset, count); - } + public override bool CanSeek => stream.CanSeek; - public override int ReadByte() - { - return stream.ReadByte(); - } + public override bool CanWrite => stream.CanWrite; - public override long Seek(long offset, SeekOrigin origin) - { - return stream.Seek(offset, origin); - } + public override void Flush() + { + stream.Flush(); + } - public override void SetLength(long value) - { - stream.SetLength(value); - } + public override long Length => stream.Length; + + public override long Position + { + get => stream.Position; + set => stream.Position = value; + } + + public override int Read(byte[] buffer, int offset, int count) + { + return stream.Read(buffer, offset, count); + } + + public override int ReadByte() + { + return stream.ReadByte(); + } + + public override long Seek(long offset, SeekOrigin origin) + { + return stream.Seek(offset, origin); + } + + public override void SetLength(long value) + { + stream.SetLength(value); + } #if !NETFRAMEWORK && !NETSTANDARD2_0 - public override int Read(Span buffer) - { - return stream.Read(buffer); - } + public override int Read(Span buffer) + { + return stream.Read(buffer); + } - public override void Write(ReadOnlySpan buffer) - { - stream.Write(buffer); - } + public override void Write(ReadOnlySpan buffer) + { + stream.Write(buffer); + } #endif - public override void Write(byte[] buffer, int offset, int count) - { - stream.Write(buffer, offset, count); - } + public override void Write(byte[] buffer, int offset, int count) + { + stream.Write(buffer, offset, count); + } - public override void WriteByte(byte value) - { - stream.WriteByte(value); - } + public override void WriteByte(byte value) + { + stream.WriteByte(value); + } - /// - /// Consumes two bytes to test if there is a BZip2 header - /// - /// - /// - public static bool IsBZip2(Stream stream) + /// + /// Consumes two bytes to test if there is a BZip2 header + /// + /// + /// + public static bool IsBZip2(Stream stream) + { + var br = new BinaryReader(stream); + var chars = br.ReadBytes(2); + if (chars.Length < 2 || chars[0] != 'B' || chars[1] != 'Z') { - BinaryReader br = new BinaryReader(stream); - byte[] chars = br.ReadBytes(2); - if (chars.Length < 2 || chars[0] != 'B' || chars[1] != 'Z') - { - return false; - } - return true; + return false; } + return true; } } diff --git a/src/SharpCompress/Compressors/BZip2/CBZip2InputStream.cs b/src/SharpCompress/Compressors/BZip2/CBZip2InputStream.cs index 1b77ed84..5f58b363 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; @@ -25,835 +25,733 @@ using System.IO; * great code. */ -namespace SharpCompress.Compressors.BZip2 +namespace SharpCompress.Compressors.BZip2; + +/** + * An input stream that decompresses from the BZip2 format (with the file + * header chars) to be read as any other stream. + * + * @author Keiron Liddle + * + * NB: note this class has been modified to read the leading BZ from the + * start of the BZIP2 stream to make it compatible with other PGP programs. + */ + +internal class CBZip2InputStream : Stream { - /** - * An input stream that decompresses from the BZip2 format (with the file - * header chars) to be read as any other stream. - * - * @author Keiron Liddle - * - * NB: note this class has been modified to read the leading BZ from the - * start of the BZIP2 stream to make it compatible with other PGP programs. - */ - - internal class CBZip2InputStream : Stream + private static void Cadvise() { - private static void Cadvise() - { - //System.out.Println("CRC Error"); - //throw new CCoruptionError(); - } + //System.out.Println("CRC Error"); + //throw new CCoruptionError(); + } - private static void BadBGLengths() - { - Cadvise(); - } + private static void BadBGLengths() + { + Cadvise(); + } - private static void BitStreamEOF() - { - Cadvise(); - } + private static void BitStreamEOF() + { + Cadvise(); + } - private static void CompressedStreamEOF() - { - Cadvise(); - } + private static void CompressedStreamEOF() + { + Cadvise(); + } - private void MakeMaps() + private void MakeMaps() + { + int i; + nInUse = 0; + for (i = 0; i < 256; i++) { - int i; - nInUse = 0; - for (i = 0; i < 256; i++) + if (inUse[i]) { - if (inUse[i]) - { - seqToUnseq[nInUse] = (char)i; - unseqToSeq[i] = (char)nInUse; - nInUse++; - } + seqToUnseq[nInUse] = (char)i; + unseqToSeq[i] = (char)nInUse; + nInUse++; } } + } - /* - index of the last char in the block, so - the block size == last + 1. - */ - private int last; + /* + index of the last char in the block, so + the block size == last + 1. + */ + private int last; - /* - index in zptr[] of original string after sorting. - */ - private int origPtr; + /* + index in zptr[] of original string after sorting. + */ + private int origPtr; - /* - always: in the range 0 .. 9. - The current block size is 100000 * this number. - */ - private int blockSize100k; + /* + always: in the range 0 .. 9. + The current block size is 100000 * this number. + */ + private int blockSize100k; - private bool blockRandomised; + private bool blockRandomised; - private int bsBuff; - private int bsLive; - private readonly CRC mCrc = new CRC(); + private int bsBuff; + private int bsLive; + private readonly CRC mCrc = new CRC(); - private readonly bool[] inUse = new bool[256]; - private int nInUse; + private readonly bool[] inUse = new bool[256]; + private int nInUse; - private readonly char[] seqToUnseq = new char[256]; - private readonly char[] unseqToSeq = new char[256]; + private readonly char[] seqToUnseq = new char[256]; + private readonly char[] unseqToSeq = new char[256]; - private readonly char[] selector = new char[BZip2Constants.MAX_SELECTORS]; - private readonly char[] selectorMtf = new char[BZip2Constants.MAX_SELECTORS]; + private readonly char[] selector = new char[BZip2Constants.MAX_SELECTORS]; + private readonly char[] selectorMtf = new char[BZip2Constants.MAX_SELECTORS]; - private int[] tt; - private char[] ll8; + private int[] tt; + private char[] ll8; - /* - freq table collected to save a pass over the data - during decompression. - */ - private readonly int[] unzftab = new int[256]; + /* + freq table collected to save a pass over the data + during decompression. + */ + private readonly int[] unzftab = new int[256]; - private readonly int[][] limit = InitIntArray( - BZip2Constants.N_GROUPS, - BZip2Constants.MAX_ALPHA_SIZE - ); - private readonly int[][] basev = InitIntArray( - BZip2Constants.N_GROUPS, - BZip2Constants.MAX_ALPHA_SIZE - ); - private readonly int[][] perm = InitIntArray( - BZip2Constants.N_GROUPS, - BZip2Constants.MAX_ALPHA_SIZE - ); - private readonly int[] minLens = new int[BZip2Constants.N_GROUPS]; + private readonly int[][] limit = InitIntArray( + BZip2Constants.N_GROUPS, + BZip2Constants.MAX_ALPHA_SIZE + ); + private readonly int[][] basev = InitIntArray( + BZip2Constants.N_GROUPS, + BZip2Constants.MAX_ALPHA_SIZE + ); + private readonly int[][] perm = InitIntArray( + BZip2Constants.N_GROUPS, + BZip2Constants.MAX_ALPHA_SIZE + ); + private readonly int[] minLens = new int[BZip2Constants.N_GROUPS]; - private Stream bsStream; + private Stream bsStream; - private bool streamEnd; + private bool streamEnd; - private int currentChar = -1; + private int currentChar = -1; - private const int START_BLOCK_STATE = 1; - private const int RAND_PART_A_STATE = 2; - private const int RAND_PART_B_STATE = 3; - private const int RAND_PART_C_STATE = 4; - private const int NO_RAND_PART_A_STATE = 5; - private const int NO_RAND_PART_B_STATE = 6; - private const int NO_RAND_PART_C_STATE = 7; + private const int START_BLOCK_STATE = 1; + private const int RAND_PART_A_STATE = 2; + private const int RAND_PART_B_STATE = 3; + private const int RAND_PART_C_STATE = 4; + private const int NO_RAND_PART_A_STATE = 5; + private const int NO_RAND_PART_B_STATE = 6; + private const int NO_RAND_PART_C_STATE = 7; - private int currentState = START_BLOCK_STATE; + private int currentState = START_BLOCK_STATE; - private int storedBlockCRC, - storedCombinedCRC; - private int computedBlockCRC, - computedCombinedCRC; - private readonly bool decompressConcatenated; + private int storedBlockCRC, + storedCombinedCRC; + private int computedBlockCRC, + computedCombinedCRC; + private readonly bool decompressConcatenated; - private int i2, - count, - chPrev, - ch2; - private int i, - tPos; - private int rNToGo; - private int rTPos; - private int j2; - private char z; - private bool isDisposed; + private int i2, + count, + chPrev, + ch2; + private int i, + tPos; + private int rNToGo; + private int rTPos; + private int j2; + private char z; + private bool isDisposed; - public CBZip2InputStream(Stream zStream, bool decompressConcatenated) + public CBZip2InputStream(Stream zStream, bool decompressConcatenated) + { + this.decompressConcatenated = decompressConcatenated; + ll8 = null; + tt = null; + BsSetStream(zStream); + Initialize(true); + InitBlock(); + SetupBlock(); + } + + protected override void Dispose(bool disposing) + { + if (isDisposed) { - this.decompressConcatenated = decompressConcatenated; - ll8 = null; - tt = null; - BsSetStream(zStream); - Initialize(true); - InitBlock(); - SetupBlock(); + return; + } + isDisposed = true; + base.Dispose(disposing); + bsStream?.Dispose(); + } + + internal static int[][] InitIntArray(int n1, int n2) + { + var a = new int[n1][]; + for (var k = 0; k < n1; ++k) + { + a[k] = new int[n2]; + } + return a; + } + + internal static char[][] InitCharArray(int n1, int n2) + { + var a = new char[n1][]; + for (var k = 0; k < n1; ++k) + { + a[k] = new char[n2]; + } + return a; + } + + public override int ReadByte() + { + if (streamEnd) + { + return -1; + } + var retChar = currentChar; + switch (currentState) + { + case START_BLOCK_STATE: + break; + case RAND_PART_A_STATE: + break; + case RAND_PART_B_STATE: + SetupRandPartB(); + break; + case RAND_PART_C_STATE: + SetupRandPartC(); + break; + case NO_RAND_PART_A_STATE: + break; + case NO_RAND_PART_B_STATE: + SetupNoRandPartB(); + break; + case NO_RAND_PART_C_STATE: + SetupNoRandPartC(); + break; + default: + break; + } + return retChar; + } + + private bool Initialize(bool isFirstStream) + { + var magic0 = bsStream.ReadByte(); + var magic1 = bsStream.ReadByte(); + var magic2 = bsStream.ReadByte(); + if (magic0 == -1 && !isFirstStream) + { + return false; + } + if (magic0 != 'B' || magic1 != 'Z' || magic2 != 'h') + { + throw new IOException("Not a BZIP2 marked stream"); + } + var magic3 = bsStream.ReadByte(); + if (magic3 < '1' || magic3 > '9') + { + BsFinishedWithStream(); + streamEnd = true; + return false; } - protected override void Dispose(bool disposing) + SetDecompressStructureSizes(magic3 - '0'); + bsLive = 0; + computedCombinedCRC = 0; + return true; + } + + private void InitBlock() + { + char magic1, + magic2, + magic3, + magic4; + char magic5, + magic6; + + while (true) { - if (isDisposed) - { - return; - } - isDisposed = true; - base.Dispose(disposing); - if (bsStream != null) - { - bsStream.Dispose(); - } - } - - internal static int[][] InitIntArray(int n1, int n2) - { - int[][] a = new int[n1][]; - for (int k = 0; k < n1; ++k) - { - a[k] = new int[n2]; - } - return a; - } - - internal static char[][] InitCharArray(int n1, int n2) - { - char[][] a = new char[n1][]; - for (int k = 0; k < n1; ++k) - { - a[k] = new char[n2]; - } - return a; - } - - public override int ReadByte() - { - if (streamEnd) - { - return -1; - } - int retChar = currentChar; - switch (currentState) - { - case START_BLOCK_STATE: - break; - case RAND_PART_A_STATE: - break; - case RAND_PART_B_STATE: - SetupRandPartB(); - break; - case RAND_PART_C_STATE: - SetupRandPartC(); - break; - case NO_RAND_PART_A_STATE: - break; - case NO_RAND_PART_B_STATE: - SetupNoRandPartB(); - break; - case NO_RAND_PART_C_STATE: - SetupNoRandPartC(); - break; - default: - break; - } - return retChar; - } - - private bool Initialize(bool isFirstStream) - { - int magic0 = bsStream.ReadByte(); - int magic1 = bsStream.ReadByte(); - int magic2 = bsStream.ReadByte(); - if (magic0 == -1 && !isFirstStream) - { - return false; - } - if (magic0 != 'B' || magic1 != 'Z' || magic2 != 'h') - { - throw new IOException("Not a BZIP2 marked stream"); - } - int magic3 = bsStream.ReadByte(); - if (magic3 < '1' || magic3 > '9') - { - BsFinishedWithStream(); - streamEnd = true; - return false; - } - - SetDecompressStructureSizes(magic3 - '0'); - bsLive = 0; - computedCombinedCRC = 0; - return true; - } - - private void InitBlock() - { - char magic1, - magic2, - magic3, - magic4; - char magic5, - magic6; - - while (true) - { - magic1 = BsGetUChar(); - magic2 = BsGetUChar(); - magic3 = BsGetUChar(); - magic4 = BsGetUChar(); - magic5 = BsGetUChar(); - magic6 = BsGetUChar(); - if ( - magic1 != 0x17 - || magic2 != 0x72 - || magic3 != 0x45 - || magic4 != 0x38 - || magic5 != 0x50 - || magic6 != 0x90 - ) - { - break; - } - - if (Complete()) - { - return; - } - } - + magic1 = BsGetUChar(); + magic2 = BsGetUChar(); + magic3 = BsGetUChar(); + magic4 = BsGetUChar(); + magic5 = BsGetUChar(); + magic6 = BsGetUChar(); if ( - magic1 != 0x31 - || magic2 != 0x41 - || magic3 != 0x59 - || magic4 != 0x26 - || magic5 != 0x53 - || magic6 != 0x59 + magic1 != 0x17 + || magic2 != 0x72 + || magic3 != 0x45 + || magic4 != 0x38 + || magic5 != 0x50 + || magic6 != 0x90 ) { - BadBlockHeader(); - streamEnd = true; - return; + break; } - storedBlockCRC = BsGetInt32(); + if (Complete()) + { + return; + } + } + if ( + magic1 != 0x31 + || magic2 != 0x41 + || magic3 != 0x59 + || magic4 != 0x26 + || magic5 != 0x53 + || magic6 != 0x59 + ) + { + BadBlockHeader(); + streamEnd = true; + return; + } + + storedBlockCRC = BsGetInt32(); + + if (BsR(1) == 1) + { + blockRandomised = true; + } + else + { + blockRandomised = false; + } + + // currBlockNo++; + GetAndMoveToFrontDecode(); + + mCrc.InitialiseCRC(); + currentState = START_BLOCK_STATE; + } + + private void EndBlock() + { + computedBlockCRC = mCrc.GetFinalCRC(); + /* A bad CRC is considered a fatal error. */ + if (storedBlockCRC != computedBlockCRC) + { + CrcError(); + } + + computedCombinedCRC = + (computedCombinedCRC << 1) | (int)(((uint)computedCombinedCRC) >> 31); + computedCombinedCRC ^= computedBlockCRC; + } + + private bool Complete() + { + storedCombinedCRC = BsGetInt32(); + if (storedCombinedCRC != computedCombinedCRC) + { + CrcError(); + } + + var complete = !decompressConcatenated || !Initialize(false); + if (complete) + { + BsFinishedWithStream(); + streamEnd = true; + } + + // Look for the next .bz2 stream if decompressing + // concatenated files. + return complete; + } + + private static void BlockOverrun() + { + Cadvise(); + } + + private static void BadBlockHeader() + { + Cadvise(); + } + + private static void CrcError() + { + Cadvise(); + } + + private void BsFinishedWithStream() + { + bsStream?.Dispose(); + bsStream = null; + } + + private void BsSetStream(Stream f) + { + bsStream = f; + bsLive = 0; + bsBuff = 0; + } + + private int BsR(int n) + { + int v; + while (bsLive < n) + { + int zzi; + int thech = '\0'; + try + { + thech = (char)bsStream.ReadByte(); + } + catch (IOException) + { + CompressedStreamEOF(); + } + if (thech == '\uffff') + { + CompressedStreamEOF(); + } + zzi = thech; + bsBuff = (bsBuff << 8) | (zzi & 0xff); + bsLive += 8; + } + + v = (bsBuff >> (bsLive - n)) & ((1 << n) - 1); + bsLive -= n; + return v; + } + + private char BsGetUChar() + { + return (char)BsR(8); + } + + private int BsGetint() + { + var u = 0; + u = (u << 8) | BsR(8); + u = (u << 8) | BsR(8); + u = (u << 8) | BsR(8); + u = (u << 8) | BsR(8); + return u; + } + + private int BsGetIntVS(int numBits) + { + return BsR(numBits); + } + + private int BsGetInt32() + { + return BsGetint(); + } + + private void HbCreateDecodeTables( + int[] limit, + int[] basev, + int[] perm, + char[] length, + int minLen, + int maxLen, + int alphaSize + ) + { + int pp, + i, + j, + vec; + + pp = 0; + for (i = minLen; i <= maxLen; i++) + { + for (j = 0; j < alphaSize; j++) + { + if (length[j] == i) + { + perm[pp] = j; + pp++; + } + } + } + + for (i = 0; i < BZip2Constants.MAX_CODE_LEN; i++) + { + basev[i] = 0; + } + for (i = 0; i < alphaSize; i++) + { + basev[length[i] + 1]++; + } + + for (i = 1; i < BZip2Constants.MAX_CODE_LEN; i++) + { + basev[i] += basev[i - 1]; + } + + for (i = 0; i < BZip2Constants.MAX_CODE_LEN; i++) + { + limit[i] = 0; + } + vec = 0; + + for (i = minLen; i <= maxLen; i++) + { + vec += (basev[i + 1] - basev[i]); + limit[i] = vec - 1; + vec <<= 1; + } + for (i = minLen + 1; i <= maxLen; i++) + { + basev[i] = ((limit[i - 1] + 1) << 1) - basev[i]; + } + } + + private void RecvDecodingTables() + { + var len = InitCharArray(BZip2Constants.N_GROUPS, BZip2Constants.MAX_ALPHA_SIZE); + int i, + j, + t, + nGroups, + nSelectors, + alphaSize; + int minLen, + maxLen; + var inUse16 = new bool[16]; + + /* Receive the mapping table */ + for (i = 0; i < 16; i++) + { if (BsR(1) == 1) { - blockRandomised = true; + inUse16[i] = true; } else { - blockRandomised = false; + inUse16[i] = false; } - - // currBlockNo++; - GetAndMoveToFrontDecode(); - - mCrc.InitialiseCRC(); - currentState = START_BLOCK_STATE; } - private void EndBlock() + for (i = 0; i < 256; i++) { - computedBlockCRC = mCrc.GetFinalCRC(); - /* A bad CRC is considered a fatal error. */ - if (storedBlockCRC != computedBlockCRC) + inUse[i] = false; + } + + for (i = 0; i < 16; i++) + { + if (inUse16[i]) { - CrcError(); - } - - computedCombinedCRC = - (computedCombinedCRC << 1) | (int)(((uint)computedCombinedCRC) >> 31); - computedCombinedCRC ^= computedBlockCRC; - } - - private bool Complete() - { - storedCombinedCRC = BsGetInt32(); - if (storedCombinedCRC != computedCombinedCRC) - { - CrcError(); - } - - bool complete = !decompressConcatenated || !Initialize(false); - if (complete) - { - BsFinishedWithStream(); - streamEnd = true; - } - - // Look for the next .bz2 stream if decompressing - // concatenated files. - return complete; - } - - private static void BlockOverrun() - { - Cadvise(); - } - - private static void BadBlockHeader() - { - Cadvise(); - } - - private static void CrcError() - { - Cadvise(); - } - - private void BsFinishedWithStream() - { - bsStream?.Dispose(); - bsStream = null; - } - - private void BsSetStream(Stream f) - { - bsStream = f; - bsLive = 0; - bsBuff = 0; - } - - private int BsR(int n) - { - int v; - while (bsLive < n) - { - int zzi; - int thech = '\0'; - try + for (j = 0; j < 16; j++) { - thech = (char)bsStream.ReadByte(); - } - catch (IOException) - { - CompressedStreamEOF(); - } - if (thech == '\uffff') - { - CompressedStreamEOF(); - } - zzi = thech; - bsBuff = (bsBuff << 8) | (zzi & 0xff); - bsLive += 8; - } - - v = (bsBuff >> (bsLive - n)) & ((1 << n) - 1); - bsLive -= n; - return v; - } - - private char BsGetUChar() - { - return (char)BsR(8); - } - - private int BsGetint() - { - int u = 0; - u = (u << 8) | BsR(8); - u = (u << 8) | BsR(8); - u = (u << 8) | BsR(8); - u = (u << 8) | BsR(8); - return u; - } - - private int BsGetIntVS(int numBits) - { - return BsR(numBits); - } - - private int BsGetInt32() - { - return BsGetint(); - } - - private void HbCreateDecodeTables( - int[] limit, - int[] basev, - int[] perm, - char[] length, - int minLen, - int maxLen, - int alphaSize - ) - { - int pp, - i, - j, - vec; - - pp = 0; - for (i = minLen; i <= maxLen; i++) - { - for (j = 0; j < alphaSize; j++) - { - if (length[j] == i) + if (BsR(1) == 1) { - perm[pp] = j; - pp++; + inUse[(i * 16) + j] = true; } } } - - for (i = 0; i < BZip2Constants.MAX_CODE_LEN; i++) - { - basev[i] = 0; - } - for (i = 0; i < alphaSize; i++) - { - basev[length[i] + 1]++; - } - - for (i = 1; i < BZip2Constants.MAX_CODE_LEN; i++) - { - basev[i] += basev[i - 1]; - } - - for (i = 0; i < BZip2Constants.MAX_CODE_LEN; i++) - { - limit[i] = 0; - } - vec = 0; - - for (i = minLen; i <= maxLen; i++) - { - vec += (basev[i + 1] - basev[i]); - limit[i] = vec - 1; - vec <<= 1; - } - for (i = minLen + 1; i <= maxLen; i++) - { - basev[i] = ((limit[i - 1] + 1) << 1) - basev[i]; - } } - private void RecvDecodingTables() + MakeMaps(); + alphaSize = nInUse + 2; + + /* Now the selectors */ + nGroups = BsR(3); + nSelectors = BsR(15); + for (i = 0; i < nSelectors; i++) { - char[][] len = InitCharArray(BZip2Constants.N_GROUPS, BZip2Constants.MAX_ALPHA_SIZE); - int i, - j, - t, - nGroups, - nSelectors, - alphaSize; - int minLen, - maxLen; - bool[] inUse16 = new bool[16]; - - /* Receive the mapping table */ - for (i = 0; i < 16; i++) + j = 0; + while (BsR(1) == 1) { - if (BsR(1) == 1) - { - inUse16[i] = true; - } - else - { - inUse16[i] = false; - } + j++; + } + selectorMtf[i] = (char)j; + } + + /* Undo the MTF values for the selectors. */ + { + var pos = new char[BZip2Constants.N_GROUPS]; + char tmp, + v; + for (v = '\0'; v < nGroups; v++) + { + pos[v] = v; } - for (i = 0; i < 256; i++) - { - inUse[i] = false; - } - - for (i = 0; i < 16; i++) - { - if (inUse16[i]) - { - for (j = 0; j < 16; j++) - { - if (BsR(1) == 1) - { - inUse[i * 16 + j] = true; - } - } - } - } - - MakeMaps(); - alphaSize = nInUse + 2; - - /* Now the selectors */ - nGroups = BsR(3); - nSelectors = BsR(15); for (i = 0; i < nSelectors; i++) { - j = 0; - while (BsR(1) == 1) + v = selectorMtf[i]; + tmp = pos[v]; + while (v > 0) { - j++; + pos[v] = pos[v - 1]; + v--; } - selectorMtf[i] = (char)j; - } - - /* Undo the MTF values for the selectors. */ - { - char[] pos = new char[BZip2Constants.N_GROUPS]; - char tmp, - v; - for (v = '\0'; v < nGroups; v++) - { - pos[v] = v; - } - - for (i = 0; i < nSelectors; i++) - { - v = selectorMtf[i]; - tmp = pos[v]; - while (v > 0) - { - pos[v] = pos[v - 1]; - v--; - } - pos[0] = tmp; - selector[i] = tmp; - } - } - - /* Now the coding tables */ - for (t = 0; t < nGroups; t++) - { - int curr = BsR(5); - for (i = 0; i < alphaSize; i++) - { - while (BsR(1) == 1) - { - if (BsR(1) == 0) - { - curr++; - } - else - { - curr--; - } - } - len[t][i] = (char)curr; - } - } - - /* Create the Huffman decoding tables */ - for (t = 0; t < nGroups; t++) - { - minLen = 32; - maxLen = 0; - for (i = 0; i < alphaSize; i++) - { - if (len[t][i] > maxLen) - { - maxLen = len[t][i]; - } - if (len[t][i] < minLen) - { - minLen = len[t][i]; - } - } - HbCreateDecodeTables( - limit[t], - basev[t], - perm[t], - len[t], - minLen, - maxLen, - alphaSize - ); - minLens[t] = minLen; + pos[0] = tmp; + selector[i] = tmp; } } - private void GetAndMoveToFrontDecode() + /* Now the coding tables */ + for (t = 0; t < nGroups; t++) { - char[] yy = new char[256]; - int i, - j, - nextSym, - limitLast; - int EOB, - groupNo, - groupPos; - - limitLast = BZip2Constants.baseBlockSize * blockSize100k; - origPtr = BsGetIntVS(24); - - RecvDecodingTables(); - EOB = nInUse + 1; - groupNo = -1; - groupPos = 0; - - /* - Setting up the unzftab entries here is not strictly - necessary, but it does save having to do it later - in a separate pass, and so saves a block's worth of - cache misses. - */ - for (i = 0; i <= 255; i++) + var curr = BsR(5); + for (i = 0; i < alphaSize; i++) { - unzftab[i] = 0; + while (BsR(1) == 1) + { + if (BsR(1) == 0) + { + curr++; + } + else + { + curr--; + } + } + len[t][i] = (char)curr; + } + } + + /* Create the Huffman decoding tables */ + for (t = 0; t < nGroups; t++) + { + minLen = 32; + maxLen = 0; + for (i = 0; i < alphaSize; i++) + { + if (len[t][i] > maxLen) + { + maxLen = len[t][i]; + } + if (len[t][i] < minLen) + { + minLen = len[t][i]; + } + } + HbCreateDecodeTables( + limit[t], + basev[t], + perm[t], + len[t], + minLen, + maxLen, + alphaSize + ); + minLens[t] = minLen; + } + } + + private void GetAndMoveToFrontDecode() + { + var yy = new char[256]; + int i, + j, + nextSym, + limitLast; + int EOB, + groupNo, + groupPos; + + limitLast = BZip2Constants.baseBlockSize * blockSize100k; + origPtr = BsGetIntVS(24); + + RecvDecodingTables(); + EOB = nInUse + 1; + groupNo = -1; + groupPos = 0; + + /* + Setting up the unzftab entries here is not strictly + necessary, but it does save having to do it later + in a separate pass, and so saves a block's worth of + cache misses. + */ + for (i = 0; i <= 255; i++) + { + unzftab[i] = 0; + } + + for (i = 0; i <= 255; i++) + { + yy[i] = (char)i; + } + + last = -1; + + { + int zt, + zn, + zvec, + zj; + if (groupPos == 0) + { + groupNo++; + groupPos = BZip2Constants.G_SIZE; + } + groupPos--; + zt = selector[groupNo]; + zn = minLens[zt]; + zvec = BsR(zn); + while (zvec > limit[zt][zn]) + { + zn++; + { + { + while (bsLive < 1) + { + int zzi; + var thech = '\0'; + try + { + thech = (char)bsStream.ReadByte(); + } + catch (IOException) + { + CompressedStreamEOF(); + } + if (thech == '\uffff') + { + CompressedStreamEOF(); + } + zzi = thech; + bsBuff = (bsBuff << 8) | (zzi & 0xff); + bsLive += 8; + } + } + zj = (bsBuff >> (bsLive - 1)) & 1; + bsLive--; + } + zvec = (zvec << 1) | zj; + } + nextSym = perm[zt][zvec - basev[zt][zn]]; + } + + while (true) + { + if (nextSym == EOB) + { + break; } - for (i = 0; i <= 255; i++) + if (nextSym == BZip2Constants.RUNA || nextSym == BZip2Constants.RUNB) { - yy[i] = (char)i; - } - - last = -1; - - { - int zt, - zn, - zvec, - zj; - if (groupPos == 0) + char ch; + var s = -1; + var N = 1; + do { - groupNo++; - groupPos = BZip2Constants.G_SIZE; - } - groupPos--; - zt = selector[groupNo]; - zn = minLens[zt]; - zvec = BsR(zn); - while (zvec > limit[zt][zn]) - { - zn++; + if (nextSym == BZip2Constants.RUNA) { - { - while (bsLive < 1) - { - int zzi; - char thech = '\0'; - try - { - thech = (char)bsStream.ReadByte(); - } - catch (IOException) - { - CompressedStreamEOF(); - } - if (thech == '\uffff') - { - CompressedStreamEOF(); - } - zzi = thech; - bsBuff = (bsBuff << 8) | (zzi & 0xff); - bsLive += 8; - } - } - zj = (bsBuff >> (bsLive - 1)) & 1; - bsLive--; + s += (0 + 1) * N; } - zvec = (zvec << 1) | zj; - } - nextSym = perm[zt][zvec - basev[zt][zn]]; - } - - while (true) - { - if (nextSym == EOB) - { - break; - } - - if (nextSym == BZip2Constants.RUNA || nextSym == BZip2Constants.RUNB) - { - char ch; - int s = -1; - int N = 1; - do + else if (nextSym == BZip2Constants.RUNB) { - if (nextSym == BZip2Constants.RUNA) - { - s = s + (0 + 1) * N; - } - else if (nextSym == BZip2Constants.RUNB) - { - s = s + (1 + 1) * N; - } - N = N * 2; - { - int zt, - zn, - zvec, - zj; - if (groupPos == 0) - { - groupNo++; - groupPos = BZip2Constants.G_SIZE; - } - groupPos--; - zt = selector[groupNo]; - zn = minLens[zt]; - zvec = BsR(zn); - while (zvec > limit[zt][zn]) - { - zn++; - { - { - while (bsLive < 1) - { - int zzi; - char thech = '\0'; - try - { - thech = (char)bsStream.ReadByte(); - } - catch (IOException) - { - CompressedStreamEOF(); - } - if (thech == '\uffff') - { - CompressedStreamEOF(); - } - zzi = thech; - bsBuff = (bsBuff << 8) | (zzi & 0xff); - bsLive += 8; - } - } - zj = (bsBuff >> (bsLive - 1)) & 1; - bsLive--; - } - zvec = (zvec << 1) | zj; - } - nextSym = perm[zt][zvec - basev[zt][zn]]; - } - } while (nextSym == BZip2Constants.RUNA || nextSym == BZip2Constants.RUNB); - - s++; - ch = seqToUnseq[yy[0]]; - unzftab[ch] += s; - - while (s > 0) - { - last++; - ll8[last] = ch; - s--; + s += (1 + 1) * N; } - - if (last >= limitLast) - { - BlockOverrun(); - } - } - else - { - char tmp; - last++; - if (last >= limitLast) - { - BlockOverrun(); - } - - tmp = yy[nextSym - 1]; - unzftab[seqToUnseq[tmp]]++; - ll8[last] = seqToUnseq[tmp]; - - /* - This loop is hammered during decompression, - hence the unrolling. - - for (j = nextSym-1; j > 0; j--) yy[j] = yy[j-1]; - */ - - j = nextSym - 1; - for (; j > 3; j -= 4) - { - yy[j] = yy[j - 1]; - yy[j - 1] = yy[j - 2]; - yy[j - 2] = yy[j - 3]; - yy[j - 3] = yy[j - 4]; - } - for (; j > 0; j--) - { - yy[j] = yy[j - 1]; - } - - yy[0] = tmp; + N *= 2; { int zt, zn, @@ -876,7 +774,7 @@ namespace SharpCompress.Compressors.BZip2 while (bsLive < 1) { int zzi; - char thech = '\0'; + var thech = '\0'; try { thech = (char)bsStream.ReadByte(); @@ -885,6 +783,10 @@ namespace SharpCompress.Compressors.BZip2 { CompressedStreamEOF(); } + if (thech == '\uffff') + { + CompressedStreamEOF(); + } zzi = thech; bsBuff = (bsBuff << 8) | (zzi & 0xff); bsLive += 8; @@ -897,56 +799,212 @@ namespace SharpCompress.Compressors.BZip2 } nextSym = perm[zt][zvec - basev[zt][zn]]; } + } while (nextSym == BZip2Constants.RUNA || nextSym == BZip2Constants.RUNB); + + s++; + ch = seqToUnseq[yy[0]]; + unzftab[ch] += s; + + while (s > 0) + { + last++; + ll8[last] = ch; + s--; } - } - } - private void SetupBlock() - { - Span cftab = stackalloc int[257]; - char ch; - - cftab[0] = 0; - for (i = 1; i <= 256; i++) - { - cftab[i] = unzftab[i - 1]; - } - for (i = 1; i <= 256; i++) - { - cftab[i] += cftab[i - 1]; - } - - for (i = 0; i <= last; i++) - { - ch = ll8[i]; - tt[cftab[ch]] = i; - cftab[ch]++; - } - - tPos = tt[origPtr]; - - count = 0; - i2 = 0; - ch2 = 256; /* not a char and not EOF */ - - if (blockRandomised) - { - rNToGo = 0; - rTPos = 0; - SetupRandPartA(); + if (last >= limitLast) + { + BlockOverrun(); + } } else { - SetupNoRandPartA(); + char tmp; + last++; + if (last >= limitLast) + { + BlockOverrun(); + } + + tmp = yy[nextSym - 1]; + unzftab[seqToUnseq[tmp]]++; + ll8[last] = seqToUnseq[tmp]; + + /* + This loop is hammered during decompression, + hence the unrolling. + + for (j = nextSym-1; j > 0; j--) yy[j] = yy[j-1]; + */ + + j = nextSym - 1; + for (; j > 3; j -= 4) + { + yy[j] = yy[j - 1]; + yy[j - 1] = yy[j - 2]; + yy[j - 2] = yy[j - 3]; + yy[j - 3] = yy[j - 4]; + } + for (; j > 0; j--) + { + yy[j] = yy[j - 1]; + } + + yy[0] = tmp; + { + int zt, + zn, + zvec, + zj; + if (groupPos == 0) + { + groupNo++; + groupPos = BZip2Constants.G_SIZE; + } + groupPos--; + zt = selector[groupNo]; + zn = minLens[zt]; + zvec = BsR(zn); + while (zvec > limit[zt][zn]) + { + zn++; + { + { + while (bsLive < 1) + { + int zzi; + var thech = '\0'; + try + { + thech = (char)bsStream.ReadByte(); + } + catch (IOException) + { + CompressedStreamEOF(); + } + zzi = thech; + bsBuff = (bsBuff << 8) | (zzi & 0xff); + bsLive += 8; + } + } + zj = (bsBuff >> (bsLive - 1)) & 1; + bsLive--; + } + zvec = (zvec << 1) | zj; + } + nextSym = perm[zt][zvec - basev[zt][zn]]; + } } } + } - private void SetupRandPartA() + private void SetupBlock() + { + Span cftab = stackalloc int[257]; + char ch; + + cftab[0] = 0; + for (i = 1; i <= 256; i++) { - if (i2 <= last) + cftab[i] = unzftab[i - 1]; + } + for (i = 1; i <= 256; i++) + { + cftab[i] += cftab[i - 1]; + } + + for (i = 0; i <= last; i++) + { + ch = ll8[i]; + tt[cftab[ch]] = i; + cftab[ch]++; + } + + tPos = tt[origPtr]; + + count = 0; + i2 = 0; + ch2 = 256; /* not a char and not EOF */ + + if (blockRandomised) + { + rNToGo = 0; + rTPos = 0; + SetupRandPartA(); + } + else + { + SetupNoRandPartA(); + } + } + + private void SetupRandPartA() + { + if (i2 <= last) + { + chPrev = ch2; + ch2 = ll8[tPos]; + tPos = tt[tPos]; + if (rNToGo == 0) { - chPrev = ch2; - ch2 = ll8[tPos]; + rNToGo = BZip2Constants.rNums[rTPos]; + rTPos++; + if (rTPos == 512) + { + rTPos = 0; + } + } + rNToGo--; + ch2 ^= (rNToGo == 1) ? 1 : 0; + i2++; + + currentChar = ch2; + currentState = RAND_PART_B_STATE; + mCrc.UpdateCRC(ch2); + } + else + { + EndBlock(); + InitBlock(); + SetupBlock(); + } + } + + private void SetupNoRandPartA() + { + if (i2 <= last) + { + chPrev = ch2; + ch2 = ll8[tPos]; + tPos = tt[tPos]; + i2++; + + currentChar = ch2; + currentState = NO_RAND_PART_B_STATE; + mCrc.UpdateCRC(ch2); + } + else + { + EndBlock(); + InitBlock(); + SetupBlock(); + } + } + + private void SetupRandPartB() + { + if (ch2 != chPrev) + { + currentState = RAND_PART_A_STATE; + count = 1; + SetupRandPartA(); + } + else + { + count++; + if (count >= 4) + { + z = ll8[tPos]; tPos = tt[tPos]; if (rNToGo == 0) { @@ -958,201 +1016,139 @@ namespace SharpCompress.Compressors.BZip2 } } rNToGo--; - ch2 ^= (rNToGo == 1) ? 1 : 0; - i2++; - - currentChar = ch2; - currentState = RAND_PART_B_STATE; - mCrc.UpdateCRC(ch2); - } - else - { - EndBlock(); - InitBlock(); - SetupBlock(); - } - } - - private void SetupNoRandPartA() - { - if (i2 <= last) - { - chPrev = ch2; - ch2 = ll8[tPos]; - tPos = tt[tPos]; - i2++; - - currentChar = ch2; - currentState = NO_RAND_PART_B_STATE; - mCrc.UpdateCRC(ch2); - } - else - { - EndBlock(); - InitBlock(); - SetupBlock(); - } - } - - private void SetupRandPartB() - { - if (ch2 != chPrev) - { - currentState = RAND_PART_A_STATE; - count = 1; - SetupRandPartA(); - } - else - { - count++; - if (count >= 4) - { - z = ll8[tPos]; - tPos = tt[tPos]; - if (rNToGo == 0) - { - rNToGo = BZip2Constants.rNums[rTPos]; - rTPos++; - if (rTPos == 512) - { - rTPos = 0; - } - } - rNToGo--; - z ^= (char)((rNToGo == 1) ? 1 : 0); - j2 = 0; - currentState = RAND_PART_C_STATE; - SetupRandPartC(); - } - else - { - currentState = RAND_PART_A_STATE; - SetupRandPartA(); - } - } - } - - private void SetupRandPartC() - { - if (j2 < z) - { - currentChar = ch2; - mCrc.UpdateCRC(ch2); - j2++; + z ^= (char)((rNToGo == 1) ? 1 : 0); + j2 = 0; + currentState = RAND_PART_C_STATE; + SetupRandPartC(); } else { currentState = RAND_PART_A_STATE; - i2++; - count = 0; SetupRandPartA(); } } - - private void SetupNoRandPartB() - { - if (ch2 != chPrev) - { - currentState = NO_RAND_PART_A_STATE; - count = 1; - SetupNoRandPartA(); - } - else - { - count++; - if (count >= 4) - { - z = ll8[tPos]; - tPos = tt[tPos]; - currentState = NO_RAND_PART_C_STATE; - j2 = 0; - SetupNoRandPartC(); - } - else - { - currentState = NO_RAND_PART_A_STATE; - SetupNoRandPartA(); - } - } - } - - private void SetupNoRandPartC() - { - if (j2 < z) - { - currentChar = ch2; - mCrc.UpdateCRC(ch2); - j2++; - } - else - { - currentState = NO_RAND_PART_A_STATE; - i2++; - count = 0; - SetupNoRandPartA(); - } - } - - private void SetDecompressStructureSizes(int newSize100k) - { - if (!(0 <= newSize100k && newSize100k <= 9 && 0 <= blockSize100k && blockSize100k <= 9)) - { - // throw new IOException("Invalid block size"); - } - - blockSize100k = newSize100k; - - if (newSize100k == 0) - { - return; - } - - int n = BZip2Constants.baseBlockSize * newSize100k; - ll8 = new char[n]; - tt = new int[n]; - } - - public override void Flush() { } - - public override int Read(byte[] buffer, int offset, int count) - { - int c = -1; - int k; - for (k = 0; k < count; ++k) - { - c = ReadByte(); - if (c == -1) - { - break; - } - buffer[k + offset] = (byte)c; - } - return k; - } - - public override long Seek(long offset, SeekOrigin origin) - { - return 0; - } - - public override void SetLength(long value) { } - - public override void Write(byte[] buffer, int offset, int count) { } - - public override void WriteByte(byte value) { } - - public override bool CanRead => true; - - public override bool CanSeek => false; - - public override bool CanWrite => false; - - public override long Length => 0; - - public override long Position - { - get { return 0; } - set { } - } + } + + private void SetupRandPartC() + { + if (j2 < z) + { + currentChar = ch2; + mCrc.UpdateCRC(ch2); + j2++; + } + else + { + currentState = RAND_PART_A_STATE; + i2++; + count = 0; + SetupRandPartA(); + } + } + + private void SetupNoRandPartB() + { + if (ch2 != chPrev) + { + currentState = NO_RAND_PART_A_STATE; + count = 1; + SetupNoRandPartA(); + } + else + { + count++; + if (count >= 4) + { + z = ll8[tPos]; + tPos = tt[tPos]; + currentState = NO_RAND_PART_C_STATE; + j2 = 0; + SetupNoRandPartC(); + } + else + { + currentState = NO_RAND_PART_A_STATE; + SetupNoRandPartA(); + } + } + } + + private void SetupNoRandPartC() + { + if (j2 < z) + { + currentChar = ch2; + mCrc.UpdateCRC(ch2); + j2++; + } + else + { + currentState = NO_RAND_PART_A_STATE; + i2++; + count = 0; + SetupNoRandPartA(); + } + } + + private void SetDecompressStructureSizes(int newSize100k) + { + if (!(0 <= newSize100k && newSize100k <= 9 && 0 <= blockSize100k && blockSize100k <= 9)) + { + // throw new IOException("Invalid block size"); + } + + blockSize100k = newSize100k; + + if (newSize100k == 0) + { + return; + } + + var n = BZip2Constants.baseBlockSize * newSize100k; + ll8 = new char[n]; + tt = new int[n]; + } + + public override void Flush() { } + + public override int Read(byte[] buffer, int offset, int count) + { + var c = -1; + int k; + for (k = 0; k < count; ++k) + { + c = ReadByte(); + if (c == -1) + { + break; + } + buffer[k + offset] = (byte)c; + } + return k; + } + + public override long Seek(long offset, SeekOrigin origin) + { + return 0; + } + + public override void SetLength(long value) { } + + public override void Write(byte[] buffer, int offset, int count) { } + + public override void WriteByte(byte value) { } + + public override bool CanRead => true; + + public override bool CanSeek => false; + + public override bool CanWrite => false; + + public override long Length => 0; + + public override long Position + { + get { return 0; } + set { } } } diff --git a/src/SharpCompress/Compressors/BZip2/CBZip2OutputStream.cs b/src/SharpCompress/Compressors/BZip2/CBZip2OutputStream.cs index 2e0f8005..d2bf3448 100644 --- a/src/SharpCompress/Compressors/BZip2/CBZip2OutputStream.cs +++ b/src/SharpCompress/Compressors/BZip2/CBZip2OutputStream.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; /* @@ -25,1030 +25,772 @@ using System.IO; #nullable disable -namespace SharpCompress.Compressors.BZip2 +namespace SharpCompress.Compressors.BZip2; + +/** + * An output stream that compresses into the BZip2 format (with the file + * header chars) into another stream. + * + * @author Keiron Liddle + * + * TODO: Update to BZip2 1.0.1 + * NB: note this class has been modified to add a leading BZ to the + * start of the BZIP2 stream to make it compatible with other PGP programs. + */ + +internal sealed class CBZip2OutputStream : Stream { - /** - * An output stream that compresses into the BZip2 format (with the file - * header chars) into another stream. - * - * @author Keiron Liddle - * - * TODO: Update to BZip2 1.0.1 - * NB: note this class has been modified to add a leading BZ to the - * start of the BZIP2 stream to make it compatible with other PGP programs. - */ + private const int SETMASK = (1 << 21); + private const int CLEARMASK = (~SETMASK); + private const int GREATER_ICOST = 15; + private const int LESSER_ICOST = 0; + private const int SMALL_THRESH = 20; + private const int DEPTH_THRESH = 10; - internal sealed class CBZip2OutputStream : Stream + /* + If you are ever unlucky/improbable enough + to get a stack overflow whilst sorting, + increase the following constant and try + again. In practice I have never seen the + stack go above 27 elems, so the following + limit seems very generous. + */ + private const int QSORT_STACK_SIZE = 1000; + private bool finished; + + private static void Panic() { - private const int SETMASK = (1 << 21); - private const int CLEARMASK = (~SETMASK); - private const int GREATER_ICOST = 15; - private const int LESSER_ICOST = 0; - private const int SMALL_THRESH = 20; - private const int DEPTH_THRESH = 10; + //System.out.Println("panic"); + //throw new CError(); + } + private void MakeMaps() + { + int i; + nInUse = 0; + for (i = 0; i < 256; i++) + { + if (inUse[i]) + { + seqToUnseq[nInUse] = (char)i; + unseqToSeq[i] = (char)nInUse; + nInUse++; + } + } + } + + private static void HbMakeCodeLengths(char[] len, int[] freq, int alphaSize, int maxLen) + { /* - If you are ever unlucky/improbable enough - to get a stack overflow whilst sorting, - increase the following constant and try - again. In practice I have never seen the - stack go above 27 elems, so the following - limit seems very generous. + Nodes and heap entries run from 1. Entry 0 + for both the heap and nodes is a sentinel. */ - private const int QSORT_STACK_SIZE = 1000; - private bool finished; + int nNodes, + nHeap, + n1, + n2, + i, + j, + k; + bool tooLong; - private static void Panic() + Span heap = stackalloc int[BZip2Constants.MAX_ALPHA_SIZE + 2]; // 1040 bytes + Span weight = stackalloc int[BZip2Constants.MAX_ALPHA_SIZE * 2]; // 1040 bytes + Span parent = stackalloc int[BZip2Constants.MAX_ALPHA_SIZE * 2]; // 1040 bytes + + for (i = 0; i < alphaSize; i++) { - //System.out.Println("panic"); - //throw new CError(); + weight[i + 1] = (freq[i] == 0 ? 1 : freq[i]) << 8; } - private void MakeMaps() + while (true) { - int i; - nInUse = 0; - for (i = 0; i < 256; i++) + nNodes = alphaSize; + nHeap = 0; + + heap[0] = 0; + weight[0] = 0; + parent[0] = -2; + + for (i = 1; i <= alphaSize; i++) { - if (inUse[i]) + parent[i] = -1; + nHeap++; + heap[nHeap] = i; { - seqToUnseq[nInUse] = (char)i; - unseqToSeq[i] = (char)nInUse; - nInUse++; + int zz, + tmp; + zz = nHeap; + tmp = heap[zz]; + while (weight[tmp] < weight[heap[zz >> 1]]) + { + heap[zz] = heap[zz >> 1]; + zz >>= 1; + } + heap[zz] = tmp; } } - } - - private static void HbMakeCodeLengths(char[] len, int[] freq, int alphaSize, int maxLen) - { - /* - Nodes and heap entries run from 1. Entry 0 - for both the heap and nodes is a sentinel. - */ - int nNodes, - nHeap, - n1, - n2, - i, - j, - k; - bool tooLong; - - Span heap = stackalloc int[BZip2Constants.MAX_ALPHA_SIZE + 2]; // 1040 bytes - Span weight = stackalloc int[BZip2Constants.MAX_ALPHA_SIZE * 2]; // 1040 bytes - Span parent = stackalloc int[BZip2Constants.MAX_ALPHA_SIZE * 2]; // 1040 bytes - - for (i = 0; i < alphaSize; i++) + if (!(nHeap < (BZip2Constants.MAX_ALPHA_SIZE + 2))) { - weight[i + 1] = (freq[i] == 0 ? 1 : freq[i]) << 8; + Panic(); } - while (true) + while (nHeap > 1) { - nNodes = alphaSize; - nHeap = 0; - - heap[0] = 0; - weight[0] = 0; - parent[0] = -2; - - for (i = 1; i <= alphaSize; i++) + n1 = heap[1]; + heap[1] = heap[nHeap]; + nHeap--; { - parent[i] = -1; - nHeap++; - heap[nHeap] = i; + int zz = 0, + yy = 0, + tmp = 0; + zz = 1; + tmp = heap[zz]; + while (true) { - int zz, - tmp; - zz = nHeap; - tmp = heap[zz]; - while (weight[tmp] < weight[heap[zz >> 1]]) + yy = zz << 1; + if (yy > nHeap) { - heap[zz] = heap[zz >> 1]; - zz >>= 1; + break; } - heap[zz] = tmp; + if (yy < nHeap && weight[heap[yy + 1]] < weight[heap[yy]]) + { + yy++; + } + if (weight[tmp] < weight[heap[yy]]) + { + break; + } + heap[zz] = heap[yy]; + zz = yy; } + heap[zz] = tmp; } - if (!(nHeap < (BZip2Constants.MAX_ALPHA_SIZE + 2))) + n2 = heap[1]; + heap[1] = heap[nHeap]; + nHeap--; { - Panic(); + int zz = 0, + yy = 0, + tmp = 0; + zz = 1; + tmp = heap[zz]; + while (true) + { + yy = zz << 1; + if (yy > nHeap) + { + break; + } + if (yy < nHeap && weight[heap[yy + 1]] < weight[heap[yy]]) + { + yy++; + } + if (weight[tmp] < weight[heap[yy]]) + { + break; + } + heap[zz] = heap[yy]; + zz = yy; + } + heap[zz] = tmp; } + nNodes++; + parent[n1] = parent[n2] = nNodes; - while (nHeap > 1) - { - n1 = heap[1]; - heap[1] = heap[nHeap]; - nHeap--; - { - int zz = 0, - yy = 0, - tmp = 0; - zz = 1; - tmp = heap[zz]; - while (true) - { - yy = zz << 1; - if (yy > nHeap) - { - break; - } - if (yy < nHeap && weight[heap[yy + 1]] < weight[heap[yy]]) - { - yy++; - } - if (weight[tmp] < weight[heap[yy]]) - { - break; - } - heap[zz] = heap[yy]; - zz = yy; - } - heap[zz] = tmp; - } - n2 = heap[1]; - heap[1] = heap[nHeap]; - nHeap--; - { - int zz = 0, - yy = 0, - tmp = 0; - zz = 1; - tmp = heap[zz]; - while (true) - { - yy = zz << 1; - if (yy > nHeap) - { - break; - } - if (yy < nHeap && weight[heap[yy + 1]] < weight[heap[yy]]) - { - yy++; - } - if (weight[tmp] < weight[heap[yy]]) - { - break; - } - heap[zz] = heap[yy]; - zz = yy; - } - heap[zz] = tmp; - } - nNodes++; - parent[n1] = parent[n2] = nNodes; - - weight[nNodes] = (int)( - (uint)((weight[n1] & 0xffffff00) + (weight[n2] & 0xffffff00)) - | (uint)( - 1 - + ( - ((weight[n1] & 0x000000ff) > (weight[n2] & 0x000000ff)) - ? (weight[n1] & 0x000000ff) - : (weight[n2] & 0x000000ff) - ) + weight[nNodes] = (int)( + (uint)((weight[n1] & 0xffffff00) + (weight[n2] & 0xffffff00)) + | (uint)( + 1 + + ( + ((weight[n1] & 0x000000ff) > (weight[n2] & 0x000000ff)) + ? (weight[n1] & 0x000000ff) + : (weight[n2] & 0x000000ff) ) - ); + ) + ); - parent[nNodes] = -1; - nHeap++; - heap[nHeap] = nNodes; + parent[nNodes] = -1; + nHeap++; + heap[nHeap] = nNodes; + { + int zz = 0, + tmp = 0; + zz = nHeap; + tmp = heap[zz]; + while (weight[tmp] < weight[heap[zz >> 1]]) { - int zz = 0, - tmp = 0; - zz = nHeap; - tmp = heap[zz]; - while (weight[tmp] < weight[heap[zz >> 1]]) - { - heap[zz] = heap[zz >> 1]; - zz >>= 1; - } - heap[zz] = tmp; + heap[zz] = heap[zz >> 1]; + zz >>= 1; } + heap[zz] = tmp; } - if (!(nNodes < (BZip2Constants.MAX_ALPHA_SIZE * 2))) - { - Panic(); - } + } + if (!(nNodes < (BZip2Constants.MAX_ALPHA_SIZE * 2))) + { + Panic(); + } - tooLong = false; - for (i = 1; i <= alphaSize; i++) + tooLong = false; + for (i = 1; i <= alphaSize; i++) + { + j = 0; + k = i; + while (parent[k] >= 0) { - j = 0; - k = i; - while (parent[k] >= 0) - { - k = parent[k]; - j++; - } - len[i - 1] = (char)j; - if (j > maxLen) - { - tooLong = true; - } + k = parent[k]; + j++; } + len[i - 1] = (char)j; + if (j > maxLen) + { + tooLong = true; + } + } - if (!tooLong) - { - break; - } + if (!tooLong) + { + break; + } - for (i = 1; i < alphaSize; i++) - { - j = weight[i] >> 8; - j = 1 + (j / 2); - weight[i] = j << 8; - } + for (i = 1; i < alphaSize; i++) + { + j = weight[i] >> 8; + j = 1 + (j / 2); + weight[i] = j << 8; } } + } - /* - index of the last char in the block, so - the block size == last + 1. - */ - private int last; + /* + index of the last char in the block, so + the block size == last + 1. + */ + private int last; - /* - index in zptr[] of original string after sorting. - */ - private int origPtr; + /* + index in zptr[] of original string after sorting. + */ + private int origPtr; - /* - always: in the range 0 .. 9. - The current block size is 100000 * this number. - */ - private readonly int blockSize100k; + /* + always: in the range 0 .. 9. + The current block size is 100000 * this number. + */ + private readonly int blockSize100k; - private bool blockRandomised; + private bool blockRandomised; - private int bytesOut; - private int bsBuff; - private int bsLive; - private readonly CRC mCrc = new CRC(); + private int bytesOut; + private int bsBuff; + private int bsLive; + private readonly CRC mCrc = new CRC(); - private readonly bool[] inUse = new bool[256]; - private int nInUse; + private readonly bool[] inUse = new bool[256]; + private int nInUse; - private readonly char[] seqToUnseq = new char[256]; - private readonly char[] unseqToSeq = new char[256]; + private readonly char[] seqToUnseq = new char[256]; + private readonly char[] unseqToSeq = new char[256]; - private readonly char[] selector = new char[BZip2Constants.MAX_SELECTORS]; - private readonly char[] selectorMtf = new char[BZip2Constants.MAX_SELECTORS]; + private readonly char[] selector = new char[BZip2Constants.MAX_SELECTORS]; + private readonly char[] selectorMtf = new char[BZip2Constants.MAX_SELECTORS]; - private char[] block; - private int[] quadrant; - private int[] zptr; - private short[] szptr; - private int[] ftab; + private char[] block; + private int[] quadrant; + private int[] zptr; + private short[] szptr; + private int[] ftab; - private int nMTF; + private int nMTF; - private readonly int[] mtfFreq = new int[BZip2Constants.MAX_ALPHA_SIZE]; + private readonly int[] mtfFreq = new int[BZip2Constants.MAX_ALPHA_SIZE]; - /* - * Used when sorting. If too many long comparisons - * happen, we stop sorting, randomise the block - * slightly, and try again. - */ - private readonly int workFactor; - private int workDone; - private int workLimit; - private bool firstAttempt; - private int nBlocksRandomised; + /* + * Used when sorting. If too many long comparisons + * happen, we stop sorting, randomise the block + * slightly, and try again. + */ + private readonly int workFactor; + private int workDone; + private int workLimit; + private bool firstAttempt; + private int nBlocksRandomised; - private int currentChar = -1; - private int runLength; + private int currentChar = -1; + private int runLength; - public CBZip2OutputStream(Stream inStream) : this(inStream, 9) { } + public CBZip2OutputStream(Stream inStream) : this(inStream, 9) { } - public CBZip2OutputStream(Stream inStream, int inBlockSize) + public CBZip2OutputStream(Stream inStream, int inBlockSize) + { + block = null; + quadrant = null; + zptr = null; + ftab = null; + + inStream.WriteByte((byte)'B'); + inStream.WriteByte((byte)'Z'); + + BsSetStream(inStream); + + workFactor = 50; + if (inBlockSize > 9) { - block = null; - quadrant = null; - zptr = null; - ftab = null; - - inStream.WriteByte((byte)'B'); - inStream.WriteByte((byte)'Z'); - - BsSetStream(inStream); - - workFactor = 50; - if (inBlockSize > 9) - { - inBlockSize = 9; - } - if (inBlockSize < 1) - { - inBlockSize = 1; - } - blockSize100k = inBlockSize; - AllocateCompressStructures(); - Initialize(); - InitBlock(); + inBlockSize = 9; } - - /** - * - * modified by Oliver Merkel, 010128 - * - */ - - public override void WriteByte(byte bv) + if (inBlockSize < 1) { - int b = (256 + bv) % 256; - if (currentChar != -1) + inBlockSize = 1; + } + blockSize100k = inBlockSize; + AllocateCompressStructures(); + Initialize(); + InitBlock(); + } + + /** + * + * modified by Oliver Merkel, 010128 + * + */ + + public override void WriteByte(byte bv) + { + var b = (256 + bv) % 256; + if (currentChar != -1) + { + if (currentChar == b) { - if (currentChar == b) - { - runLength++; - if (runLength > 254) - { - WriteRun(); - currentChar = -1; - runLength = 0; - } - } - else + runLength++; + if (runLength > 254) { WriteRun(); - runLength = 1; - currentChar = b; + currentChar = -1; + runLength = 0; } } else { - currentChar = b; - runLength++; - } - } - - private void WriteRun() - { - if (last < allowableBlockSize) - { - inUse[currentChar] = true; - for (int i = 0; i < runLength; i++) - { - mCrc.UpdateCRC((char)currentChar); - } - switch (runLength) - { - case 1: - last++; - block[last + 1] = (char)currentChar; - break; - case 2: - last++; - block[last + 1] = (char)currentChar; - last++; - block[last + 1] = (char)currentChar; - break; - case 3: - last++; - block[last + 1] = (char)currentChar; - last++; - block[last + 1] = (char)currentChar; - last++; - block[last + 1] = (char)currentChar; - break; - default: - inUse[runLength - 4] = true; - last++; - block[last + 1] = (char)currentChar; - last++; - block[last + 1] = (char)currentChar; - last++; - block[last + 1] = (char)currentChar; - last++; - block[last + 1] = (char)currentChar; - last++; - block[last + 1] = (char)(runLength - 4); - break; - } - } - else - { - EndBlock(); - InitBlock(); WriteRun(); + runLength = 1; + currentChar = b; } } - - private bool disposed; - - protected override void Dispose(bool disposing) + else { - if (disposing) + currentChar = b; + runLength++; + } + } + + private void WriteRun() + { + if (last < allowableBlockSize) + { + inUse[currentChar] = true; + for (var i = 0; i < runLength; i++) { - if (disposed) - { - return; - } - - Finish(); - - disposed = true; - base.Dispose(); - bsStream?.Dispose(); - bsStream = null; + mCrc.UpdateCRC((char)currentChar); + } + switch (runLength) + { + case 1: + last++; + block[last + 1] = (char)currentChar; + break; + case 2: + last++; + block[last + 1] = (char)currentChar; + last++; + block[last + 1] = (char)currentChar; + break; + case 3: + last++; + block[last + 1] = (char)currentChar; + last++; + block[last + 1] = (char)currentChar; + last++; + block[last + 1] = (char)currentChar; + break; + default: + inUse[runLength - 4] = true; + last++; + block[last + 1] = (char)currentChar; + last++; + block[last + 1] = (char)currentChar; + last++; + block[last + 1] = (char)currentChar; + last++; + block[last + 1] = (char)currentChar; + last++; + block[last + 1] = (char)(runLength - 4); + break; } } - - public void Finish() + else { - if (finished) + EndBlock(); + InitBlock(); + WriteRun(); + } + } + + private bool disposed; + + protected override void Dispose(bool disposing) + { + if (disposing) + { + if (disposed) { return; } - if (runLength > 0) + Finish(); + + disposed = true; + Dispose(); + bsStream?.Dispose(); + bsStream = null; + } + } + + public void Finish() + { + if (finished) + { + return; + } + + if (runLength > 0) + { + WriteRun(); + } + currentChar = -1; + EndBlock(); + EndCompression(); + finished = true; + Flush(); + } + + public override void Flush() + { + bsStream.Flush(); + } + + private int blockCRC, + combinedCRC; + + private void Initialize() + { + bytesOut = 0; + nBlocksRandomised = 0; + + /* Write `magic' bytes h indicating file-format == huffmanised, + followed by a digit indicating blockSize100k. + */ + BsPutUChar('h'); + BsPutUChar('0' + blockSize100k); + + combinedCRC = 0; + } + + private int allowableBlockSize; + + private void InitBlock() + { + // blockNo++; + mCrc.InitialiseCRC(); + last = -1; + + // ch = 0; + + for (var i = 0; i < 256; i++) + { + inUse[i] = false; + } + + /* 20 is just a paranoia constant */ + allowableBlockSize = (BZip2Constants.baseBlockSize * blockSize100k) - 20; + } + + private void EndBlock() + { + blockCRC = mCrc.GetFinalCRC(); + combinedCRC = (combinedCRC << 1) | (int)(((uint)combinedCRC) >> 31); + combinedCRC ^= blockCRC; + + /* sort the block and establish posn of original string */ + DoReversibleTransformation(); + + /* + A 6-byte block header, the value chosen arbitrarily + as 0x314159265359 :-). A 32 bit value does not really + give a strong enough guarantee that the value will not + appear by chance in the compressed datastream. Worst-case + probability of this event, for a 900k block, is about + 2.0e-3 for 32 bits, 1.0e-5 for 40 bits and 4.0e-8 for 48 bits. + For a compressed file of size 100Gb -- about 100000 blocks -- + only a 48-bit marker will do. NB: normal compression/ + decompression do *not* rely on these statistical properties. + They are only important when trying to recover blocks from + damaged files. + */ + BsPutUChar(0x31); + BsPutUChar(0x41); + BsPutUChar(0x59); + BsPutUChar(0x26); + BsPutUChar(0x53); + BsPutUChar(0x59); + + /* Now the block's CRC, so it is in a known place. */ + BsPutint(blockCRC); + + /* Now a single bit indicating randomisation. */ + if (blockRandomised) + { + BsW(1, 1); + nBlocksRandomised++; + } + else + { + BsW(1, 0); + } + + /* Finally, block's contents proper. */ + MoveToFrontCodeAndSend(); + } + + private void EndCompression() + { + /* + Now another magic 48-bit number, 0x177245385090, to + indicate the end of the last block. (Sqrt(pi), if + you want to know. I did want to use e, but it contains + too much repetition -- 27 18 28 18 28 46 -- for me + to feel statistically comfortable. Call me paranoid.) + */ + BsPutUChar(0x17); + BsPutUChar(0x72); + BsPutUChar(0x45); + BsPutUChar(0x38); + BsPutUChar(0x50); + BsPutUChar(0x90); + + BsPutint(combinedCRC); + + BsFinishedWithStream(); + } + + private void HbAssignCodes(int[] code, char[] length, int minLen, int maxLen, int alphaSize) + { + int n, + vec, + i; + + vec = 0; + for (n = minLen; n <= maxLen; n++) + { + for (i = 0; i < alphaSize; i++) { - WriteRun(); - } - currentChar = -1; - EndBlock(); - EndCompression(); - finished = true; - Flush(); - } - - public override void Flush() - { - bsStream.Flush(); - } - - private int blockCRC, - combinedCRC; - - private void Initialize() - { - bytesOut = 0; - nBlocksRandomised = 0; - - /* Write `magic' bytes h indicating file-format == huffmanised, - followed by a digit indicating blockSize100k. - */ - BsPutUChar('h'); - BsPutUChar('0' + blockSize100k); - - combinedCRC = 0; - } - - private int allowableBlockSize; - - private void InitBlock() - { - // blockNo++; - mCrc.InitialiseCRC(); - last = -1; - - // ch = 0; - - for (int i = 0; i < 256; i++) - { - inUse[i] = false; - } - - /* 20 is just a paranoia constant */ - allowableBlockSize = BZip2Constants.baseBlockSize * blockSize100k - 20; - } - - private void EndBlock() - { - blockCRC = mCrc.GetFinalCRC(); - combinedCRC = (combinedCRC << 1) | (int)(((uint)combinedCRC) >> 31); - combinedCRC ^= blockCRC; - - /* sort the block and establish posn of original string */ - DoReversibleTransformation(); - - /* - A 6-byte block header, the value chosen arbitrarily - as 0x314159265359 :-). A 32 bit value does not really - give a strong enough guarantee that the value will not - appear by chance in the compressed datastream. Worst-case - probability of this event, for a 900k block, is about - 2.0e-3 for 32 bits, 1.0e-5 for 40 bits and 4.0e-8 for 48 bits. - For a compressed file of size 100Gb -- about 100000 blocks -- - only a 48-bit marker will do. NB: normal compression/ - decompression do *not* rely on these statistical properties. - They are only important when trying to recover blocks from - damaged files. - */ - BsPutUChar(0x31); - BsPutUChar(0x41); - BsPutUChar(0x59); - BsPutUChar(0x26); - BsPutUChar(0x53); - BsPutUChar(0x59); - - /* Now the block's CRC, so it is in a known place. */ - BsPutint(blockCRC); - - /* Now a single bit indicating randomisation. */ - if (blockRandomised) - { - BsW(1, 1); - nBlocksRandomised++; - } - else - { - BsW(1, 0); - } - - /* Finally, block's contents proper. */ - MoveToFrontCodeAndSend(); - } - - private void EndCompression() - { - /* - Now another magic 48-bit number, 0x177245385090, to - indicate the end of the last block. (Sqrt(pi), if - you want to know. I did want to use e, but it contains - too much repetition -- 27 18 28 18 28 46 -- for me - to feel statistically comfortable. Call me paranoid.) - */ - BsPutUChar(0x17); - BsPutUChar(0x72); - BsPutUChar(0x45); - BsPutUChar(0x38); - BsPutUChar(0x50); - BsPutUChar(0x90); - - BsPutint(combinedCRC); - - BsFinishedWithStream(); - } - - private void HbAssignCodes(int[] code, char[] length, int minLen, int maxLen, int alphaSize) - { - int n, - vec, - i; - - vec = 0; - for (n = minLen; n <= maxLen; n++) - { - for (i = 0; i < alphaSize; i++) + if (length[i] == n) { - if (length[i] == n) + code[i] = vec; + vec++; + } + } + ; + vec <<= 1; + } + } + + private void BsSetStream(Stream f) + { + bsStream = f; + bsLive = 0; + bsBuff = 0; + bytesOut = 0; + } + + private void BsFinishedWithStream() + { + while (bsLive > 0) + { + var ch = (bsBuff >> 24); + bsStream.WriteByte((byte)ch); // write 8-bit + bsBuff <<= 8; + bsLive -= 8; + bytesOut++; + } + } + + private void BsW(int n, int v) + { + while (bsLive >= 8) + { + var ch = (bsBuff >> 24); + bsStream.WriteByte((byte)ch); // write 8-bit + bsBuff <<= 8; + bsLive -= 8; + bytesOut++; + } + bsBuff |= (v << (32 - bsLive - n)); + bsLive += n; + } + + private void BsPutUChar(int c) + { + BsW(8, c); + } + + private void BsPutint(int u) + { + BsW(8, (u >> 24) & 0xff); + BsW(8, (u >> 16) & 0xff); + BsW(8, (u >> 8) & 0xff); + BsW(8, u & 0xff); + } + + private void BsPutIntVS(int numBits, int c) + { + BsW(numBits, c); + } + + private void SendMTFValues() + { + var len = CBZip2InputStream.InitCharArray( + BZip2Constants.N_GROUPS, + BZip2Constants.MAX_ALPHA_SIZE + ); + + int v, + t, + i, + j, + gs, + ge, + totc, + bt, + bc, + iter; + int nSelectors = 0, + alphaSize, + minLen, + maxLen, + selCtr; + int nGroups; //, nBytes; + + alphaSize = nInUse + 2; + for (t = 0; t < BZip2Constants.N_GROUPS; t++) + { + for (v = 0; v < alphaSize; v++) + { + len[t][v] = (char)GREATER_ICOST; + } + } + + /* Decide how many coding tables to use */ + if (nMTF <= 0) + { + Panic(); + } + + if (nMTF < 200) + { + nGroups = 2; + } + else if (nMTF < 600) + { + nGroups = 3; + } + else if (nMTF < 1200) + { + nGroups = 4; + } + else if (nMTF < 2400) + { + nGroups = 5; + } + else + { + nGroups = 6; + } + + /* Generate an initial set of coding tables */ + { + int nPart, + remF, + tFreq, + aFreq; + + nPart = nGroups; + remF = nMTF; + gs = 0; + while (nPart > 0) + { + tFreq = remF / nPart; + ge = gs - 1; + aFreq = 0; + while (aFreq < tFreq && ge < alphaSize - 1) + { + ge++; + aFreq += mtfFreq[ge]; + } + + if (ge > gs && nPart != nGroups && nPart != 1 && ((nGroups - nPart) % 2 == 1)) + { + aFreq -= mtfFreq[ge]; + ge--; + } + + for (v = 0; v < alphaSize; v++) + { + if (v >= gs && v <= ge) { - code[i] = vec; - vec++; + len[nPart - 1][v] = (char)LESSER_ICOST; + } + else + { + len[nPart - 1][v] = (char)GREATER_ICOST; } } - ; - vec <<= 1; + + nPart--; + gs = ge + 1; + remF -= aFreq; } } - private void BsSetStream(Stream f) + var rfreq = CBZip2InputStream.InitIntArray( + BZip2Constants.N_GROUPS, + BZip2Constants.MAX_ALPHA_SIZE + ); + var fave = new int[BZip2Constants.N_GROUPS]; + var cost = new short[BZip2Constants.N_GROUPS]; + /* + Iterate up to N_ITERS times to improve the tables. + */ + for (iter = 0; iter < BZip2Constants.N_ITERS; iter++) { - bsStream = f; - bsLive = 0; - bsBuff = 0; - bytesOut = 0; - } - - private void BsFinishedWithStream() - { - while (bsLive > 0) + for (t = 0; t < nGroups; t++) { - int ch = (bsBuff >> 24); - bsStream.WriteByte((byte)ch); // write 8-bit - bsBuff <<= 8; - bsLive -= 8; - bytesOut++; + fave[t] = 0; } - } - private void BsW(int n, int v) - { - while (bsLive >= 8) - { - int ch = (bsBuff >> 24); - bsStream.WriteByte((byte)ch); // write 8-bit - bsBuff <<= 8; - bsLive -= 8; - bytesOut++; - } - bsBuff |= (v << (32 - bsLive - n)); - bsLive += n; - } - - private void BsPutUChar(int c) - { - BsW(8, c); - } - - private void BsPutint(int u) - { - BsW(8, (u >> 24) & 0xff); - BsW(8, (u >> 16) & 0xff); - BsW(8, (u >> 8) & 0xff); - BsW(8, u & 0xff); - } - - private void BsPutIntVS(int numBits, int c) - { - BsW(numBits, c); - } - - private void SendMTFValues() - { - char[][] len = CBZip2InputStream.InitCharArray( - BZip2Constants.N_GROUPS, - BZip2Constants.MAX_ALPHA_SIZE - ); - - int v, - t, - i, - j, - gs, - ge, - totc, - bt, - bc, - iter; - int nSelectors = 0, - alphaSize, - minLen, - maxLen, - selCtr; - int nGroups; //, nBytes; - - alphaSize = nInUse + 2; - for (t = 0; t < BZip2Constants.N_GROUPS; t++) + for (t = 0; t < nGroups; t++) { for (v = 0; v < alphaSize; v++) { - len[t][v] = (char)GREATER_ICOST; + rfreq[t][v] = 0; } } - /* Decide how many coding tables to use */ - if (nMTF <= 0) - { - Panic(); - } - - if (nMTF < 200) - { - nGroups = 2; - } - else if (nMTF < 600) - { - nGroups = 3; - } - else if (nMTF < 1200) - { - nGroups = 4; - } - else if (nMTF < 2400) - { - nGroups = 5; - } - else - { - nGroups = 6; - } - - /* Generate an initial set of coding tables */ - { - int nPart, - remF, - tFreq, - aFreq; - - nPart = nGroups; - remF = nMTF; - gs = 0; - while (nPart > 0) - { - tFreq = remF / nPart; - ge = gs - 1; - aFreq = 0; - while (aFreq < tFreq && ge < alphaSize - 1) - { - ge++; - aFreq += mtfFreq[ge]; - } - - if (ge > gs && nPart != nGroups && nPart != 1 && ((nGroups - nPart) % 2 == 1)) - { - aFreq -= mtfFreq[ge]; - ge--; - } - - for (v = 0; v < alphaSize; v++) - { - if (v >= gs && v <= ge) - { - len[nPart - 1][v] = (char)LESSER_ICOST; - } - else - { - len[nPart - 1][v] = (char)GREATER_ICOST; - } - } - - nPart--; - gs = ge + 1; - remF -= aFreq; - } - } - - int[][] rfreq = CBZip2InputStream.InitIntArray( - BZip2Constants.N_GROUPS, - BZip2Constants.MAX_ALPHA_SIZE - ); - int[] fave = new int[BZip2Constants.N_GROUPS]; - short[] cost = new short[BZip2Constants.N_GROUPS]; - /* - Iterate up to N_ITERS times to improve the tables. - */ - for (iter = 0; iter < BZip2Constants.N_ITERS; iter++) - { - for (t = 0; t < nGroups; t++) - { - fave[t] = 0; - } - - for (t = 0; t < nGroups; t++) - { - for (v = 0; v < alphaSize; v++) - { - rfreq[t][v] = 0; - } - } - - nSelectors = 0; - totc = 0; - gs = 0; - while (true) - { - /* Set group start & end marks. */ - if (gs >= nMTF) - { - break; - } - ge = gs + BZip2Constants.G_SIZE - 1; - if (ge >= nMTF) - { - ge = nMTF - 1; - } - - /* - Calculate the cost of this group as coded - by each of the coding tables. - */ - for (t = 0; t < nGroups; t++) - { - cost[t] = 0; - } - - if (nGroups == 6) - { - short cost0, - cost1, - cost2, - cost3, - cost4, - cost5; - cost0 = cost1 = cost2 = cost3 = cost4 = cost5 = 0; - for (i = gs; i <= ge; i++) - { - short icv = szptr[i]; - cost0 += (short)len[0][icv]; - cost1 += (short)len[1][icv]; - cost2 += (short)len[2][icv]; - cost3 += (short)len[3][icv]; - cost4 += (short)len[4][icv]; - cost5 += (short)len[5][icv]; - } - cost[0] = cost0; - cost[1] = cost1; - cost[2] = cost2; - cost[3] = cost3; - cost[4] = cost4; - cost[5] = cost5; - } - else - { - for (i = gs; i <= ge; i++) - { - short icv = szptr[i]; - for (t = 0; t < nGroups; t++) - { - cost[t] += (short)len[t][icv]; - } - } - } - - /* - Find the coding table which is best for this group, - and record its identity in the selector table. - */ - bc = 999999999; - bt = -1; - for (t = 0; t < nGroups; t++) - { - if (cost[t] < bc) - { - bc = cost[t]; - bt = t; - } - } - ; - totc += bc; - fave[bt]++; - selector[nSelectors] = (char)bt; - nSelectors++; - - /* - Increment the symbol frequencies for the selected table. - */ - for (i = gs; i <= ge; i++) - { - rfreq[bt][szptr[i]]++; - } - - gs = ge + 1; - } - - /* - Recompute the tables based on the accumulated frequencies. - */ - for (t = 0; t < nGroups; t++) - { - HbMakeCodeLengths(len[t], rfreq[t], alphaSize, 20); - } - } - - rfreq = null; - fave = null; - cost = null; - - if (!(nGroups < 8)) - { - Panic(); - } - if (!(nSelectors < 32768 && nSelectors <= (2 + (900000 / BZip2Constants.G_SIZE)))) - { - Panic(); - } - - /* Compute MTF values for the selectors. */ - { - char[] pos = new char[BZip2Constants.N_GROUPS]; - char ll_i, - tmp2, - tmp; - for (i = 0; i < nGroups; i++) - { - pos[i] = (char)i; - } - for (i = 0; i < nSelectors; i++) - { - ll_i = selector[i]; - j = 0; - tmp = pos[j]; - while (ll_i != tmp) - { - j++; - tmp2 = tmp; - tmp = pos[j]; - pos[j] = tmp2; - } - pos[0] = tmp; - selectorMtf[i] = (char)j; - } - } - - int[][] code = CBZip2InputStream.InitIntArray( - BZip2Constants.N_GROUPS, - BZip2Constants.MAX_ALPHA_SIZE - ); - - /* Assign actual codes for the tables. */ - for (t = 0; t < nGroups; t++) - { - minLen = 32; - maxLen = 0; - for (i = 0; i < alphaSize; i++) - { - if (len[t][i] > maxLen) - { - maxLen = len[t][i]; - } - if (len[t][i] < minLen) - { - minLen = len[t][i]; - } - } - if (maxLen > 20) - { - Panic(); - } - if (minLen < 1) - { - Panic(); - } - HbAssignCodes(code[t], len[t], minLen, maxLen, alphaSize); - } - - /* Transmit the mapping table. */ - { - bool[] inUse16 = new bool[16]; - for (i = 0; i < 16; i++) - { - inUse16[i] = false; - for (j = 0; j < 16; j++) - { - if (inUse[i * 16 + j]) - { - inUse16[i] = true; - } - } - } - - //nBytes = bytesOut; - for (i = 0; i < 16; i++) - { - if (inUse16[i]) - { - BsW(1, 1); - } - else - { - BsW(1, 0); - } - } - - for (i = 0; i < 16; i++) - { - if (inUse16[i]) - { - for (j = 0; j < 16; j++) - { - if (inUse[i * 16 + j]) - { - BsW(1, 1); - } - else - { - BsW(1, 0); - } - } - } - } - } - - /* Now the selectors. */ - //nBytes = bytesOut; - BsW(3, nGroups); - BsW(15, nSelectors); - for (i = 0; i < nSelectors; i++) - { - for (j = 0; j < selectorMtf[i]; j++) - { - BsW(1, 1); - } - BsW(1, 0); - } - - /* Now the coding tables. */ - //nBytes = bytesOut; - - for (t = 0; t < nGroups; t++) - { - int curr = len[t][0]; - BsW(5, curr); - for (i = 0; i < alphaSize; i++) - { - while (curr < len[t][i]) - { - BsW(2, 2); - curr++; /* 10 */ - } - while (curr > len[t][i]) - { - BsW(2, 3); - curr--; /* 11 */ - } - BsW(1, 0); - } - } - - /* And finally, the block data proper */ - //nBytes = bytesOut; - selCtr = 0; + nSelectors = 0; + totc = 0; gs = 0; while (true) { + /* Set group start & end marks. */ if (gs >= nMTF) { break; @@ -1058,222 +800,480 @@ namespace SharpCompress.Compressors.BZip2 { ge = nMTF - 1; } + + /* + Calculate the cost of this group as coded + by each of the coding tables. + */ + for (t = 0; t < nGroups; t++) + { + cost[t] = 0; + } + + if (nGroups == 6) + { + short cost0, + cost1, + cost2, + cost3, + cost4, + cost5; + cost0 = cost1 = cost2 = cost3 = cost4 = cost5 = 0; + for (i = gs; i <= ge; i++) + { + var icv = szptr[i]; + cost0 += (short)len[0][icv]; + cost1 += (short)len[1][icv]; + cost2 += (short)len[2][icv]; + cost3 += (short)len[3][icv]; + cost4 += (short)len[4][icv]; + cost5 += (short)len[5][icv]; + } + cost[0] = cost0; + cost[1] = cost1; + cost[2] = cost2; + cost[3] = cost3; + cost[4] = cost4; + cost[5] = cost5; + } + else + { + for (i = gs; i <= ge; i++) + { + var icv = szptr[i]; + for (t = 0; t < nGroups; t++) + { + cost[t] += (short)len[t][icv]; + } + } + } + + /* + Find the coding table which is best for this group, + and record its identity in the selector table. + */ + bc = 999999999; + bt = -1; + for (t = 0; t < nGroups; t++) + { + if (cost[t] < bc) + { + bc = cost[t]; + bt = t; + } + } + ; + totc += bc; + fave[bt]++; + selector[nSelectors] = (char)bt; + nSelectors++; + + /* + Increment the symbol frequencies for the selected table. + */ for (i = gs; i <= ge; i++) { - BsW(len[selector[selCtr]][szptr[i]], code[selector[selCtr]][szptr[i]]); + rfreq[bt][szptr[i]]++; } gs = ge + 1; - selCtr++; } - if (!(selCtr == nSelectors)) + + /* + Recompute the tables based on the accumulated frequencies. + */ + for (t = 0; t < nGroups; t++) + { + HbMakeCodeLengths(len[t], rfreq[t], alphaSize, 20); + } + } + + rfreq = null; + fave = null; + cost = null; + + if (!(nGroups < 8)) + { + Panic(); + } + if (!(nSelectors < 32768 && nSelectors <= (2 + (900000 / BZip2Constants.G_SIZE)))) + { + Panic(); + } + + /* Compute MTF values for the selectors. */ + { + var pos = new char[BZip2Constants.N_GROUPS]; + char ll_i, + tmp2, + tmp; + for (i = 0; i < nGroups; i++) + { + pos[i] = (char)i; + } + for (i = 0; i < nSelectors; i++) + { + ll_i = selector[i]; + j = 0; + tmp = pos[j]; + while (ll_i != tmp) + { + j++; + tmp2 = tmp; + tmp = pos[j]; + pos[j] = tmp2; + } + pos[0] = tmp; + selectorMtf[i] = (char)j; + } + } + + var code = CBZip2InputStream.InitIntArray( + BZip2Constants.N_GROUPS, + BZip2Constants.MAX_ALPHA_SIZE + ); + + /* Assign actual codes for the tables. */ + for (t = 0; t < nGroups; t++) + { + minLen = 32; + maxLen = 0; + for (i = 0; i < alphaSize; i++) + { + if (len[t][i] > maxLen) + { + maxLen = len[t][i]; + } + if (len[t][i] < minLen) + { + minLen = len[t][i]; + } + } + if (maxLen > 20) { Panic(); } + if (minLen < 1) + { + Panic(); + } + HbAssignCodes(code[t], len[t], minLen, maxLen, alphaSize); } - private void MoveToFrontCodeAndSend() + /* Transmit the mapping table. */ { - BsPutIntVS(24, origPtr); - GenerateMTFValues(); - SendMTFValues(); - } - - private Stream bsStream; - - private void SimpleSort(int lo, int hi, int d) - { - int i, - j, - h, - bigN, - hp; - int v; - - bigN = hi - lo + 1; - if (bigN < 2) + var inUse16 = new bool[16]; + for (i = 0; i < 16; i++) { - return; - } - - hp = 0; - while (incs[hp] < bigN) - { - hp++; - } - hp--; - - for (; hp >= 0; hp--) - { - h = incs[hp]; - - i = lo + h; - while (true) + inUse16[i] = false; + for (j = 0; j < 16; j++) { - /* copy 1 */ - if (i > hi) + if (inUse[(i * 16) + j]) { - break; + inUse16[i] = true; } - v = zptr[i]; - j = i; - while (FullGtU(zptr[j - h] + d, v + d)) - { - zptr[j] = zptr[j - h]; - j = j - h; - if (j <= (lo + h - 1)) - { - break; - } - } - zptr[j] = v; - i++; + } + } - /* copy 2 */ - if (i > hi) - { - break; - } - v = zptr[i]; - j = i; - while (FullGtU(zptr[j - h] + d, v + d)) - { - zptr[j] = zptr[j - h]; - j = j - h; - if (j <= (lo + h - 1)) - { - break; - } - } - zptr[j] = v; - i++; + //nBytes = bytesOut; + for (i = 0; i < 16; i++) + { + if (inUse16[i]) + { + BsW(1, 1); + } + else + { + BsW(1, 0); + } + } - /* copy 3 */ - if (i > hi) + for (i = 0; i < 16; i++) + { + if (inUse16[i]) + { + for (j = 0; j < 16; j++) { - break; - } - v = zptr[i]; - j = i; - while (FullGtU(zptr[j - h] + d, v + d)) - { - zptr[j] = zptr[j - h]; - j = j - h; - if (j <= (lo + h - 1)) + if (inUse[(i * 16) + j]) { - break; + BsW(1, 1); + } + else + { + BsW(1, 0); } - } - zptr[j] = v; - i++; - - if (workDone > workLimit && firstAttempt) - { - return; } } } } - private void Vswap(int p1, int p2, int n) + /* Now the selectors. */ + //nBytes = bytesOut; + BsW(3, nGroups); + BsW(15, nSelectors); + for (i = 0; i < nSelectors; i++) { - int temp = 0; - while (n > 0) + for (j = 0; j < selectorMtf[i]; j++) { - temp = zptr[p1]; - zptr[p1] = zptr[p2]; - zptr[p2] = temp; - p1++; - p2++; - n--; + BsW(1, 1); } + BsW(1, 0); } - private char Med3(char a, char b, char c) + /* Now the coding tables. */ + //nBytes = bytesOut; + + for (t = 0; t < nGroups; t++) { - char t; - if (a > b) + int curr = len[t][0]; + BsW(5, curr); + for (i = 0; i < alphaSize; i++) { - t = a; - a = b; - b = t; - } - if (b > c) - { - t = b; - b = c; - c = t; - } - if (a > b) - { - b = a; - } - return b; - } - - internal class StackElem - { - internal int ll; - internal int hh; - internal int dd; - } - - private void QSort3(int loSt, int hiSt, int dSt) - { - int unLo, - unHi, - ltLo, - gtHi, - med, - n, - m; - int sp, - lo, - hi, - d; - StackElem[] stack = new StackElem[QSORT_STACK_SIZE]; - for (int count = 0; count < QSORT_STACK_SIZE; count++) - { - stack[count] = new StackElem(); - } - - sp = 0; - - stack[sp].ll = loSt; - stack[sp].hh = hiSt; - stack[sp].dd = dSt; - sp++; - - while (sp > 0) - { - if (sp >= QSORT_STACK_SIZE) + while (curr < len[t][i]) { - Panic(); + BsW(2, 2); + curr++; /* 10 */ } - - sp--; - lo = stack[sp].ll; - hi = stack[sp].hh; - d = stack[sp].dd; - - if (hi - lo < SMALL_THRESH || d > DEPTH_THRESH) + while (curr > len[t][i]) { - SimpleSort(lo, hi, d); - if (workDone > workLimit && firstAttempt) + BsW(2, 3); + curr--; /* 11 */ + } + BsW(1, 0); + } + } + + /* And finally, the block data proper */ + //nBytes = bytesOut; + selCtr = 0; + gs = 0; + while (true) + { + if (gs >= nMTF) + { + break; + } + ge = gs + BZip2Constants.G_SIZE - 1; + if (ge >= nMTF) + { + ge = nMTF - 1; + } + for (i = gs; i <= ge; i++) + { + BsW(len[selector[selCtr]][szptr[i]], code[selector[selCtr]][szptr[i]]); + } + + gs = ge + 1; + selCtr++; + } + if (!(selCtr == nSelectors)) + { + Panic(); + } + } + + private void MoveToFrontCodeAndSend() + { + BsPutIntVS(24, origPtr); + GenerateMTFValues(); + SendMTFValues(); + } + + private Stream bsStream; + + private void SimpleSort(int lo, int hi, int d) + { + int i, + j, + h, + bigN, + hp; + int v; + + bigN = hi - lo + 1; + if (bigN < 2) + { + return; + } + + hp = 0; + while (incs[hp] < bigN) + { + hp++; + } + hp--; + + for (; hp >= 0; hp--) + { + h = incs[hp]; + + i = lo + h; + while (true) + { + /* copy 1 */ + if (i > hi) + { + break; + } + v = zptr[i]; + j = i; + while (FullGtU(zptr[j - h] + d, v + d)) + { + zptr[j] = zptr[j - h]; + j -= h; + if (j <= (lo + h - 1)) { - return; + break; } - continue; } + zptr[j] = v; + i++; - med = Med3( - block[zptr[lo] + d + 1], - block[zptr[hi] + d + 1], - block[zptr[(lo + hi) >> 1] + d + 1] - ); + /* copy 2 */ + if (i > hi) + { + break; + } + v = zptr[i]; + j = i; + while (FullGtU(zptr[j - h] + d, v + d)) + { + zptr[j] = zptr[j - h]; + j -= h; + if (j <= (lo + h - 1)) + { + break; + } + } + zptr[j] = v; + i++; - unLo = ltLo = lo; - unHi = gtHi = hi; + /* copy 3 */ + if (i > hi) + { + break; + } + v = zptr[i]; + j = i; + while (FullGtU(zptr[j - h] + d, v + d)) + { + zptr[j] = zptr[j - h]; + j -= h; + if (j <= (lo + h - 1)) + { + break; + } + } + zptr[j] = v; + i++; + + if (workDone > workLimit && firstAttempt) + { + return; + } + } + } + } + + private void Vswap(int p1, int p2, int n) + { + var temp = 0; + while (n > 0) + { + temp = zptr[p1]; + zptr[p1] = zptr[p2]; + zptr[p2] = temp; + p1++; + p2++; + n--; + } + } + + private char Med3(char a, char b, char c) + { + char t; + if (a > b) + { + t = a; + a = b; + b = t; + } + if (b > c) + { + t = b; + b = c; + c = t; + } + if (a > b) + { + b = a; + } + return b; + } + + internal class StackElem + { + internal int ll; + internal int hh; + internal int dd; + } + + private void QSort3(int loSt, int hiSt, int dSt) + { + int unLo, + unHi, + ltLo, + gtHi, + med, + n, + m; + int sp, + lo, + hi, + d; + var stack = new StackElem[QSORT_STACK_SIZE]; + for (var count = 0; count < QSORT_STACK_SIZE; count++) + { + stack[count] = new StackElem(); + } + + sp = 0; + + stack[sp].ll = loSt; + stack[sp].hh = hiSt; + stack[sp].dd = dSt; + sp++; + + while (sp > 0) + { + if (sp >= QSORT_STACK_SIZE) + { + Panic(); + } + + sp--; + lo = stack[sp].ll; + hi = stack[sp].hh; + d = stack[sp].dd; + + if (hi - lo < SMALL_THRESH || d > DEPTH_THRESH) + { + SimpleSort(lo, hi, d); + if (workDone > workLimit && firstAttempt) + { + return; + } + continue; + } + + med = Med3( + block[zptr[lo] + d + 1], + block[zptr[hi] + d + 1], + block[zptr[(lo + hi) >> 1] + d + 1] + ); + + unLo = ltLo = lo; + unHi = gtHi = hi; while (true) { @@ -1284,33 +1284,33 @@ namespace SharpCompress.Compressors.BZip2 break; } n = block[zptr[unLo] + d + 1] - med; - if (n == 0) - { - int temp = 0; - temp = zptr[unLo]; - zptr[unLo] = zptr[ltLo]; - zptr[ltLo] = temp; - ltLo++; - unLo++; - continue; - } - ; - if (n > 0) - { - break; - } - unLo++; - } - while (true) + if (n == 0) { - if (unLo > unHi) - { - break; - } - n = block[zptr[unHi] + d + 1] - med; - if (n == 0) - { - int temp = 0; + var temp = 0; + temp = zptr[unLo]; + zptr[unLo] = zptr[ltLo]; + zptr[ltLo] = temp; + ltLo++; + unLo++; + continue; + } + ; + if (n > 0) + { + break; + } + unLo++; + } + while (true) + { + if (unLo > unHi) + { + break; + } + n = block[zptr[unHi] + d + 1] - med; + if (n == 0) + { + var temp = 0; temp = zptr[unHi]; zptr[unHi] = zptr[gtHi]; zptr[gtHi] = temp; @@ -1329,700 +1329,699 @@ namespace SharpCompress.Compressors.BZip2 { break; } - int tempx = zptr[unLo]; + var tempx = zptr[unLo]; zptr[unLo] = zptr[unHi]; zptr[unHi] = tempx; unLo++; unHi--; } - if (gtHi < ltLo) - { - stack[sp].ll = lo; - stack[sp].hh = hi; - stack[sp].dd = d + 1; - sp++; - continue; - } - - n = ((ltLo - lo) < (unLo - ltLo)) ? (ltLo - lo) : (unLo - ltLo); - Vswap(lo, unLo - n, n); - m = ((hi - gtHi) < (gtHi - unHi)) ? (hi - gtHi) : (gtHi - unHi); - Vswap(unLo, hi - m + 1, m); - - n = lo + unLo - ltLo - 1; - m = hi - (gtHi - unHi) + 1; - + if (gtHi < ltLo) + { stack[sp].ll = lo; - stack[sp].hh = n; - stack[sp].dd = d; - sp++; - - stack[sp].ll = n + 1; - stack[sp].hh = m - 1; + stack[sp].hh = hi; stack[sp].dd = d + 1; sp++; - - stack[sp].ll = m; - stack[sp].hh = hi; - stack[sp].dd = d; - sp++; + continue; } + + n = ((ltLo - lo) < (unLo - ltLo)) ? (ltLo - lo) : (unLo - ltLo); + Vswap(lo, unLo - n, n); + m = ((hi - gtHi) < (gtHi - unHi)) ? (hi - gtHi) : (gtHi - unHi); + Vswap(unLo, hi - m + 1, m); + + n = lo + unLo - ltLo - 1; + m = hi - (gtHi - unHi) + 1; + + stack[sp].ll = lo; + stack[sp].hh = n; + stack[sp].dd = d; + sp++; + + stack[sp].ll = n + 1; + stack[sp].hh = m - 1; + stack[sp].dd = d + 1; + sp++; + + stack[sp].ll = m; + stack[sp].hh = hi; + stack[sp].dd = d; + sp++; } + } - private void MainSort() - { - int i, - j, - ss, - sb; - Span runningOrder = stackalloc int[256]; - Span copy = stackalloc int[256]; - bool[] bigDone = new bool[256]; - int c1, - c2; - int numQSorted; - - /* - In the various block-sized structures, live data runs - from 0 to last+NUM_OVERSHOOT_BYTES inclusive. First, - set up the overshoot area for block. - */ - - // if (verbosity >= 4) fprintf ( stderr, " sort initialise ...\n" ); - for (i = 0; i < BZip2Constants.NUM_OVERSHOOT_BYTES; i++) - { - block[last + i + 2] = block[(i % (last + 1)) + 1]; - } - for (i = 0; i <= last + BZip2Constants.NUM_OVERSHOOT_BYTES; i++) - { - quadrant[i] = 0; - } - - block[0] = block[last + 1]; - - if (last < 4000) - { - /* - Use SimpleSort(), since the full sorting mechanism - has quite a large constant overhead. - */ - for (i = 0; i <= last; i++) - { - zptr[i] = i; - } - firstAttempt = false; - workDone = workLimit = 0; - SimpleSort(0, last, 0); - } - else - { - numQSorted = 0; - for (i = 0; i <= 255; i++) - { - bigDone[i] = false; - } - - for (i = 0; i <= 65536; i++) - { - ftab[i] = 0; - } - - c1 = block[0]; - for (i = 0; i <= last; i++) - { - c2 = block[i + 1]; - ftab[(c1 << 8) + c2]++; - c1 = c2; - } - - for (i = 1; i <= 65536; i++) - { - ftab[i] += ftab[i - 1]; - } - - c1 = block[1]; - for (i = 0; i < last; i++) - { - c2 = block[i + 2]; - j = (c1 << 8) + c2; - c1 = c2; - ftab[j]--; - zptr[ftab[j]] = i; - } - - j = ((block[last + 1]) << 8) + (block[1]); - ftab[j]--; - zptr[ftab[j]] = last; - - /* - Now ftab contains the first loc of every small bucket. - Calculate the running order, from smallest to largest - big bucket. - */ - - for (i = 0; i <= 255; i++) - { - runningOrder[i] = i; - } - - { - int vv; - int h = 1; - do - { - h = 3 * h + 1; - } while (h <= 256); - do - { - h = h / 3; - for (i = h; i <= 255; i++) - { - vv = runningOrder[i]; - j = i; - while ( - ( - ftab[((runningOrder[j - h]) + 1) << 8] - - ftab[(runningOrder[j - h]) << 8] - ) > (ftab[((vv) + 1) << 8] - ftab[(vv) << 8]) - ) - { - runningOrder[j] = runningOrder[j - h]; - j = j - h; - if (j <= (h - 1)) - { - break; - } - } - runningOrder[j] = vv; - } - } while (h != 1); - } - - /* - The main sorting loop. - */ - for (i = 0; i <= 255; i++) - { - /* - Process big buckets, starting with the least full. - */ - ss = runningOrder[i]; - - /* - Complete the big bucket [ss] by quicksorting - any unsorted small buckets [ss, j]. Hopefully - previous pointer-scanning phases have already - completed many of the small buckets [ss, j], so - we don't have to sort them at all. - */ - for (j = 0; j <= 255; j++) - { - sb = (ss << 8) + j; - if (!((ftab[sb] & SETMASK) == SETMASK)) - { - int lo = ftab[sb] & CLEARMASK; - int hi = (ftab[sb + 1] & CLEARMASK) - 1; - if (hi > lo) - { - QSort3(lo, hi, 2); - numQSorted += (hi - lo + 1); - if (workDone > workLimit && firstAttempt) - { - return; - } - } - ftab[sb] |= SETMASK; - } - } - - /* - The ss big bucket is now done. Record this fact, - and update the quadrant descriptors. Remember to - update quadrants in the overshoot area too, if - necessary. The "if (i < 255)" test merely skips - this updating for the last bucket processed, since - updating for the last bucket is pointless. - */ - bigDone[ss] = true; - - if (i < 255) - { - int bbStart = ftab[ss << 8] & CLEARMASK; - int bbSize = (ftab[(ss + 1) << 8] & CLEARMASK) - bbStart; - int shifts = 0; - - while ((bbSize >> shifts) > 65534) - { - shifts++; - } - - for (j = 0; j < bbSize; j++) - { - int a2update = zptr[bbStart + j]; - int qVal = (j >> shifts); - quadrant[a2update] = qVal; - if (a2update < BZip2Constants.NUM_OVERSHOOT_BYTES) - { - quadrant[a2update + last + 1] = qVal; - } - } - - if (!(((bbSize - 1) >> shifts) <= 65535)) - { - Panic(); - } - } - - /* - Now scan this big bucket so as to synthesise the - sorted order for small buckets [t, ss] for all t != ss. - */ - for (j = 0; j <= 255; j++) - { - copy[j] = ftab[(j << 8) + ss] & CLEARMASK; - } - - for (j = ftab[ss << 8] & CLEARMASK; j < (ftab[(ss + 1) << 8] & CLEARMASK); j++) - { - c1 = block[zptr[j]]; - if (!bigDone[c1]) - { - zptr[copy[c1]] = zptr[j] == 0 ? last : zptr[j] - 1; - copy[c1]++; - } - } - - for (j = 0; j <= 255; j++) - { - ftab[(j << 8) + ss] |= SETMASK; - } - } - } - } - - private void RandomiseBlock() - { - int i; - int rNToGo = 0; - int rTPos = 0; - for (i = 0; i < 256; i++) - { - inUse[i] = false; - } - - for (i = 0; i <= last; i++) - { - if (rNToGo == 0) - { - rNToGo = (char)BZip2Constants.rNums[rTPos]; - rTPos++; - if (rTPos == 512) - { - rTPos = 0; - } - } - rNToGo--; - block[i + 1] ^= (char)((rNToGo == 1) ? 1 : 0); - - // handle 16 bit signed numbers - block[i + 1] &= (char)0xFF; - - inUse[block[i + 1]] = true; - } - } - - private void DoReversibleTransformation() - { - int i; - - workLimit = workFactor * last; - workDone = 0; - blockRandomised = false; - firstAttempt = true; - - MainSort(); - - if (workDone > workLimit && firstAttempt) - { - RandomiseBlock(); - workLimit = workDone = 0; - blockRandomised = true; - firstAttempt = false; - MainSort(); - } - - origPtr = -1; - for (i = 0; i <= last; i++) - { - if (zptr[i] == 0) - { - origPtr = i; - break; - } - } - ; - - if (origPtr == -1) - { - Panic(); - } - } - - private bool FullGtU(int i1, int i2) - { - int k; - char c1, - c2; - int s1, - s2; - - c1 = block[i1 + 1]; - c2 = block[i2 + 1]; - if (c1 != c2) - { - return (c1 > c2); - } - i1++; - i2++; - - c1 = block[i1 + 1]; - c2 = block[i2 + 1]; - if (c1 != c2) - { - return (c1 > c2); - } - i1++; - i2++; - - c1 = block[i1 + 1]; - c2 = block[i2 + 1]; - if (c1 != c2) - { - return (c1 > c2); - } - i1++; - i2++; - - c1 = block[i1 + 1]; - c2 = block[i2 + 1]; - if (c1 != c2) - { - return (c1 > c2); - } - i1++; - i2++; - - c1 = block[i1 + 1]; - c2 = block[i2 + 1]; - if (c1 != c2) - { - return (c1 > c2); - } - i1++; - i2++; - - c1 = block[i1 + 1]; - c2 = block[i2 + 1]; - if (c1 != c2) - { - return (c1 > c2); - } - i1++; - i2++; - - k = last + 1; - - do - { - c1 = block[i1 + 1]; - c2 = block[i2 + 1]; - if (c1 != c2) - { - return (c1 > c2); - } - s1 = quadrant[i1]; - s2 = quadrant[i2]; - if (s1 != s2) - { - return (s1 > s2); - } - i1++; - i2++; - - c1 = block[i1 + 1]; - c2 = block[i2 + 1]; - if (c1 != c2) - { - return (c1 > c2); - } - s1 = quadrant[i1]; - s2 = quadrant[i2]; - if (s1 != s2) - { - return (s1 > s2); - } - i1++; - i2++; - - c1 = block[i1 + 1]; - c2 = block[i2 + 1]; - if (c1 != c2) - { - return (c1 > c2); - } - s1 = quadrant[i1]; - s2 = quadrant[i2]; - if (s1 != s2) - { - return (s1 > s2); - } - i1++; - i2++; - - c1 = block[i1 + 1]; - c2 = block[i2 + 1]; - if (c1 != c2) - { - return (c1 > c2); - } - s1 = quadrant[i1]; - s2 = quadrant[i2]; - if (s1 != s2) - { - return (s1 > s2); - } - i1++; - i2++; - - if (i1 > last) - { - i1 -= last; - i1--; - } - ; - if (i2 > last) - { - i2 -= last; - i2--; - } - ; - - k -= 4; - workDone++; - } while (k >= 0); - - return false; - } + private void MainSort() + { + int i, + j, + ss, + sb; + Span runningOrder = stackalloc int[256]; + Span copy = stackalloc int[256]; + var bigDone = new bool[256]; + int c1, + c2; + int numQSorted; /* - Knuth's increments seem to work better - than Incerpi-Sedgewick here. Possibly - because the number of elems to sort is - usually small, typically <= 20. + In the various block-sized structures, live data runs + from 0 to last+NUM_OVERSHOOT_BYTES inclusive. First, + set up the overshoot area for block. */ - private readonly int[] incs = + // if (verbosity >= 4) fprintf ( stderr, " sort initialise ...\n" ); + for (i = 0; i < BZip2Constants.NUM_OVERSHOOT_BYTES; i++) { - 1, - 4, - 13, - 40, - 121, - 364, - 1093, - 3280, - 9841, - 29524, - 88573, - 265720, - 797161, - 2391484 - }; - - private void AllocateCompressStructures() + block[last + i + 2] = block[(i % (last + 1)) + 1]; + } + for (i = 0; i <= last + BZip2Constants.NUM_OVERSHOOT_BYTES; i++) { - int n = BZip2Constants.baseBlockSize * blockSize100k; - block = new char[(n + 1 + BZip2Constants.NUM_OVERSHOOT_BYTES)]; - quadrant = new int[(n + BZip2Constants.NUM_OVERSHOOT_BYTES)]; - zptr = new int[n]; - ftab = new int[65537]; - - if (block is null || quadrant is null || zptr is null || ftab is null) - { - //int totalDraw = (n + 1 + NUM_OVERSHOOT_BYTES) + (n + NUM_OVERSHOOT_BYTES) + n + 65537; - //compressOutOfMemory ( totalDraw, n ); - } - - /* - The back end needs a place to store the MTF values - whilst it calculates the coding tables. We could - put them in the zptr array. However, these values - will fit in a short, so we overlay szptr at the - start of zptr, in the hope of reducing the number - of cache misses induced by the multiple traversals - of the MTF values when calculating coding tables. - Seems to improve compression speed by about 1%. - */ - // szptr = zptr; - - szptr = new short[2 * n]; + quadrant[i] = 0; } - private void GenerateMTFValues() + block[0] = block[last + 1]; + + if (last < 4000) { - char[] yy = new char[256]; - int i, - j; - char tmp; - char tmp2; - int zPend; - int wr; - int EOB; - - MakeMaps(); - EOB = nInUse + 1; - - for (i = 0; i <= EOB; i++) - { - mtfFreq[i] = 0; - } - - wr = 0; - zPend = 0; - for (i = 0; i < nInUse; i++) - { - yy[i] = (char)i; - } - + /* + Use SimpleSort(), since the full sorting mechanism + has quite a large constant overhead. + */ for (i = 0; i <= last; i++) { - char ll_i; + zptr[i] = i; + } + firstAttempt = false; + workDone = workLimit = 0; + SimpleSort(0, last, 0); + } + else + { + numQSorted = 0; + for (i = 0; i <= 255; i++) + { + bigDone[i] = false; + } - ll_i = unseqToSeq[block[zptr[i]]]; + for (i = 0; i <= 65536; i++) + { + ftab[i] = 0; + } - j = 0; - tmp = yy[j]; - while (ll_i != tmp) - { - j++; - tmp2 = tmp; - tmp = yy[j]; - yy[j] = tmp2; - } - ; - yy[0] = tmp; + c1 = block[0]; + for (i = 0; i <= last; i++) + { + c2 = block[i + 1]; + ftab[(c1 << 8) + c2]++; + c1 = c2; + } - if (j == 0) + for (i = 1; i <= 65536; i++) + { + ftab[i] += ftab[i - 1]; + } + + c1 = block[1]; + for (i = 0; i < last; i++) + { + c2 = block[i + 2]; + j = (c1 << 8) + c2; + c1 = c2; + ftab[j]--; + zptr[ftab[j]] = i; + } + + j = ((block[last + 1]) << 8) + (block[1]); + ftab[j]--; + zptr[ftab[j]] = last; + + /* + Now ftab contains the first loc of every small bucket. + Calculate the running order, from smallest to largest + big bucket. + */ + + for (i = 0; i <= 255; i++) + { + runningOrder[i] = i; + } + + { + int vv; + var h = 1; + do { - zPend++; - } - else + h = (3 * h) + 1; + } while (h <= 256); + do { - if (zPend > 0) + h /= 3; + for (i = h; i <= 255; i++) { - zPend--; - while (true) + vv = runningOrder[i]; + j = i; + while ( + ( + ftab[((runningOrder[j - h]) + 1) << 8] + - ftab[(runningOrder[j - h]) << 8] + ) > (ftab[((vv) + 1) << 8] - ftab[(vv) << 8]) + ) { - switch (zPend % 2) - { - case 0: - szptr[wr] = BZip2Constants.RUNA; - wr++; - mtfFreq[BZip2Constants.RUNA]++; - break; - case 1: - szptr[wr] = BZip2Constants.RUNB; - wr++; - mtfFreq[BZip2Constants.RUNB]++; - break; - } - ; - if (zPend < 2) + runningOrder[j] = runningOrder[j - h]; + j -= h; + if (j <= (h - 1)) { break; } - zPend = (zPend - 2) / 2; } - ; - zPend = 0; + runningOrder[j] = vv; } - szptr[wr] = (short)(j + 1); - wr++; - mtfFreq[j + 1]++; - } + } while (h != 1); } - if (zPend > 0) + /* + The main sorting loop. + */ + for (i = 0; i <= 255; i++) { - zPend--; - while (true) + /* + Process big buckets, starting with the least full. + */ + ss = runningOrder[i]; + + /* + Complete the big bucket [ss] by quicksorting + any unsorted small buckets [ss, j]. Hopefully + previous pointer-scanning phases have already + completed many of the small buckets [ss, j], so + we don't have to sort them at all. + */ + for (j = 0; j <= 255; j++) { - switch (zPend % 2) + sb = (ss << 8) + j; + if (!((ftab[sb] & SETMASK) == SETMASK)) { - case 0: - szptr[wr] = BZip2Constants.RUNA; - wr++; - mtfFreq[BZip2Constants.RUNA]++; - break; - case 1: - szptr[wr] = BZip2Constants.RUNB; - wr++; - mtfFreq[BZip2Constants.RUNB]++; - break; + var lo = ftab[sb] & CLEARMASK; + var hi = (ftab[sb + 1] & CLEARMASK) - 1; + if (hi > lo) + { + QSort3(lo, hi, 2); + numQSorted += (hi - lo + 1); + if (workDone > workLimit && firstAttempt) + { + return; + } + } + ftab[sb] |= SETMASK; } - if (zPend < 2) + } + + /* + The ss big bucket is now done. Record this fact, + and update the quadrant descriptors. Remember to + update quadrants in the overshoot area too, if + necessary. The "if (i < 255)" test merely skips + this updating for the last bucket processed, since + updating for the last bucket is pointless. + */ + bigDone[ss] = true; + + if (i < 255) + { + var bbStart = ftab[ss << 8] & CLEARMASK; + var bbSize = (ftab[(ss + 1) << 8] & CLEARMASK) - bbStart; + var shifts = 0; + + while ((bbSize >> shifts) > 65534) { - break; + shifts++; } - zPend = (zPend - 2) / 2; + + for (j = 0; j < bbSize; j++) + { + var a2update = zptr[bbStart + j]; + var qVal = (j >> shifts); + quadrant[a2update] = qVal; + if (a2update < BZip2Constants.NUM_OVERSHOOT_BYTES) + { + quadrant[a2update + last + 1] = qVal; + } + } + + if (!(((bbSize - 1) >> shifts) <= 65535)) + { + Panic(); + } + } + + /* + Now scan this big bucket so as to synthesise the + sorted order for small buckets [t, ss] for all t != ss. + */ + for (j = 0; j <= 255; j++) + { + copy[j] = ftab[(j << 8) + ss] & CLEARMASK; + } + + for (j = ftab[ss << 8] & CLEARMASK; j < (ftab[(ss + 1) << 8] & CLEARMASK); j++) + { + c1 = block[zptr[j]]; + if (!bigDone[c1]) + { + zptr[copy[c1]] = zptr[j] == 0 ? last : zptr[j] - 1; + copy[c1]++; + } + } + + for (j = 0; j <= 255; j++) + { + ftab[(j << 8) + ss] |= SETMASK; } } - - szptr[wr] = (short)EOB; - wr++; - mtfFreq[EOB]++; - - nMTF = wr; - } - - public override int Read(byte[] buffer, int offset, int count) - { - return 0; - } - - public override int ReadByte() - { - return -1; - } - - public override long Seek(long offset, SeekOrigin origin) - { - return 0; - } - - public override void SetLength(long value) { } - - public override void Write(byte[] buffer, int offset, int count) - { - for (int k = 0; k < count; ++k) - { - WriteByte(buffer[k + offset]); - } - } - - public override bool CanRead => false; - - public override bool CanSeek => false; - - public override bool CanWrite => true; - - public override long Length => 0; - - public override long Position - { - get { return 0; } - set { } } } + + private void RandomiseBlock() + { + int i; + var rNToGo = 0; + var rTPos = 0; + for (i = 0; i < 256; i++) + { + inUse[i] = false; + } + + for (i = 0; i <= last; i++) + { + if (rNToGo == 0) + { + rNToGo = (char)BZip2Constants.rNums[rTPos]; + rTPos++; + if (rTPos == 512) + { + rTPos = 0; + } + } + rNToGo--; + block[i + 1] ^= (char)((rNToGo == 1) ? 1 : 0); + + // handle 16 bit signed numbers + block[i + 1] &= (char)0xFF; + + inUse[block[i + 1]] = true; + } + } + + private void DoReversibleTransformation() + { + int i; + + workLimit = workFactor * last; + workDone = 0; + blockRandomised = false; + firstAttempt = true; + + MainSort(); + + if (workDone > workLimit && firstAttempt) + { + RandomiseBlock(); + workLimit = workDone = 0; + blockRandomised = true; + firstAttempt = false; + MainSort(); + } + + origPtr = -1; + for (i = 0; i <= last; i++) + { + if (zptr[i] == 0) + { + origPtr = i; + break; + } + } + ; + + if (origPtr == -1) + { + Panic(); + } + } + + private bool FullGtU(int i1, int i2) + { + int k; + char c1, + c2; + int s1, + s2; + + c1 = block[i1 + 1]; + c2 = block[i2 + 1]; + if (c1 != c2) + { + return (c1 > c2); + } + i1++; + i2++; + + c1 = block[i1 + 1]; + c2 = block[i2 + 1]; + if (c1 != c2) + { + return (c1 > c2); + } + i1++; + i2++; + + c1 = block[i1 + 1]; + c2 = block[i2 + 1]; + if (c1 != c2) + { + return (c1 > c2); + } + i1++; + i2++; + + c1 = block[i1 + 1]; + c2 = block[i2 + 1]; + if (c1 != c2) + { + return (c1 > c2); + } + i1++; + i2++; + + c1 = block[i1 + 1]; + c2 = block[i2 + 1]; + if (c1 != c2) + { + return (c1 > c2); + } + i1++; + i2++; + + c1 = block[i1 + 1]; + c2 = block[i2 + 1]; + if (c1 != c2) + { + return (c1 > c2); + } + i1++; + i2++; + + k = last + 1; + + do + { + c1 = block[i1 + 1]; + c2 = block[i2 + 1]; + if (c1 != c2) + { + return (c1 > c2); + } + s1 = quadrant[i1]; + s2 = quadrant[i2]; + if (s1 != s2) + { + return (s1 > s2); + } + i1++; + i2++; + + c1 = block[i1 + 1]; + c2 = block[i2 + 1]; + if (c1 != c2) + { + return (c1 > c2); + } + s1 = quadrant[i1]; + s2 = quadrant[i2]; + if (s1 != s2) + { + return (s1 > s2); + } + i1++; + i2++; + + c1 = block[i1 + 1]; + c2 = block[i2 + 1]; + if (c1 != c2) + { + return (c1 > c2); + } + s1 = quadrant[i1]; + s2 = quadrant[i2]; + if (s1 != s2) + { + return (s1 > s2); + } + i1++; + i2++; + + c1 = block[i1 + 1]; + c2 = block[i2 + 1]; + if (c1 != c2) + { + return (c1 > c2); + } + s1 = quadrant[i1]; + s2 = quadrant[i2]; + if (s1 != s2) + { + return (s1 > s2); + } + i1++; + i2++; + + if (i1 > last) + { + i1 -= last; + i1--; + } + ; + if (i2 > last) + { + i2 -= last; + i2--; + } + ; + + k -= 4; + workDone++; + } while (k >= 0); + + return false; + } + + /* + Knuth's increments seem to work better + than Incerpi-Sedgewick here. Possibly + because the number of elems to sort is + usually small, typically <= 20. + */ + + private readonly int[] incs = + { + 1, + 4, + 13, + 40, + 121, + 364, + 1093, + 3280, + 9841, + 29524, + 88573, + 265720, + 797161, + 2391484 + }; + + private void AllocateCompressStructures() + { + var n = BZip2Constants.baseBlockSize * blockSize100k; + block = new char[(n + 1 + BZip2Constants.NUM_OVERSHOOT_BYTES)]; + quadrant = new int[(n + BZip2Constants.NUM_OVERSHOOT_BYTES)]; + zptr = new int[n]; + ftab = new int[65537]; + + if (block is null || quadrant is null || zptr is null || ftab is null) + { + //int totalDraw = (n + 1 + NUM_OVERSHOOT_BYTES) + (n + NUM_OVERSHOOT_BYTES) + n + 65537; + //compressOutOfMemory ( totalDraw, n ); + } + + /* + The back end needs a place to store the MTF values + whilst it calculates the coding tables. We could + put them in the zptr array. However, these values + will fit in a short, so we overlay szptr at the + start of zptr, in the hope of reducing the number + of cache misses induced by the multiple traversals + of the MTF values when calculating coding tables. + Seems to improve compression speed by about 1%. + */ + // szptr = zptr; + + szptr = new short[2 * n]; + } + + private void GenerateMTFValues() + { + var yy = new char[256]; + int i, + j; + char tmp; + char tmp2; + int zPend; + int wr; + int EOB; + + MakeMaps(); + EOB = nInUse + 1; + + for (i = 0; i <= EOB; i++) + { + mtfFreq[i] = 0; + } + + wr = 0; + zPend = 0; + for (i = 0; i < nInUse; i++) + { + yy[i] = (char)i; + } + + for (i = 0; i <= last; i++) + { + char ll_i; + + ll_i = unseqToSeq[block[zptr[i]]]; + + j = 0; + tmp = yy[j]; + while (ll_i != tmp) + { + j++; + tmp2 = tmp; + tmp = yy[j]; + yy[j] = tmp2; + } + ; + yy[0] = tmp; + + if (j == 0) + { + zPend++; + } + else + { + if (zPend > 0) + { + zPend--; + while (true) + { + switch (zPend % 2) + { + case 0: + szptr[wr] = BZip2Constants.RUNA; + wr++; + mtfFreq[BZip2Constants.RUNA]++; + break; + case 1: + szptr[wr] = BZip2Constants.RUNB; + wr++; + mtfFreq[BZip2Constants.RUNB]++; + break; + } + ; + if (zPend < 2) + { + break; + } + zPend = (zPend - 2) / 2; + } + ; + zPend = 0; + } + szptr[wr] = (short)(j + 1); + wr++; + mtfFreq[j + 1]++; + } + } + + if (zPend > 0) + { + zPend--; + while (true) + { + switch (zPend % 2) + { + case 0: + szptr[wr] = BZip2Constants.RUNA; + wr++; + mtfFreq[BZip2Constants.RUNA]++; + break; + case 1: + szptr[wr] = BZip2Constants.RUNB; + wr++; + mtfFreq[BZip2Constants.RUNB]++; + break; + } + if (zPend < 2) + { + break; + } + zPend = (zPend - 2) / 2; + } + } + + szptr[wr] = (short)EOB; + wr++; + mtfFreq[EOB]++; + + nMTF = wr; + } + + public override int Read(byte[] buffer, int offset, int count) + { + return 0; + } + + public override int ReadByte() + { + return -1; + } + + public override long Seek(long offset, SeekOrigin origin) + { + return 0; + } + + public override void SetLength(long value) { } + + public override void Write(byte[] buffer, int offset, int count) + { + for (var k = 0; k < count; ++k) + { + WriteByte(buffer[k + offset]); + } + } + + public override bool CanRead => false; + + public override bool CanSeek => false; + + public override bool CanWrite => true; + + public override long Length => 0; + + public override long Position + { + get { return 0; } + set { } + } } diff --git a/src/SharpCompress/Compressors/BZip2/CRC.cs b/src/SharpCompress/Compressors/BZip2/CRC.cs index d9b268cb..7c208aff 100644 --- a/src/SharpCompress/Compressors/BZip2/CRC.cs +++ b/src/SharpCompress/Compressors/BZip2/CRC.cs @@ -1,4 +1,4 @@ -/* +/* * Copyright 2001,2004-2005 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,312 +20,311 @@ * great code. */ -namespace SharpCompress.Compressors.BZip2 +namespace SharpCompress.Compressors.BZip2; + +/** + * A simple class the hold and calculate the CRC for sanity checking + * of the data. + * + * @author Keiron Liddle + */ + +internal class CRC { - /** - * A simple class the hold and calculate the CRC for sanity checking - * of the data. - * - * @author Keiron Liddle - */ - - internal class CRC + public static int[] crc32Table = { - public static int[] crc32Table = - { - 0x00000000, - 0x04c11db7, - 0x09823b6e, - 0x0d4326d9, - 0x130476dc, - 0x17c56b6b, - 0x1a864db2, - 0x1e475005, - 0x2608edb8, - 0x22c9f00f, - 0x2f8ad6d6, - 0x2b4bcb61, - 0x350c9b64, - 0x31cd86d3, - 0x3c8ea00a, - 0x384fbdbd, - 0x4c11db70, - 0x48d0c6c7, - 0x4593e01e, - 0x4152fda9, - 0x5f15adac, - 0x5bd4b01b, - 0x569796c2, - 0x52568b75, - 0x6a1936c8, - 0x6ed82b7f, - 0x639b0da6, - 0x675a1011, - 0x791d4014, - 0x7ddc5da3, - 0x709f7b7a, - 0x745e66cd, - unchecked((int)0x9823b6e0), - unchecked((int)0x9ce2ab57), - unchecked((int)0x91a18d8e), - unchecked((int)0x95609039), - unchecked((int)0x8b27c03c), - unchecked((int)0x8fe6dd8b), - unchecked((int)0x82a5fb52), - unchecked((int)0x8664e6e5), - unchecked((int)0xbe2b5b58), - unchecked((int)0xbaea46ef), - unchecked((int)0xb7a96036), - unchecked((int)0xb3687d81), - unchecked((int)0xad2f2d84), - unchecked((int)0xa9ee3033), - unchecked((int)0xa4ad16ea), - unchecked((int)0xa06c0b5d), - unchecked((int)0xd4326d90), - unchecked((int)0xd0f37027), - unchecked((int)0xddb056fe), - unchecked((int)0xd9714b49), - unchecked((int)0xc7361b4c), - unchecked((int)0xc3f706fb), - unchecked((int)0xceb42022), - unchecked((int)0xca753d95), - unchecked((int)0xf23a8028), - unchecked((int)0xf6fb9d9f), - unchecked((int)0xfbb8bb46), - unchecked((int)0xff79a6f1), - unchecked((int)0xe13ef6f4), - unchecked((int)0xe5ffeb43), - unchecked((int)0xe8bccd9a), - unchecked((int)0xec7dd02d), - 0x34867077, - 0x30476dc0, - 0x3d044b19, - 0x39c556ae, - 0x278206ab, - 0x23431b1c, - 0x2e003dc5, - 0x2ac12072, - 0x128e9dcf, - 0x164f8078, - 0x1b0ca6a1, - 0x1fcdbb16, - 0x018aeb13, - 0x054bf6a4, - 0x0808d07d, - 0x0cc9cdca, - 0x7897ab07, - 0x7c56b6b0, - 0x71159069, - 0x75d48dde, - 0x6b93dddb, - 0x6f52c06c, - 0x6211e6b5, - 0x66d0fb02, - 0x5e9f46bf, - 0x5a5e5b08, - 0x571d7dd1, - 0x53dc6066, - 0x4d9b3063, - 0x495a2dd4, - 0x44190b0d, - 0x40d816ba, - unchecked((int)0xaca5c697), - unchecked((int)0xa864db20), - unchecked((int)0xa527fdf9), - unchecked((int)0xa1e6e04e), - unchecked((int)0xbfa1b04b), - unchecked((int)0xbb60adfc), - unchecked((int)0xb6238b25), - unchecked((int)0xb2e29692), - unchecked((int)0x8aad2b2f), - unchecked((int)0x8e6c3698), - unchecked((int)0x832f1041), - unchecked((int)0x87ee0df6), - unchecked((int)0x99a95df3), - unchecked((int)0x9d684044), - unchecked((int)0x902b669d), - unchecked((int)0x94ea7b2a), - unchecked((int)0xe0b41de7), - unchecked((int)0xe4750050), - unchecked((int)0xe9362689), - unchecked((int)0xedf73b3e), - unchecked((int)0xf3b06b3b), - unchecked((int)0xf771768c), - unchecked((int)0xfa325055), - unchecked((int)0xfef34de2), - unchecked((int)0xc6bcf05f), - unchecked((int)0xc27dede8), - unchecked((int)0xcf3ecb31), - unchecked((int)0xcbffd686), - unchecked((int)0xd5b88683), - unchecked((int)0xd1799b34), - unchecked((int)0xdc3abded), - unchecked((int)0xd8fba05a), - 0x690ce0ee, - 0x6dcdfd59, - 0x608edb80, - 0x644fc637, - 0x7a089632, - 0x7ec98b85, - 0x738aad5c, - 0x774bb0eb, - 0x4f040d56, - 0x4bc510e1, - 0x46863638, - 0x42472b8f, - 0x5c007b8a, - 0x58c1663d, - 0x558240e4, - 0x51435d53, - 0x251d3b9e, - 0x21dc2629, - 0x2c9f00f0, - 0x285e1d47, - 0x36194d42, - 0x32d850f5, - 0x3f9b762c, - 0x3b5a6b9b, - 0x0315d626, - 0x07d4cb91, - 0x0a97ed48, - 0x0e56f0ff, - 0x1011a0fa, - 0x14d0bd4d, - 0x19939b94, - 0x1d528623, - unchecked((int)0xf12f560e), - unchecked((int)0xf5ee4bb9), - unchecked((int)0xf8ad6d60), - unchecked((int)0xfc6c70d7), - unchecked((int)0xe22b20d2), - unchecked((int)0xe6ea3d65), - unchecked((int)0xeba91bbc), - unchecked((int)0xef68060b), - unchecked((int)0xd727bbb6), - unchecked((int)0xd3e6a601), - unchecked((int)0xdea580d8), - unchecked((int)0xda649d6f), - unchecked((int)0xc423cd6a), - unchecked((int)0xc0e2d0dd), - unchecked((int)0xcda1f604), - unchecked((int)0xc960ebb3), - unchecked((int)0xbd3e8d7e), - unchecked((int)0xb9ff90c9), - unchecked((int)0xb4bcb610), - unchecked((int)0xb07daba7), - unchecked((int)0xae3afba2), - unchecked((int)0xaafbe615), - unchecked((int)0xa7b8c0cc), - unchecked((int)0xa379dd7b), - unchecked((int)0x9b3660c6), - unchecked((int)0x9ff77d71), - unchecked((int)0x92b45ba8), - unchecked((int)0x9675461f), - unchecked((int)0x8832161a), - unchecked((int)0x8cf30bad), - unchecked((int)0x81b02d74), - unchecked((int)0x857130c3), - 0x5d8a9099, - 0x594b8d2e, - 0x5408abf7, - 0x50c9b640, - 0x4e8ee645, - 0x4a4ffbf2, - 0x470cdd2b, - 0x43cdc09c, - 0x7b827d21, - 0x7f436096, - 0x7200464f, - 0x76c15bf8, - 0x68860bfd, - 0x6c47164a, - 0x61043093, - 0x65c52d24, - 0x119b4be9, - 0x155a565e, - 0x18197087, - 0x1cd86d30, - 0x029f3d35, - 0x065e2082, - 0x0b1d065b, - 0x0fdc1bec, - 0x3793a651, - 0x3352bbe6, - 0x3e119d3f, - 0x3ad08088, - 0x2497d08d, - 0x2056cd3a, - 0x2d15ebe3, - 0x29d4f654, - unchecked((int)0xc5a92679), - unchecked((int)0xc1683bce), - unchecked((int)0xcc2b1d17), - unchecked((int)0xc8ea00a0), - unchecked((int)0xd6ad50a5), - unchecked((int)0xd26c4d12), - unchecked((int)0xdf2f6bcb), - unchecked((int)0xdbee767c), - unchecked((int)0xe3a1cbc1), - unchecked((int)0xe760d676), - unchecked((int)0xea23f0af), - unchecked((int)0xeee2ed18), - unchecked((int)0xf0a5bd1d), - unchecked((int)0xf464a0aa), - unchecked((int)0xf9278673), - unchecked((int)0xfde69bc4), - unchecked((int)0x89b8fd09), - unchecked((int)0x8d79e0be), - unchecked((int)0x803ac667), - unchecked((int)0x84fbdbd0), - unchecked((int)0x9abc8bd5), - unchecked((int)0x9e7d9662), - unchecked((int)0x933eb0bb), - unchecked((int)0x97ffad0c), - unchecked((int)0xafb010b1), - unchecked((int)0xab710d06), - unchecked((int)0xa6322bdf), - unchecked((int)0xa2f33668), - unchecked((int)0xbcb4666d), - unchecked((int)0xb8757bda), - unchecked((int)0xb5365d03), - unchecked((int)0xb1f740b4) - }; + 0x00000000, + 0x04c11db7, + 0x09823b6e, + 0x0d4326d9, + 0x130476dc, + 0x17c56b6b, + 0x1a864db2, + 0x1e475005, + 0x2608edb8, + 0x22c9f00f, + 0x2f8ad6d6, + 0x2b4bcb61, + 0x350c9b64, + 0x31cd86d3, + 0x3c8ea00a, + 0x384fbdbd, + 0x4c11db70, + 0x48d0c6c7, + 0x4593e01e, + 0x4152fda9, + 0x5f15adac, + 0x5bd4b01b, + 0x569796c2, + 0x52568b75, + 0x6a1936c8, + 0x6ed82b7f, + 0x639b0da6, + 0x675a1011, + 0x791d4014, + 0x7ddc5da3, + 0x709f7b7a, + 0x745e66cd, + unchecked((int)0x9823b6e0), + unchecked((int)0x9ce2ab57), + unchecked((int)0x91a18d8e), + unchecked((int)0x95609039), + unchecked((int)0x8b27c03c), + unchecked((int)0x8fe6dd8b), + unchecked((int)0x82a5fb52), + unchecked((int)0x8664e6e5), + unchecked((int)0xbe2b5b58), + unchecked((int)0xbaea46ef), + unchecked((int)0xb7a96036), + unchecked((int)0xb3687d81), + unchecked((int)0xad2f2d84), + unchecked((int)0xa9ee3033), + unchecked((int)0xa4ad16ea), + unchecked((int)0xa06c0b5d), + unchecked((int)0xd4326d90), + unchecked((int)0xd0f37027), + unchecked((int)0xddb056fe), + unchecked((int)0xd9714b49), + unchecked((int)0xc7361b4c), + unchecked((int)0xc3f706fb), + unchecked((int)0xceb42022), + unchecked((int)0xca753d95), + unchecked((int)0xf23a8028), + unchecked((int)0xf6fb9d9f), + unchecked((int)0xfbb8bb46), + unchecked((int)0xff79a6f1), + unchecked((int)0xe13ef6f4), + unchecked((int)0xe5ffeb43), + unchecked((int)0xe8bccd9a), + unchecked((int)0xec7dd02d), + 0x34867077, + 0x30476dc0, + 0x3d044b19, + 0x39c556ae, + 0x278206ab, + 0x23431b1c, + 0x2e003dc5, + 0x2ac12072, + 0x128e9dcf, + 0x164f8078, + 0x1b0ca6a1, + 0x1fcdbb16, + 0x018aeb13, + 0x054bf6a4, + 0x0808d07d, + 0x0cc9cdca, + 0x7897ab07, + 0x7c56b6b0, + 0x71159069, + 0x75d48dde, + 0x6b93dddb, + 0x6f52c06c, + 0x6211e6b5, + 0x66d0fb02, + 0x5e9f46bf, + 0x5a5e5b08, + 0x571d7dd1, + 0x53dc6066, + 0x4d9b3063, + 0x495a2dd4, + 0x44190b0d, + 0x40d816ba, + unchecked((int)0xaca5c697), + unchecked((int)0xa864db20), + unchecked((int)0xa527fdf9), + unchecked((int)0xa1e6e04e), + unchecked((int)0xbfa1b04b), + unchecked((int)0xbb60adfc), + unchecked((int)0xb6238b25), + unchecked((int)0xb2e29692), + unchecked((int)0x8aad2b2f), + unchecked((int)0x8e6c3698), + unchecked((int)0x832f1041), + unchecked((int)0x87ee0df6), + unchecked((int)0x99a95df3), + unchecked((int)0x9d684044), + unchecked((int)0x902b669d), + unchecked((int)0x94ea7b2a), + unchecked((int)0xe0b41de7), + unchecked((int)0xe4750050), + unchecked((int)0xe9362689), + unchecked((int)0xedf73b3e), + unchecked((int)0xf3b06b3b), + unchecked((int)0xf771768c), + unchecked((int)0xfa325055), + unchecked((int)0xfef34de2), + unchecked((int)0xc6bcf05f), + unchecked((int)0xc27dede8), + unchecked((int)0xcf3ecb31), + unchecked((int)0xcbffd686), + unchecked((int)0xd5b88683), + unchecked((int)0xd1799b34), + unchecked((int)0xdc3abded), + unchecked((int)0xd8fba05a), + 0x690ce0ee, + 0x6dcdfd59, + 0x608edb80, + 0x644fc637, + 0x7a089632, + 0x7ec98b85, + 0x738aad5c, + 0x774bb0eb, + 0x4f040d56, + 0x4bc510e1, + 0x46863638, + 0x42472b8f, + 0x5c007b8a, + 0x58c1663d, + 0x558240e4, + 0x51435d53, + 0x251d3b9e, + 0x21dc2629, + 0x2c9f00f0, + 0x285e1d47, + 0x36194d42, + 0x32d850f5, + 0x3f9b762c, + 0x3b5a6b9b, + 0x0315d626, + 0x07d4cb91, + 0x0a97ed48, + 0x0e56f0ff, + 0x1011a0fa, + 0x14d0bd4d, + 0x19939b94, + 0x1d528623, + unchecked((int)0xf12f560e), + unchecked((int)0xf5ee4bb9), + unchecked((int)0xf8ad6d60), + unchecked((int)0xfc6c70d7), + unchecked((int)0xe22b20d2), + unchecked((int)0xe6ea3d65), + unchecked((int)0xeba91bbc), + unchecked((int)0xef68060b), + unchecked((int)0xd727bbb6), + unchecked((int)0xd3e6a601), + unchecked((int)0xdea580d8), + unchecked((int)0xda649d6f), + unchecked((int)0xc423cd6a), + unchecked((int)0xc0e2d0dd), + unchecked((int)0xcda1f604), + unchecked((int)0xc960ebb3), + unchecked((int)0xbd3e8d7e), + unchecked((int)0xb9ff90c9), + unchecked((int)0xb4bcb610), + unchecked((int)0xb07daba7), + unchecked((int)0xae3afba2), + unchecked((int)0xaafbe615), + unchecked((int)0xa7b8c0cc), + unchecked((int)0xa379dd7b), + unchecked((int)0x9b3660c6), + unchecked((int)0x9ff77d71), + unchecked((int)0x92b45ba8), + unchecked((int)0x9675461f), + unchecked((int)0x8832161a), + unchecked((int)0x8cf30bad), + unchecked((int)0x81b02d74), + unchecked((int)0x857130c3), + 0x5d8a9099, + 0x594b8d2e, + 0x5408abf7, + 0x50c9b640, + 0x4e8ee645, + 0x4a4ffbf2, + 0x470cdd2b, + 0x43cdc09c, + 0x7b827d21, + 0x7f436096, + 0x7200464f, + 0x76c15bf8, + 0x68860bfd, + 0x6c47164a, + 0x61043093, + 0x65c52d24, + 0x119b4be9, + 0x155a565e, + 0x18197087, + 0x1cd86d30, + 0x029f3d35, + 0x065e2082, + 0x0b1d065b, + 0x0fdc1bec, + 0x3793a651, + 0x3352bbe6, + 0x3e119d3f, + 0x3ad08088, + 0x2497d08d, + 0x2056cd3a, + 0x2d15ebe3, + 0x29d4f654, + unchecked((int)0xc5a92679), + unchecked((int)0xc1683bce), + unchecked((int)0xcc2b1d17), + unchecked((int)0xc8ea00a0), + unchecked((int)0xd6ad50a5), + unchecked((int)0xd26c4d12), + unchecked((int)0xdf2f6bcb), + unchecked((int)0xdbee767c), + unchecked((int)0xe3a1cbc1), + unchecked((int)0xe760d676), + unchecked((int)0xea23f0af), + unchecked((int)0xeee2ed18), + unchecked((int)0xf0a5bd1d), + unchecked((int)0xf464a0aa), + unchecked((int)0xf9278673), + unchecked((int)0xfde69bc4), + unchecked((int)0x89b8fd09), + unchecked((int)0x8d79e0be), + unchecked((int)0x803ac667), + unchecked((int)0x84fbdbd0), + unchecked((int)0x9abc8bd5), + unchecked((int)0x9e7d9662), + unchecked((int)0x933eb0bb), + unchecked((int)0x97ffad0c), + unchecked((int)0xafb010b1), + unchecked((int)0xab710d06), + unchecked((int)0xa6322bdf), + unchecked((int)0xa2f33668), + unchecked((int)0xbcb4666d), + unchecked((int)0xb8757bda), + unchecked((int)0xb5365d03), + unchecked((int)0xb1f740b4) + }; - public CRC() - { - InitialiseCRC(); - } - - internal void InitialiseCRC() - { - globalCrc = unchecked((int)0xffffffff); - } - - internal int GetFinalCRC() - { - return ~globalCrc; - } - - internal int GetGlobalCRC() - { - return globalCrc; - } - - internal void SetGlobalCRC(int newCrc) - { - globalCrc = newCrc; - } - - internal void UpdateCRC(int inCh) - { - int temp = (globalCrc >> 24) ^ inCh; - if (temp < 0) - { - temp = 256 + temp; - } - globalCrc = (globalCrc << 8) ^ crc32Table[temp]; - } - - internal int globalCrc; + public CRC() + { + InitialiseCRC(); } + + internal void InitialiseCRC() + { + globalCrc = unchecked((int)0xffffffff); + } + + internal int GetFinalCRC() + { + return ~globalCrc; + } + + internal int GetGlobalCRC() + { + return globalCrc; + } + + internal void SetGlobalCRC(int newCrc) + { + globalCrc = newCrc; + } + + internal void UpdateCRC(int inCh) + { + var temp = (globalCrc >> 24) ^ inCh; + if (temp < 0) + { + temp = 256 + temp; + } + globalCrc = (globalCrc << 8) ^ crc32Table[temp]; + } + + internal int globalCrc; } diff --git a/src/SharpCompress/Compressors/CompressionMode.cs b/src/SharpCompress/Compressors/CompressionMode.cs index a886c441..4eba1121 100644 --- a/src/SharpCompress/Compressors/CompressionMode.cs +++ b/src/SharpCompress/Compressors/CompressionMode.cs @@ -1,8 +1,7 @@ -namespace SharpCompress.Compressors +namespace SharpCompress.Compressors; + +public enum CompressionMode { - public enum CompressionMode - { - Compress = 0, - Decompress = 1 - } + Compress = 0, + Decompress = 1 } diff --git a/src/SharpCompress/Compressors/Deflate/CRC32.cs b/src/SharpCompress/Compressors/Deflate/CRC32.cs index c1f3a0e2..01e5ba2a 100644 --- a/src/SharpCompress/Compressors/Deflate/CRC32.cs +++ b/src/SharpCompress/Compressors/Deflate/CRC32.cs @@ -35,260 +35,253 @@ using System; using System.IO; -namespace SharpCompress.Compressors.Deflate +namespace SharpCompress.Compressors.Deflate; + +/// +/// Calculates a 32bit Cyclic Redundancy Checksum (CRC) using the same polynomial +/// used by Zip. This type is used internally by DotNetZip; it is generally not used +/// directly by applications wishing to create, read, or manipulate zip archive +/// files. +/// +[CLSCompliant(false)] +public class CRC32 { - /// - /// Calculates a 32bit Cyclic Redundancy Checksum (CRC) using the same polynomial - /// used by Zip. This type is used internally by DotNetZip; it is generally not used - /// directly by applications wishing to create, read, or manipulate zip archive - /// files. - /// - [CLSCompliant(false)] - public class CRC32 + private const int BUFFER_SIZE = 8192; + private static readonly uint[] crc32Table; + private uint runningCrc32Result = 0xFFFFFFFF; + + static CRC32() { - private const int BUFFER_SIZE = 8192; - private static readonly UInt32[] crc32Table; - private UInt32 runningCrc32Result = 0xFFFFFFFF; - - static CRC32() + unchecked { - unchecked + // PKZip specifies CRC32 with a polynomial of 0xEDB88320; + // This is also the CRC-32 polynomial used bby Ethernet, FDDI, + // bzip2, gzip, and others. + // Often the polynomial is shown reversed as 0x04C11DB7. + // For more details, see http://en.wikipedia.org/wiki/Cyclic_redundancy_check + var dwPolynomial = 0xEDB88320; + uint i, + j; + + crc32Table = new uint[256]; + + uint dwCrc; + for (i = 0; i < 256; i++) { - // PKZip specifies CRC32 with a polynomial of 0xEDB88320; - // This is also the CRC-32 polynomial used bby Ethernet, FDDI, - // bzip2, gzip, and others. - // Often the polynomial is shown reversed as 0x04C11DB7. - // For more details, see http://en.wikipedia.org/wiki/Cyclic_redundancy_check - UInt32 dwPolynomial = 0xEDB88320; - UInt32 i, - j; - - crc32Table = new UInt32[256]; - - UInt32 dwCrc; - for (i = 0; i < 256; i++) + dwCrc = i; + for (j = 8; j > 0; j--) { - dwCrc = i; - for (j = 8; j > 0; j--) + if ((dwCrc & 1) == 1) { - if ((dwCrc & 1) == 1) - { - dwCrc = (dwCrc >> 1) ^ dwPolynomial; - } - else - { - dwCrc >>= 1; - } + dwCrc = (dwCrc >> 1) ^ dwPolynomial; } - crc32Table[i] = dwCrc; - } - } - } - - /// - /// indicates the total number of bytes read on the CRC stream. - /// This is used when writing the ZipDirEntry when compressing files. - /// - public Int64 TotalBytesRead { get; private set; } - - /// - /// Indicates the current CRC for all blocks slurped in. - /// - public Int32 Crc32Result => unchecked((Int32)(~runningCrc32Result)); - - /// - /// Returns the CRC32 for the specified stream. - /// - /// The stream over which to calculate the CRC32 - /// the CRC32 calculation - public UInt32 GetCrc32(Stream input) - { - return GetCrc32AndCopy(input, null); - } - - /// - /// Returns the CRC32 for the specified stream, and writes the input into the - /// output stream. - /// - /// The stream over which to calculate the CRC32 - /// The stream into which to deflate the input - /// the CRC32 calculation - public UInt32 GetCrc32AndCopy(Stream input, Stream? output) - { - if (input is null) - { - throw new ZlibException("The input stream must not be null."); - } - unchecked - { - //UInt32 crc32Result; - //crc32Result = 0xFFFFFFFF; - var buffer = new byte[BUFFER_SIZE]; - int readSize = BUFFER_SIZE; - - TotalBytesRead = 0; - int count = input.Read(buffer, 0, readSize); - if (output != null) - { - output.Write(buffer, 0, count); - } - TotalBytesRead += count; - while (count > 0) - { - SlurpBlock(buffer, 0, count); - count = input.Read(buffer, 0, readSize); - if (output != null) + else { - output.Write(buffer, 0, count); + dwCrc >>= 1; } - TotalBytesRead += count; } - - return ~runningCrc32Result; + crc32Table[i] = dwCrc; } } + } - /// - /// Get the CRC32 for the given (word,byte) combo. This is a computation - /// defined by PKzip. - /// - /// The word to start with. - /// The byte to combine it with. - /// The CRC-ized result. - public Int32 ComputeCrc32(Int32 W, byte B) + /// + /// indicates the total number of bytes read on the CRC stream. + /// This is used when writing the ZipDirEntry when compressing files. + /// + public long TotalBytesRead { get; private set; } + + /// + /// Indicates the current CRC for all blocks slurped in. + /// + public int Crc32Result => unchecked((int)(~runningCrc32Result)); + + /// + /// Returns the CRC32 for the specified stream. + /// + /// The stream over which to calculate the CRC32 + /// the CRC32 calculation + public uint GetCrc32(Stream input) + { + return GetCrc32AndCopy(input, null); + } + + /// + /// Returns the CRC32 for the specified stream, and writes the input into the + /// output stream. + /// + /// The stream over which to calculate the CRC32 + /// The stream into which to deflate the input + /// the CRC32 calculation + public uint GetCrc32AndCopy(Stream input, Stream? output) + { + if (input is null) { - return _InternalComputeCrc32((UInt32)W, B); + throw new ZlibException("The input stream must not be null."); } - - internal int _InternalComputeCrc32(UInt32 W, byte B) + unchecked { - return (Int32)(crc32Table[(W ^ B) & 0xFF] ^ (W >> 8)); - } + //UInt32 crc32Result; + //crc32Result = 0xFFFFFFFF; + var buffer = new byte[BUFFER_SIZE]; + var readSize = BUFFER_SIZE; - /// - /// Update the value for the running CRC32 using the given block of bytes. - /// This is useful when using the CRC32() class in a Stream. - /// - /// block of bytes to slurp - /// starting point in the block - /// how many bytes within the block to slurp - public void SlurpBlock(byte[] block, int offset, int count) - { - if (block is null) - { - throw new ZlibException("The data buffer must not be null."); - } - - for (int i = 0; i < count; i++) - { - int x = offset + i; - runningCrc32Result = - ((runningCrc32Result) >> 8) - ^ crc32Table[(block[x]) ^ ((runningCrc32Result) & 0x000000FF)]; - } + TotalBytesRead = 0; + var count = input.Read(buffer, 0, readSize); + output?.Write(buffer, 0, count); TotalBytesRead += count; + while (count > 0) + { + SlurpBlock(buffer, 0, count); + count = input.Read(buffer, 0, readSize); + output?.Write(buffer, 0, count); + TotalBytesRead += count; + } + + return ~runningCrc32Result; + } + } + + /// + /// Get the CRC32 for the given (word,byte) combo. This is a computation + /// defined by PKzip. + /// + /// The word to start with. + /// The byte to combine it with. + /// The CRC-ized result. + public int ComputeCrc32(int W, byte B) + { + return _InternalComputeCrc32((uint)W, B); + } + + internal int _InternalComputeCrc32(uint W, byte B) + { + return (int)(crc32Table[(W ^ B) & 0xFF] ^ (W >> 8)); + } + + /// + /// Update the value for the running CRC32 using the given block of bytes. + /// This is useful when using the CRC32() class in a Stream. + /// + /// block of bytes to slurp + /// starting point in the block + /// how many bytes within the block to slurp + public void SlurpBlock(byte[] block, int offset, int count) + { + if (block is null) + { + throw new ZlibException("The data buffer must not be null."); } - // pre-initialize the crc table for speed of lookup. - - private uint gf2_matrix_times(ReadOnlySpan matrix, uint vec) + for (var i = 0; i < count; i++) { - uint sum = 0; - int i = 0; - while (vec != 0) + var x = offset + i; + runningCrc32Result = + ((runningCrc32Result) >> 8) + ^ crc32Table[(block[x]) ^ ((runningCrc32Result) & 0x000000FF)]; + } + TotalBytesRead += count; + } + + // pre-initialize the crc table for speed of lookup. + + private uint gf2_matrix_times(ReadOnlySpan matrix, uint vec) + { + uint sum = 0; + var i = 0; + while (vec != 0) + { + if ((vec & 0x01) == 0x01) { - if ((vec & 0x01) == 0x01) - { - sum ^= matrix[i]; - } - vec >>= 1; - i++; + sum ^= matrix[i]; } - return sum; + vec >>= 1; + i++; + } + return sum; + } + + private void gf2_matrix_square(Span square, Span mat) + { + for (var i = 0; i < 32; i++) + { + square[i] = gf2_matrix_times(mat, mat[i]); + } + } + + /// + /// Combines the given CRC32 value with the current running total. + /// + /// + /// This is useful when using a divide-and-conquer approach to calculating a CRC. + /// Multiple threads can each calculate a CRC32 on a segment of the data, and then + /// combine the individual CRC32 values at the end. + /// + /// the crc value to be combined with this one + /// the length of data the CRC value was calculated on + public void Combine(int crc, int length) + { + Span even = stackalloc uint[32]; // even-power-of-two zeros operator + Span odd = stackalloc uint[32]; // odd-power-of-two zeros operator + + if (length == 0) + { + return; } - private void gf2_matrix_square(Span square, Span mat) + var crc1 = ~runningCrc32Result; + var crc2 = (uint)crc; + + // put operator for one zero bit in odd + odd[0] = 0xEDB88320; // the CRC-32 polynomial + uint row = 1; + for (var i = 1; i < 32; i++) { - for (int i = 0; i < 32; i++) - { - square[i] = gf2_matrix_times(mat, mat[i]); - } + odd[i] = row; + row <<= 1; } - /// - /// Combines the given CRC32 value with the current running total. - /// - /// - /// This is useful when using a divide-and-conquer approach to calculating a CRC. - /// Multiple threads can each calculate a CRC32 on a segment of the data, and then - /// combine the individual CRC32 values at the end. - /// - /// the crc value to be combined with this one - /// the length of data the CRC value was calculated on - public void Combine(int crc, int length) + // put operator for two zero bits in even + gf2_matrix_square(even, odd); + + // put operator for four zero bits in odd + gf2_matrix_square(odd, even); + + var len2 = (uint)length; + + // apply len2 zeros to crc1 (first square will put the operator for one + // zero byte, eight zero bits, in even) + do { - Span even = stackalloc uint[32]; // even-power-of-two zeros operator - Span odd = stackalloc uint[32]; // odd-power-of-two zeros operator - - if (length == 0) - { - return; - } - - uint crc1 = ~runningCrc32Result; - var crc2 = (uint)crc; - - // put operator for one zero bit in odd - odd[0] = 0xEDB88320; // the CRC-32 polynomial - uint row = 1; - for (int i = 1; i < 32; i++) - { - odd[i] = row; - row <<= 1; - } - - // put operator for two zero bits in even + // apply zeros operator for this bit of len2 gf2_matrix_square(even, odd); - // put operator for four zero bits in odd - gf2_matrix_square(odd, even); - - var len2 = (uint)length; - - // apply len2 zeros to crc1 (first square will put the operator for one - // zero byte, eight zero bits, in even) - do + if ((len2 & 1) == 1) { - // apply zeros operator for this bit of len2 - gf2_matrix_square(even, odd); + crc1 = gf2_matrix_times(even, crc1); + } + len2 >>= 1; - if ((len2 & 1) == 1) - { - crc1 = gf2_matrix_times(even, crc1); - } - len2 >>= 1; + if (len2 == 0) + { + break; + } - if (len2 == 0) - { - break; - } + // another iteration of the loop with odd and even swapped + gf2_matrix_square(odd, even); + if ((len2 & 1) == 1) + { + crc1 = gf2_matrix_times(odd, crc1); + } + len2 >>= 1; + } while (len2 != 0); - // another iteration of the loop with odd and even swapped - gf2_matrix_square(odd, even); - if ((len2 & 1) == 1) - { - crc1 = gf2_matrix_times(odd, crc1); - } - len2 >>= 1; - } while (len2 != 0); + crc1 ^= crc2; - crc1 ^= crc2; + runningCrc32Result = ~crc1; - runningCrc32Result = ~crc1; - - //return (int) crc1; - } - - // private member vars + //return (int) crc1; } + + // private member vars } diff --git a/src/SharpCompress/Compressors/Deflate/DeflateManager.cs b/src/SharpCompress/Compressors/Deflate/DeflateManager.cs index e6dd441d..f424b1a0 100644 --- a/src/SharpCompress/Compressors/Deflate/DeflateManager.cs +++ b/src/SharpCompress/Compressors/Deflate/DeflateManager.cs @@ -72,1322 +72,1464 @@ using System; using SharpCompress.Algorithms; -namespace SharpCompress.Compressors.Deflate +namespace SharpCompress.Compressors.Deflate; + +internal sealed partial class DeflateManager { - internal sealed partial class DeflateManager + // extra bits for each length code + internal static readonly int[] ExtraLengthBits = { - // extra bits for each length code - internal static readonly int[] ExtraLengthBits = - { - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1, - 1, - 1, - 1, - 2, - 2, - 2, - 2, - 3, - 3, - 3, - 3, - 4, - 4, - 4, - 4, - 5, - 5, - 5, - 5, - 0 - }; + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 4, + 4, + 4, + 4, + 5, + 5, + 5, + 5, + 0 + }; - // extra bits for each distance code - internal static readonly int[] ExtraDistanceBits = - { - 0, - 0, - 0, - 0, - 1, - 1, - 2, - 2, - 3, - 3, - 4, - 4, - 5, - 5, - 6, - 6, - 7, - 7, - 8, - 8, - 9, - 9, - 10, - 10, - 11, - 11, - 12, - 12, - 13, - 13 - }; + // extra bits for each distance code + internal static readonly int[] ExtraDistanceBits = + { + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 2, + 3, + 3, + 4, + 4, + 5, + 5, + 6, + 6, + 7, + 7, + 8, + 8, + 9, + 9, + 10, + 10, + 11, + 11, + 12, + 12, + 13, + 13 + }; - internal enum BlockState + internal enum BlockState + { + NeedMore = 0, // block not completed, need more input or more output + BlockDone, // block flush performed + FinishStarted, // finish started, need only more output at next deflate + FinishDone // finish done, accept no more input or output + } + + internal enum DeflateFlavor + { + Store, + Fast, + Slow + } + + private const int MEM_LEVEL_MAX = 9; + private const int MEM_LEVEL_DEFAULT = 8; + + internal delegate BlockState CompressFunc(FlushType flush); + + internal class Config + { + // Use a faster search when the previous match is longer than this + internal int GoodLength; // reduce lazy search above this match length + + // Attempt to find a better match only when the current match is + // strictly smaller than this value. This mechanism is used only for + // compression levels >= 4. For levels 1,2,3: MaxLazy is actually + // MaxInsertLength. (See DeflateFast) + + internal int MaxLazy; // do not perform lazy search above this match length + + internal int NiceLength; // quit search above this match length + + // To speed up deflation, hash chains are never searched beyond this + // length. A higher limit improves compression ratio but degrades the speed. + + internal int MaxChainLength; + + internal DeflateFlavor Flavor; + + private Config( + int goodLength, + int maxLazy, + int niceLength, + int maxChainLength, + DeflateFlavor flavor + ) { - NeedMore = 0, // block not completed, need more input or more output - BlockDone, // block flush performed - FinishStarted, // finish started, need only more output at next deflate - FinishDone // finish done, accept no more input or output + GoodLength = goodLength; + MaxLazy = maxLazy; + NiceLength = niceLength; + MaxChainLength = maxChainLength; + Flavor = flavor; } - internal enum DeflateFlavor + public static Config Lookup(CompressionLevel level) { - Store, - Fast, - Slow + return Table[(int)level]; } - private const int MEM_LEVEL_MAX = 9; - private const int MEM_LEVEL_DEFAULT = 8; - - internal delegate BlockState CompressFunc(FlushType flush); - - internal class Config + static Config() { - // Use a faster search when the previous match is longer than this - internal int GoodLength; // reduce lazy search above this match length - - // Attempt to find a better match only when the current match is - // strictly smaller than this value. This mechanism is used only for - // compression levels >= 4. For levels 1,2,3: MaxLazy is actually - // MaxInsertLength. (See DeflateFast) - - internal int MaxLazy; // do not perform lazy search above this match length - - internal int NiceLength; // quit search above this match length - - // To speed up deflation, hash chains are never searched beyond this - // length. A higher limit improves compression ratio but degrades the speed. - - internal int MaxChainLength; - - internal DeflateFlavor Flavor; - - private Config( - int goodLength, - int maxLazy, - int niceLength, - int maxChainLength, - DeflateFlavor flavor - ) + Table = new[] { - GoodLength = goodLength; - MaxLazy = maxLazy; - NiceLength = niceLength; - MaxChainLength = maxChainLength; - Flavor = flavor; + new Config(0, 0, 0, 0, DeflateFlavor.Store), + new Config(4, 4, 8, 4, DeflateFlavor.Fast), + new Config(4, 5, 16, 8, DeflateFlavor.Fast), + new Config(4, 6, 32, 32, DeflateFlavor.Fast), + new Config(4, 4, 16, 16, DeflateFlavor.Slow), + new Config(8, 16, 32, 32, DeflateFlavor.Slow), + new Config(8, 16, 128, 128, DeflateFlavor.Slow), + new Config(8, 32, 128, 256, DeflateFlavor.Slow), + new Config(32, 128, 258, 1024, DeflateFlavor.Slow), + new Config(32, 258, 258, 4096, DeflateFlavor.Slow) + }; + } + + private static readonly Config[] Table; + } + + private CompressFunc DeflateFunction; + + private static readonly string[] _ErrorMessage = + { + "need dictionary", + "stream end", + "", + "file error", + "stream error", + "data error", + "insufficient memory", + "buffer error", + "incompatible version", + "" + }; + + // preset dictionary flag in zlib header + private const int PRESET_DICT = 0x20; + + private const int INIT_STATE = 42; + private const int BUSY_STATE = 113; + private const int FINISH_STATE = 666; + + // The deflate compression method + private const int Z_DEFLATED = 8; + + private const int STORED_BLOCK = 0; + private const int STATIC_TREES = 1; + private const int DYN_TREES = 2; + + // The three kinds of block type + private const int Z_BINARY = 0; + private const int Z_ASCII = 1; + private const int Z_UNKNOWN = 2; + + private const int Buf_size = 8 * 2; + + private const int MIN_MATCH = 3; + private const int MAX_MATCH = 258; + + private const int MIN_LOOKAHEAD = (MAX_MATCH + MIN_MATCH + 1); + + private static readonly int HEAP_SIZE = ((2 * InternalConstants.L_CODES) + 1); + + private const int END_BLOCK = 256; + + internal ZlibCodec _codec; // the zlib encoder/decoder + internal int status; // as the name implies + internal byte[] pending; // output still pending - waiting to be compressed + internal int nextPending; // index of next pending byte to output to the stream + internal int pendingCount; // number of bytes in the pending buffer + + internal sbyte data_type; // UNKNOWN, BINARY or ASCII + internal int last_flush; // value of flush param for previous deflate call + + internal int w_size; // LZ77 window size (32K by default) + internal int w_bits; // log2(w_size) (8..16) + internal int w_mask; // w_size - 1 + + //internal byte[] dictionary; + internal byte[] window; + + // Sliding window. Input bytes are read into the second half of the window, + // and move to the first half later to keep a dictionary of at least wSize + // bytes. With this organization, matches are limited to a distance of + // wSize-MAX_MATCH bytes, but this ensures that IO is always + // performed with a length multiple of the block size. + // + // To do: use the user input buffer as sliding window. + + internal int window_size; + + // Actual size of window: 2*wSize, except when the user input buffer + // is directly used as sliding window. + + internal short[] prev; + + // Link to older string with same hash index. To limit the size of this + // array to 64K, this link is maintained only for the last 32K strings. + // An index in this array is thus a window index modulo 32K. + + private short[] head; // Heads of the hash chains or NIL. + + private int ins_h; // hash index of string to be inserted + private int hash_size; // number of elements in hash table + private int hash_bits; // log2(hash_size) + private int hash_mask; // hash_size-1 + + // Number of bits by which ins_h must be shifted at each input + // step. It must be such that after MIN_MATCH steps, the oldest + // byte no longer takes part in the hash key, that is: + // hash_shift * MIN_MATCH >= hash_bits + private int hash_shift; + + // Window position at the beginning of the current output block. Gets + // negative when the window is moved backwards. + + private int blockStart; + + private Config config; + private int match_length; // length of best match + private int prev_match; // previous match + private int match_available; // set if previous match exists + private int strstart; // start of string to insert into.....???? + private int match_start; // start of matching string + private int lookahead; // number of valid bytes ahead in window + + // Length of the best match at previous step. Matches not greater than this + // are discarded. This is used in the lazy match evaluation. + private int prev_length; + + // Insert new strings in the hash table only if the match length is not + // greater than this length. This saves time but degrades compression. + // max_insert_length is used only for compression levels <= 3. + + private CompressionLevel compressionLevel; // compression level (1..9) + private CompressionStrategy compressionStrategy; // favor or force Huffman coding + + private readonly short[] dyn_ltree; // literal and length tree + 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 + + // number of codes at each bit length for an optimal tree + private readonly short[] bl_count = new short[InternalConstants.MAX_BITS + 1]; + + // heap used to build the Huffman trees + private readonly int[] heap = new int[(2 * InternalConstants.L_CODES) + 1]; + + private int heap_len; // number of elements in the heap + private int heap_max; // element of largest frequency + + // The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + // The same heap array is used to build all trees. + + // Depth of each subtree used as tie breaker for trees of equal frequency + private readonly sbyte[] depth = new sbyte[(2 * InternalConstants.L_CODES) + 1]; + + private int _lengthOffset; // index for literals or lengths + + // Size of match buffer for literals/lengths. There are 4 reasons for + // limiting lit_bufsize to 64K: + // - frequencies can be kept in 16 bit counters + // - if compression is not successful for the first block, all input + // data is still in the window so we can still emit a stored block even + // when input comes from standard input. (This can also be done for + // all blocks if lit_bufsize is not greater than 32K.) + // - if compression is not successful for a file smaller than 64K, we can + // even emit a stored file instead of a stored block (saving 5 bytes). + // This is applicable only for zip (not gzip or zlib). + // - creating new Huffman trees less frequently may not provide fast + // adaptation to changes in the input data statistics. (Take for + // example a binary file with poorly compressible code followed by + // a highly compressible string table.) Smaller buffer sizes give + // fast adaptation but have of course the overhead of transmitting + // trees more frequently. + + internal int lit_bufsize; + + internal int last_lit; // running index in l_buf + + // Buffer for distances. To simplify the code, d_buf and l_buf have + // the same number of elements. To use different lengths, an extra flag + // array would be necessary. + + internal int _distanceOffset; // index into pending; points to distance data?? + + internal int opt_len; // bit length of current block with optimal trees + internal int static_len; // bit length of current block with static trees + internal int matches; // number of string matches in current block + internal int last_eob_len; // bit length of EOB code for last block + + // Output buffer. bits are inserted starting at the bottom (least + // significant bits). + internal short bi_buf; + + // Number of valid bits in bi_buf. All bits above the last valid bit + // are always zero. + internal int bi_valid; + + internal DeflateManager() + { + dyn_ltree = new short[HEAP_SIZE * 2]; + dyn_dtree = new short[((2 * InternalConstants.D_CODES) + 1) * 2]; // distance tree + bl_tree = new short[((2 * InternalConstants.BL_CODES) + 1) * 2]; // Huffman tree for bit lengths + } + + // lm_init + private void _InitializeLazyMatch() + { + window_size = 2 * w_size; + + // clear the hash - workitem 9063 + Array.Clear(head, 0, hash_size); + + //for (int i = 0; i < hash_size; i++) head[i] = 0; + + config = Config.Lookup(compressionLevel); + SetDeflater(); + + strstart = 0; + blockStart = 0; + lookahead = 0; + match_length = prev_length = MIN_MATCH - 1; + match_available = 0; + ins_h = 0; + } + + // Initialize the tree data structures for a new zlib stream. + private void _InitializeTreeData() + { + treeLiterals.dyn_tree = dyn_ltree; + treeLiterals.staticTree = StaticTree.Literals; + + treeDistances.dyn_tree = dyn_dtree; + treeDistances.staticTree = StaticTree.Distances; + + treeBitLengths.dyn_tree = bl_tree; + treeBitLengths.staticTree = StaticTree.BitLengths; + + bi_buf = 0; + bi_valid = 0; + last_eob_len = 8; // enough lookahead for inflate + + // Initialize the first block of the first file: + _InitializeBlocks(); + } + + internal void _InitializeBlocks() + { + // Initialize the trees. + for (var i = 0; i < InternalConstants.L_CODES; i++) + { + dyn_ltree[i * 2] = 0; + } + for (var i = 0; i < InternalConstants.D_CODES; i++) + { + dyn_dtree[i * 2] = 0; + } + for (var i = 0; i < InternalConstants.BL_CODES; i++) + { + bl_tree[i * 2] = 0; + } + + dyn_ltree[END_BLOCK * 2] = 1; + opt_len = static_len = 0; + last_lit = matches = 0; + } + + // Restore the heap property by moving down the tree starting at node k, + // exchanging a node with the smallest of its two sons if necessary, stopping + // when the heap property is re-established (each father smaller than its + // two sons). + internal void pqdownheap(short[] tree, int k) + { + var v = heap[k]; + var j = k << 1; // left son of k + while (j <= heap_len) + { + // Set j to the smallest of the two sons: + if (j < heap_len && IsSmaller(tree, heap[j + 1], heap[j], depth)) + { + j++; } - public static Config Lookup(CompressionLevel level) + // Exit if v is smaller than both sons + if (IsSmaller(tree, v, heap[j], depth)) { - return Table[(int)level]; + break; } - static Config() + // Exchange v with the smallest son + heap[k] = heap[j]; + k = j; + + // And continue down the tree, setting j to the left son of k + j <<= 1; + } + heap[k] = v; + } + + internal static bool IsSmaller(short[] tree, int n, int m, sbyte[] depth) + { + var tn2 = tree[n * 2]; + var tm2 = tree[m * 2]; + return (tn2 < tm2 || (tn2 == tm2 && depth[n] <= depth[m])); + } + + // Scan a literal or distance tree to determine the frequencies of the codes + // in the bit length tree. + internal void ScanTree(short[] tree, int maxCode) + { + int n; // iterates over all tree elements + var prevlen = -1; // last emitted length + int curlen; // length of current code + int nextlen = tree[(0 * 2) + 1]; // length of next code + var count = 0; // repeat count of the current code + var max_count = 7; // max repeat count + var min_count = 4; // min repeat count + + if (nextlen == 0) + { + max_count = 138; + min_count = 3; + } + tree[((maxCode + 1) * 2) + 1] = 0x7fff; // guard //?? + + for (n = 0; n <= maxCode; n++) + { + curlen = nextlen; + nextlen = tree[((n + 1) * 2) + 1]; + if (++count < max_count && curlen == nextlen) { - Table = new[] - { - new Config(0, 0, 0, 0, DeflateFlavor.Store), - new Config(4, 4, 8, 4, DeflateFlavor.Fast), - new Config(4, 5, 16, 8, DeflateFlavor.Fast), - new Config(4, 6, 32, 32, DeflateFlavor.Fast), - new Config(4, 4, 16, 16, DeflateFlavor.Slow), - new Config(8, 16, 32, 32, DeflateFlavor.Slow), - new Config(8, 16, 128, 128, DeflateFlavor.Slow), - new Config(8, 32, 128, 256, DeflateFlavor.Slow), - new Config(32, 128, 258, 1024, DeflateFlavor.Slow), - new Config(32, 258, 258, 4096, DeflateFlavor.Slow) - }; + continue; } - - private static readonly Config[] Table; - } - - private CompressFunc DeflateFunction; - - private static readonly String[] _ErrorMessage = - { - "need dictionary", - "stream end", - "", - "file error", - "stream error", - "data error", - "insufficient memory", - "buffer error", - "incompatible version", - "" - }; - - // preset dictionary flag in zlib header - private const int PRESET_DICT = 0x20; - - private const int INIT_STATE = 42; - private const int BUSY_STATE = 113; - private const int FINISH_STATE = 666; - - // The deflate compression method - private const int Z_DEFLATED = 8; - - private const int STORED_BLOCK = 0; - private const int STATIC_TREES = 1; - private const int DYN_TREES = 2; - - // The three kinds of block type - private const int Z_BINARY = 0; - private const int Z_ASCII = 1; - private const int Z_UNKNOWN = 2; - - private const int Buf_size = 8 * 2; - - private const int MIN_MATCH = 3; - private const int MAX_MATCH = 258; - - private const int MIN_LOOKAHEAD = (MAX_MATCH + MIN_MATCH + 1); - - private static readonly int HEAP_SIZE = (2 * InternalConstants.L_CODES + 1); - - private const int END_BLOCK = 256; - - internal ZlibCodec _codec; // the zlib encoder/decoder - internal int status; // as the name implies - internal byte[] pending; // output still pending - waiting to be compressed - internal int nextPending; // index of next pending byte to output to the stream - internal int pendingCount; // number of bytes in the pending buffer - - internal sbyte data_type; // UNKNOWN, BINARY or ASCII - internal int last_flush; // value of flush param for previous deflate call - - internal int w_size; // LZ77 window size (32K by default) - internal int w_bits; // log2(w_size) (8..16) - internal int w_mask; // w_size - 1 - - //internal byte[] dictionary; - internal byte[] window; - - // Sliding window. Input bytes are read into the second half of the window, - // and move to the first half later to keep a dictionary of at least wSize - // bytes. With this organization, matches are limited to a distance of - // wSize-MAX_MATCH bytes, but this ensures that IO is always - // performed with a length multiple of the block size. - // - // To do: use the user input buffer as sliding window. - - internal int window_size; - - // Actual size of window: 2*wSize, except when the user input buffer - // is directly used as sliding window. - - internal short[] prev; - - // Link to older string with same hash index. To limit the size of this - // array to 64K, this link is maintained only for the last 32K strings. - // An index in this array is thus a window index modulo 32K. - - private short[] head; // Heads of the hash chains or NIL. - - private int ins_h; // hash index of string to be inserted - private int hash_size; // number of elements in hash table - private int hash_bits; // log2(hash_size) - private int hash_mask; // hash_size-1 - - // Number of bits by which ins_h must be shifted at each input - // step. It must be such that after MIN_MATCH steps, the oldest - // byte no longer takes part in the hash key, that is: - // hash_shift * MIN_MATCH >= hash_bits - private int hash_shift; - - // Window position at the beginning of the current output block. Gets - // negative when the window is moved backwards. - - private int blockStart; - - private Config config; - private int match_length; // length of best match - private int prev_match; // previous match - private int match_available; // set if previous match exists - private int strstart; // start of string to insert into.....???? - private int match_start; // start of matching string - private int lookahead; // number of valid bytes ahead in window - - // Length of the best match at previous step. Matches not greater than this - // are discarded. This is used in the lazy match evaluation. - private int prev_length; - - // Insert new strings in the hash table only if the match length is not - // greater than this length. This saves time but degrades compression. - // max_insert_length is used only for compression levels <= 3. - - private CompressionLevel compressionLevel; // compression level (1..9) - private CompressionStrategy compressionStrategy; // favor or force Huffman coding - - private readonly short[] dyn_ltree; // literal and length tree - 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 - - // number of codes at each bit length for an optimal tree - private readonly short[] bl_count = new short[InternalConstants.MAX_BITS + 1]; - - // heap used to build the Huffman trees - private readonly int[] heap = new int[2 * InternalConstants.L_CODES + 1]; - - private int heap_len; // number of elements in the heap - private int heap_max; // element of largest frequency - - // The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. - // The same heap array is used to build all trees. - - // Depth of each subtree used as tie breaker for trees of equal frequency - private readonly sbyte[] depth = new sbyte[2 * InternalConstants.L_CODES + 1]; - - private int _lengthOffset; // index for literals or lengths - - // Size of match buffer for literals/lengths. There are 4 reasons for - // limiting lit_bufsize to 64K: - // - frequencies can be kept in 16 bit counters - // - if compression is not successful for the first block, all input - // data is still in the window so we can still emit a stored block even - // when input comes from standard input. (This can also be done for - // all blocks if lit_bufsize is not greater than 32K.) - // - if compression is not successful for a file smaller than 64K, we can - // even emit a stored file instead of a stored block (saving 5 bytes). - // This is applicable only for zip (not gzip or zlib). - // - creating new Huffman trees less frequently may not provide fast - // adaptation to changes in the input data statistics. (Take for - // example a binary file with poorly compressible code followed by - // a highly compressible string table.) Smaller buffer sizes give - // fast adaptation but have of course the overhead of transmitting - // trees more frequently. - - internal int lit_bufsize; - - internal int last_lit; // running index in l_buf - - // Buffer for distances. To simplify the code, d_buf and l_buf have - // the same number of elements. To use different lengths, an extra flag - // array would be necessary. - - internal int _distanceOffset; // index into pending; points to distance data?? - - internal int opt_len; // bit length of current block with optimal trees - internal int static_len; // bit length of current block with static trees - internal int matches; // number of string matches in current block - internal int last_eob_len; // bit length of EOB code for last block - - // Output buffer. bits are inserted starting at the bottom (least - // significant bits). - internal short bi_buf; - - // Number of valid bits in bi_buf. All bits above the last valid bit - // are always zero. - internal int bi_valid; - - internal DeflateManager() - { - dyn_ltree = new short[HEAP_SIZE * 2]; - dyn_dtree = new short[(2 * InternalConstants.D_CODES + 1) * 2]; // distance tree - bl_tree = new short[(2 * InternalConstants.BL_CODES + 1) * 2]; // Huffman tree for bit lengths - } - - // lm_init - private void _InitializeLazyMatch() - { - window_size = 2 * w_size; - - // clear the hash - workitem 9063 - Array.Clear(head, 0, hash_size); - - //for (int i = 0; i < hash_size; i++) head[i] = 0; - - config = Config.Lookup(compressionLevel); - SetDeflater(); - - strstart = 0; - blockStart = 0; - lookahead = 0; - match_length = prev_length = MIN_MATCH - 1; - match_available = 0; - ins_h = 0; - } - - // Initialize the tree data structures for a new zlib stream. - private void _InitializeTreeData() - { - treeLiterals.dyn_tree = dyn_ltree; - treeLiterals.staticTree = StaticTree.Literals; - - treeDistances.dyn_tree = dyn_dtree; - treeDistances.staticTree = StaticTree.Distances; - - treeBitLengths.dyn_tree = bl_tree; - treeBitLengths.staticTree = StaticTree.BitLengths; - - bi_buf = 0; - bi_valid = 0; - last_eob_len = 8; // enough lookahead for inflate - - // Initialize the first block of the first file: - _InitializeBlocks(); - } - - internal void _InitializeBlocks() - { - // Initialize the trees. - for (int i = 0; i < InternalConstants.L_CODES; i++) + if (count < min_count) { - dyn_ltree[i * 2] = 0; + bl_tree[curlen * 2] = (short)(bl_tree[curlen * 2] + count); } - for (int i = 0; i < InternalConstants.D_CODES; i++) + else if (curlen != 0) { - dyn_dtree[i * 2] = 0; + if (curlen != prevlen) + { + bl_tree[curlen * 2]++; + } + bl_tree[InternalConstants.REP_3_6 * 2]++; } - for (int i = 0; i < InternalConstants.BL_CODES; i++) + else if (count <= 10) { - bl_tree[i * 2] = 0; - } - - dyn_ltree[END_BLOCK * 2] = 1; - opt_len = static_len = 0; - last_lit = matches = 0; - } - - // Restore the heap property by moving down the tree starting at node k, - // exchanging a node with the smallest of its two sons if necessary, stopping - // when the heap property is re-established (each father smaller than its - // two sons). - internal void pqdownheap(short[] tree, int k) - { - int v = heap[k]; - int j = k << 1; // left son of k - while (j <= heap_len) - { - // Set j to the smallest of the two sons: - if (j < heap_len && IsSmaller(tree, heap[j + 1], heap[j], depth)) - { - j++; - } - - // Exit if v is smaller than both sons - if (IsSmaller(tree, v, heap[j], depth)) - { - break; - } - - // Exchange v with the smallest son - heap[k] = heap[j]; - k = j; - - // And continue down the tree, setting j to the left son of k - j <<= 1; - } - heap[k] = v; - } - - internal static bool IsSmaller(short[] tree, int n, int m, sbyte[] depth) - { - short tn2 = tree[n * 2]; - short tm2 = tree[m * 2]; - return (tn2 < tm2 || (tn2 == tm2 && depth[n] <= depth[m])); - } - - // Scan a literal or distance tree to determine the frequencies of the codes - // in the bit length tree. - internal void ScanTree(short[] tree, int maxCode) - { - int n; // iterates over all tree elements - int prevlen = -1; // last emitted length - int curlen; // length of current code - int nextlen = tree[0 * 2 + 1]; // length of next code - int count = 0; // repeat count of the current code - int max_count = 7; // max repeat count - int min_count = 4; // min repeat count - - if (nextlen == 0) - { - max_count = 138; - min_count = 3; - } - tree[(maxCode + 1) * 2 + 1] = 0x7fff; // guard //?? - - for (n = 0; n <= maxCode; n++) - { - curlen = nextlen; - nextlen = tree[(n + 1) * 2 + 1]; - if (++count < max_count && curlen == nextlen) - { - continue; - } - if (count < min_count) - { - bl_tree[curlen * 2] = (short)(bl_tree[curlen * 2] + count); - } - else if (curlen != 0) - { - if (curlen != prevlen) - { - bl_tree[curlen * 2]++; - } - bl_tree[InternalConstants.REP_3_6 * 2]++; - } - else if (count <= 10) - { - bl_tree[InternalConstants.REPZ_3_10 * 2]++; - } - else - { - bl_tree[InternalConstants.REPZ_11_138 * 2]++; - } - count = 0; - prevlen = curlen; - if (nextlen == 0) - { - max_count = 138; - min_count = 3; - } - else if (curlen == nextlen) - { - max_count = 6; - min_count = 3; - } - else - { - max_count = 7; - min_count = 4; - } - } - } - - // Construct the Huffman tree for the bit lengths and return the index in - // bl_order of the last bit length code to send. - internal int BuildBlTree() - { - int max_blindex; // index of last bit length code of non zero freq - - // Determine the bit length frequencies for literal and distance trees - ScanTree(dyn_ltree, treeLiterals.max_code); - ScanTree(dyn_dtree, treeDistances.max_code); - - // Build the bit length tree: - treeBitLengths.build_tree(this); - - // opt_len now includes the length of the tree representations, except - // the lengths of the bit lengths codes and the 5+5+4 bits for the counts. - - // Determine the number of bit length codes to send. The pkzip format - // requires that at least 4 bit length codes be sent. (appnote.txt says - // 3 but the actual value used is 4.) - for (max_blindex = InternalConstants.BL_CODES - 1; max_blindex >= 3; max_blindex--) - { - if (bl_tree[Tree.bl_order[max_blindex] * 2 + 1] != 0) - { - break; - } - } - - // Update opt_len to include the bit length tree and counts - opt_len += 3 * (max_blindex + 1) + 5 + 5 + 4; - - return max_blindex; - } - - // Send the header for a block using dynamic Huffman trees: the counts, the - // lengths of the bit length codes, the literal tree and the distance tree. - // IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. - internal void send_all_trees(int lcodes, int dcodes, int blcodes) - { - int rank; // index in bl_order - - send_bits(lcodes - 257, 5); // not +255 as stated in appnote.txt - send_bits(dcodes - 1, 5); - send_bits(blcodes - 4, 4); // not -3 as stated in appnote.txt - for (rank = 0; rank < blcodes; rank++) - { - send_bits(bl_tree[Tree.bl_order[rank] * 2 + 1], 3); - } - send_tree(dyn_ltree, lcodes - 1); // literal tree - send_tree(dyn_dtree, dcodes - 1); // distance tree - } - - // Send a literal or distance tree in compressed form, using the codes in - // bl_tree. - internal void send_tree(short[] tree, int max_code) - { - int n; // iterates over all tree elements - int prevlen = -1; // last emitted length - int curlen; // length of current code - int nextlen = tree[0 * 2 + 1]; // length of next code - int count = 0; // repeat count of the current code - int max_count = 7; // max repeat count - int min_count = 4; // min repeat count - - if (nextlen == 0) - { - max_count = 138; - min_count = 3; - } - - for (n = 0; n <= max_code; n++) - { - curlen = nextlen; - nextlen = tree[(n + 1) * 2 + 1]; - if (++count < max_count && curlen == nextlen) - { - continue; - } - if (count < min_count) - { - do - { - send_code(curlen, bl_tree); - } while (--count != 0); - } - else if (curlen != 0) - { - if (curlen != prevlen) - { - send_code(curlen, bl_tree); - count--; - } - send_code(InternalConstants.REP_3_6, bl_tree); - send_bits(count - 3, 2); - } - else if (count <= 10) - { - send_code(InternalConstants.REPZ_3_10, bl_tree); - send_bits(count - 3, 3); - } - else - { - send_code(InternalConstants.REPZ_11_138, bl_tree); - send_bits(count - 11, 7); - } - count = 0; - prevlen = curlen; - if (nextlen == 0) - { - max_count = 138; - min_count = 3; - } - else if (curlen == nextlen) - { - max_count = 6; - min_count = 3; - } - else - { - max_count = 7; - min_count = 4; - } - } - } - - // Output a block of bytes on the stream. - // IN assertion: there is enough room in pending_buf. - private void put_bytes(byte[] p, int start, int len) - { - Array.Copy(p, start, pending, pendingCount, len); - pendingCount += len; - } - -#if NOTNEEDED - private void put_byte(byte c) - { - pending[pendingCount++] = c; - } - - internal void put_short(int b) - { - unchecked - { - pending[pendingCount++] = (byte)b; - pending[pendingCount++] = (byte)(b >> 8); - } - } - - internal void putShortMSB(int b) - { - unchecked - { - pending[pendingCount++] = (byte)(b >> 8); - pending[pendingCount++] = (byte)b; - } - } -#endif - - internal void send_code(int c, short[] tree) - { - int c2 = c * 2; - send_bits((tree[c2] & 0xffff), (tree[c2 + 1] & 0xffff)); - } - -#pragma warning disable 675 // workaround for Visual Studio 2015 compiler bug: https://github.com/dotnet/roslyn/issues/4027 - internal void send_bits(int value, int length) - { - int len = length; - unchecked - { - if (bi_valid > Buf_size - len) - { - //int val = value; - // bi_buf |= (val << bi_valid); - - bi_buf |= (short)((value << bi_valid) & 0xffff); - - //put_short(bi_buf); - pending[pendingCount++] = (byte)bi_buf; - pending[pendingCount++] = (byte)(bi_buf >> 8); - - bi_buf = (short)((uint)value >> (Buf_size - bi_valid)); - bi_valid += len - Buf_size; - } - else - { - // bi_buf |= (value) << bi_valid; - bi_buf |= (short)((value << bi_valid) & 0xffff); - bi_valid += len; - } - } - } -#pragma warning restore 675 - - // Send one empty static block to give enough lookahead for inflate. - // This takes 10 bits, of which 7 may remain in the bit buffer. - // The current inflate code requires 9 bits of lookahead. If the - // last two codes for the previous block (real code plus EOB) were coded - // on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode - // the last real code. In this case we send two empty static blocks instead - // of one. (There are no problems if the previous block is stored or fixed.) - // To simplify the code, we assume the worst case of last real code encoded - // on one bit only. - internal void _tr_align() - { - send_bits(STATIC_TREES << 1, 3); - send_code(END_BLOCK, StaticTree.lengthAndLiteralsTreeCodes); - - bi_flush(); - - // Of the 10 bits for the empty block, we have already sent - // (10 - bi_valid) bits. The lookahead for the last real code (before - // the EOB of the previous block) was thus at least one plus the length - // of the EOB plus what we have just sent of the empty static block. - if (1 + last_eob_len + 10 - bi_valid < 9) - { - send_bits(STATIC_TREES << 1, 3); - send_code(END_BLOCK, StaticTree.lengthAndLiteralsTreeCodes); - bi_flush(); - } - last_eob_len = 7; - } - - // Save the match info and tally the frequency counts. Return true if - // the current block must be flushed. - internal bool _tr_tally(int dist, int lc) - { - pending[_distanceOffset + last_lit * 2] = unchecked((byte)((uint)dist >> 8)); - pending[_distanceOffset + last_lit * 2 + 1] = unchecked((byte)dist); - pending[_lengthOffset + last_lit] = unchecked((byte)lc); - last_lit++; - - if (dist == 0) - { - // lc is the unmatched char - dyn_ltree[lc * 2]++; + bl_tree[InternalConstants.REPZ_3_10 * 2]++; } else { - matches++; - - // Here, lc is the match length - MIN_MATCH - dist--; // dist = match distance - 1 - dyn_ltree[(Tree.LengthCode[lc] + InternalConstants.LITERALS + 1) * 2]++; - dyn_dtree[Tree.DistanceCode(dist) * 2]++; + bl_tree[InternalConstants.REPZ_11_138 * 2]++; } - - if ((last_lit & 0x1fff) == 0 && (int)compressionLevel > 2) + count = 0; + prevlen = curlen; + if (nextlen == 0) { - // Compute an upper bound for the compressed length - int out_length = last_lit << 3; - int in_length = strstart - blockStart; - int dcode; - for (dcode = 0; dcode < InternalConstants.D_CODES; dcode++) - { - out_length = (int)( - out_length + dyn_dtree[dcode * 2] * (5L + ExtraDistanceBits[dcode]) - ); - } - out_length >>= 3; - if ((matches < (last_lit / 2)) && out_length < in_length / 2) - { - return true; - } + max_count = 138; + min_count = 3; } + else if (curlen == nextlen) + { + max_count = 6; + min_count = 3; + } + else + { + max_count = 7; + min_count = 4; + } + } + } - return (last_lit == lit_bufsize - 1) || (last_lit == lit_bufsize); + // Construct the Huffman tree for the bit lengths and return the index in + // bl_order of the last bit length code to send. + internal int BuildBlTree() + { + int max_blindex; // index of last bit length code of non zero freq - // dinoch - wraparound? - // We avoid equality with lit_bufsize because of wraparound at 64K - // on 16 bit machines and because stored blocks are restricted to - // 64K-1 bytes. + // Determine the bit length frequencies for literal and distance trees + ScanTree(dyn_ltree, treeLiterals.max_code); + ScanTree(dyn_dtree, treeDistances.max_code); + + // Build the bit length tree: + treeBitLengths.build_tree(this); + + // opt_len now includes the length of the tree representations, except + // the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + + // Determine the number of bit length codes to send. The pkzip format + // requires that at least 4 bit length codes be sent. (appnote.txt says + // 3 but the actual value used is 4.) + for (max_blindex = InternalConstants.BL_CODES - 1; max_blindex >= 3; max_blindex--) + { + if (bl_tree[(Tree.bl_order[max_blindex] * 2) + 1] != 0) + { + break; + } } - // Send the block data compressed using the given Huffman trees - internal void send_compressed_block(short[] ltree, short[] dtree) - { - int distance; // distance of matched string - int lc; // match length or unmatched char (if dist == 0) - int lx = 0; // running index in l_buf - int code; // the code to send - int extra; // number of extra bits to send + // Update opt_len to include the bit length tree and counts + opt_len += (3 * (max_blindex + 1)) + 5 + 5 + 4; - if (last_lit != 0) + return max_blindex; + } + + // Send the header for a block using dynamic Huffman trees: the counts, the + // lengths of the bit length codes, the literal tree and the distance tree. + // IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. + internal void send_all_trees(int lcodes, int dcodes, int blcodes) + { + int rank; // index in bl_order + + send_bits(lcodes - 257, 5); // not +255 as stated in appnote.txt + send_bits(dcodes - 1, 5); + send_bits(blcodes - 4, 4); // not -3 as stated in appnote.txt + for (rank = 0; rank < blcodes; rank++) + { + send_bits(bl_tree[(Tree.bl_order[rank] * 2) + 1], 3); + } + send_tree(dyn_ltree, lcodes - 1); // literal tree + send_tree(dyn_dtree, dcodes - 1); // distance tree + } + + // Send a literal or distance tree in compressed form, using the codes in + // bl_tree. + internal void send_tree(short[] tree, int max_code) + { + int n; // iterates over all tree elements + var prevlen = -1; // last emitted length + int curlen; // length of current code + int nextlen = tree[(0 * 2) + 1]; // length of next code + var count = 0; // repeat count of the current code + var max_count = 7; // max repeat count + var min_count = 4; // min repeat count + + if (nextlen == 0) + { + max_count = 138; + min_count = 3; + } + + for (n = 0; n <= max_code; n++) + { + curlen = nextlen; + nextlen = tree[((n + 1) * 2) + 1]; + if (++count < max_count && curlen == nextlen) + { + continue; + } + if (count < min_count) { do { - int ix = _distanceOffset + lx * 2; - distance = ((pending[ix] << 8) & 0xff00) | (pending[ix + 1] & 0xff); - lc = (pending[_lengthOffset + lx]) & 0xff; - lx++; - - if (distance == 0) - { - send_code(lc, ltree); // send a literal byte - } - else - { - // literal or match pair - // Here, lc is the match length - MIN_MATCH - code = Tree.LengthCode[lc]; - - // send the length code - send_code(code + InternalConstants.LITERALS + 1, ltree); - extra = ExtraLengthBits[code]; - if (extra != 0) - { - // send the extra length bits - lc -= Tree.LengthBase[code]; - send_bits(lc, extra); - } - distance--; // dist is now the match distance - 1 - code = Tree.DistanceCode(distance); - - // send the distance code - send_code(code, dtree); - - extra = ExtraDistanceBits[code]; - if (extra != 0) - { - // send the extra distance bits - distance -= Tree.DistanceBase[code]; - send_bits(distance, extra); - } - } - - // Check that the overlay between pending and d_buf+l_buf is ok: - } while (lx < last_lit); + send_code(curlen, bl_tree); + } while (--count != 0); } - - send_code(END_BLOCK, ltree); - last_eob_len = ltree[END_BLOCK * 2 + 1]; - } - - // Set the data type to ASCII or BINARY, using a crude approximation: - // binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise. - // IN assertion: the fields freq of dyn_ltree are set and the total of all - // frequencies does not exceed 64K (to fit in an int on 16 bit machines). - internal void set_data_type() - { - int n = 0; - int ascii_freq = 0; - int bin_freq = 0; - while (n < 7) + else if (curlen != 0) { - bin_freq += dyn_ltree[n * 2]; - n++; - } - while (n < 128) - { - ascii_freq += dyn_ltree[n * 2]; - n++; - } - while (n < InternalConstants.LITERALS) - { - bin_freq += dyn_ltree[n * 2]; - n++; - } - data_type = (sbyte)(bin_freq > (ascii_freq >> 2) ? Z_BINARY : Z_ASCII); - } - - // Flush the bit buffer, keeping at most 7 bits in it. - internal void bi_flush() - { - if (bi_valid == 16) - { - pending[pendingCount++] = (byte)bi_buf; - pending[pendingCount++] = (byte)(bi_buf >> 8); - bi_buf = 0; - bi_valid = 0; - } - else if (bi_valid >= 8) - { - //put_byte((byte)bi_buf); - pending[pendingCount++] = (byte)bi_buf; - bi_buf >>= 8; - bi_valid -= 8; - } - } - - // Flush the bit buffer and align the output on a byte boundary - internal void bi_windup() - { - if (bi_valid > 8) - { - pending[pendingCount++] = (byte)bi_buf; - pending[pendingCount++] = (byte)(bi_buf >> 8); - } - else if (bi_valid > 0) - { - //put_byte((byte)bi_buf); - pending[pendingCount++] = (byte)bi_buf; - } - bi_buf = 0; - bi_valid = 0; - } - - // Copy a stored block, storing first the length and its - // one's complement if requested. - internal void copy_block(int buf, int len, bool header) - { - bi_windup(); // align on byte boundary - last_eob_len = 8; // enough lookahead for inflate - - if (header) - { - unchecked + if (curlen != prevlen) { - //put_short((short)len); - pending[pendingCount++] = (byte)len; - pending[pendingCount++] = (byte)(len >> 8); - - //put_short((short)~len); - pending[pendingCount++] = (byte)~len; - pending[pendingCount++] = (byte)(~len >> 8); + send_code(curlen, bl_tree); + count--; } + send_code(InternalConstants.REP_3_6, bl_tree); + send_bits(count - 3, 2); } - - put_bytes(window, buf, len); - } - - internal void flush_block_only(bool eof) - { - _tr_flush_block(blockStart >= 0 ? blockStart : -1, strstart - blockStart, eof); - blockStart = strstart; - _codec.flush_pending(); - } - - // Copy without compression as much as possible from the input stream, return - // the current block state. - // This function does not insert new strings in the dictionary since - // uncompressible data is probably not useful. This function is used - // only for the level=0 compression option. - // NOTE: this function should be optimized to avoid extra copying from - // window to pending_buf. - internal BlockState DeflateNone(FlushType flush) - { - // Stored blocks are limited to 0xffff bytes, pending is limited - // to pending_buf_size, and each stored block has a 5 byte header: - - int max_block_size = 0xffff; - int max_start; - - if (max_block_size > pending.Length - 5) + else if (count <= 10) { - max_block_size = pending.Length - 5; - } - - // Copy as much as possible from input to output: - while (true) - { - // Fill the window as much as possible: - if (lookahead <= 1) - { - _fillWindow(); - if (lookahead == 0 && flush == FlushType.None) - { - return BlockState.NeedMore; - } - if (lookahead == 0) - { - break; // flush the current block - } - } - - strstart += lookahead; - lookahead = 0; - - // Emit a stored block if pending will be full: - max_start = blockStart + max_block_size; - if (strstart == 0 || strstart >= max_start) - { - // strstart == 0 is possible when wraparound on 16-bit machine - lookahead = strstart - max_start; - strstart = max_start; - - flush_block_only(false); - if (_codec.AvailableBytesOut == 0) - { - return BlockState.NeedMore; - } - } - - // Flush if we may have to slide, otherwise block_start may become - // negative and the data will be gone: - if (strstart - blockStart >= w_size - MIN_LOOKAHEAD) - { - flush_block_only(false); - if (_codec.AvailableBytesOut == 0) - { - return BlockState.NeedMore; - } - } - } - - flush_block_only(flush == FlushType.Finish); - if (_codec.AvailableBytesOut == 0) - { - return (flush == FlushType.Finish) ? BlockState.FinishStarted : BlockState.NeedMore; - } - - return flush == FlushType.Finish ? BlockState.FinishDone : BlockState.BlockDone; - } - - // Send a stored block - internal void _tr_stored_block(int buf, int stored_len, bool eof) - { - send_bits((STORED_BLOCK << 1) + (eof ? 1 : 0), 3); // send block type - copy_block(buf, stored_len, true); // with header - } - - // Determine the best encoding for the current block: dynamic trees, static - // trees or store, and output the encoded block to the zip file. - internal void _tr_flush_block(int buf, int stored_len, bool eof) - { - int opt_lenb, - static_lenb; // opt_len and static_len in bytes - int max_blindex = 0; // index of last bit length code of non zero freq - - // Build the Huffman trees unless a stored block is forced - if (compressionLevel > 0) - { - // Check if the file is ascii or binary - if (data_type == Z_UNKNOWN) - { - set_data_type(); - } - - // Construct the literal and distance trees - treeLiterals.build_tree(this); - - treeDistances.build_tree(this); - - // At this point, opt_len and static_len are the total bit lengths of - // the compressed block data, excluding the tree representations. - - // Build the bit length tree for the above two trees, and get the index - // in bl_order of the last bit length code to send. - max_blindex = BuildBlTree(); - - // Determine the best encoding. Compute first the block length in bytes - opt_lenb = (opt_len + 3 + 7) >> 3; - static_lenb = (static_len + 3 + 7) >> 3; - - if (static_lenb <= opt_lenb) - { - opt_lenb = static_lenb; - } + send_code(InternalConstants.REPZ_3_10, bl_tree); + send_bits(count - 3, 3); } else { - opt_lenb = static_lenb = stored_len + 5; // force a stored block + send_code(InternalConstants.REPZ_11_138, bl_tree); + send_bits(count - 11, 7); } - - if (stored_len + 4 <= opt_lenb && buf != -1) + count = 0; + prevlen = curlen; + if (nextlen == 0) { - // 4: two words for the lengths - // The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. - // Otherwise we can't have processed more than WSIZE input bytes since - // the last block flush, because compression would have been - // successful. If LIT_BUFSIZE <= WSIZE, it is never too late to - // transform a block into a stored block. - _tr_stored_block(buf, stored_len, eof); + max_count = 138; + min_count = 3; } - else if (static_lenb == opt_lenb) + else if (curlen == nextlen) { - send_bits((STATIC_TREES << 1) + (eof ? 1 : 0), 3); - send_compressed_block( - StaticTree.lengthAndLiteralsTreeCodes, - StaticTree.distTreeCodes - ); + max_count = 6; + min_count = 3; } else { - send_bits((DYN_TREES << 1) + (eof ? 1 : 0), 3); - send_all_trees( - treeLiterals.max_code + 1, - treeDistances.max_code + 1, - max_blindex + 1 - ); - send_compressed_block(dyn_ltree, dyn_dtree); + max_count = 7; + min_count = 4; } + } + } - // The above check is made mod 2^32, for files larger than 512 MB - // and uLong implemented on 32 bits. + // Output a block of bytes on the stream. + // IN assertion: there is enough room in pending_buf. + private void put_bytes(byte[] p, int start, int len) + { + Array.Copy(p, start, pending, pendingCount, len); + pendingCount += len; + } - _InitializeBlocks(); +#if NOTNEEDED + private void put_byte(byte c) + { + pending[pendingCount++] = c; + } - if (eof) + internal void put_short(int b) + { + unchecked + { + pending[pendingCount++] = (byte)b; + pending[pendingCount++] = (byte)(b >> 8); + } + } + + internal void putShortMSB(int b) + { + unchecked + { + pending[pendingCount++] = (byte)(b >> 8); + pending[pendingCount++] = (byte)b; + } + } +#endif + + internal void send_code(int c, short[] tree) + { + var c2 = c * 2; + send_bits((tree[c2] & 0xffff), (tree[c2 + 1] & 0xffff)); + } + +#pragma warning disable 675 // workaround for Visual Studio 2015 compiler bug: https://github.com/dotnet/roslyn/issues/4027 + internal void send_bits(int value, int length) + { + var len = length; + unchecked + { + if (bi_valid > Buf_size - len) { - bi_windup(); + //int val = value; + // bi_buf |= (val << bi_valid); + + bi_buf |= (short)((value << bi_valid) & 0xffff); + + //put_short(bi_buf); + pending[pendingCount++] = (byte)bi_buf; + pending[pendingCount++] = (byte)(bi_buf >> 8); + + bi_buf = (short)((uint)value >> (Buf_size - bi_valid)); + bi_valid += len - Buf_size; + } + else + { + // bi_buf |= (value) << bi_valid; + bi_buf |= (short)((value << bi_valid) & 0xffff); + bi_valid += len; + } + } + } +#pragma warning restore 675 + + // Send one empty static block to give enough lookahead for inflate. + // This takes 10 bits, of which 7 may remain in the bit buffer. + // The current inflate code requires 9 bits of lookahead. If the + // last two codes for the previous block (real code plus EOB) were coded + // on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode + // the last real code. In this case we send two empty static blocks instead + // of one. (There are no problems if the previous block is stored or fixed.) + // To simplify the code, we assume the worst case of last real code encoded + // on one bit only. + internal void _tr_align() + { + send_bits(STATIC_TREES << 1, 3); + send_code(END_BLOCK, StaticTree.lengthAndLiteralsTreeCodes); + + bi_flush(); + + // Of the 10 bits for the empty block, we have already sent + // (10 - bi_valid) bits. The lookahead for the last real code (before + // the EOB of the previous block) was thus at least one plus the length + // of the EOB plus what we have just sent of the empty static block. + if (1 + last_eob_len + 10 - bi_valid < 9) + { + send_bits(STATIC_TREES << 1, 3); + send_code(END_BLOCK, StaticTree.lengthAndLiteralsTreeCodes); + bi_flush(); + } + last_eob_len = 7; + } + + // Save the match info and tally the frequency counts. Return true if + // the current block must be flushed. + internal bool _tr_tally(int dist, int lc) + { + pending[_distanceOffset + (last_lit * 2)] = unchecked((byte)((uint)dist >> 8)); + pending[_distanceOffset + (last_lit * 2) + 1] = unchecked((byte)dist); + pending[_lengthOffset + last_lit] = unchecked((byte)lc); + last_lit++; + + if (dist == 0) + { + // lc is the unmatched char + dyn_ltree[lc * 2]++; + } + else + { + matches++; + + // Here, lc is the match length - MIN_MATCH + dist--; // dist = match distance - 1 + dyn_ltree[(Tree.LengthCode[lc] + InternalConstants.LITERALS + 1) * 2]++; + dyn_dtree[Tree.DistanceCode(dist) * 2]++; + } + + if ((last_lit & 0x1fff) == 0 && (int)compressionLevel > 2) + { + // Compute an upper bound for the compressed length + var out_length = last_lit << 3; + var in_length = strstart - blockStart; + int dcode; + for (dcode = 0; dcode < InternalConstants.D_CODES; dcode++) + { + out_length = (int)( + out_length + (dyn_dtree[dcode * 2] * (5L + ExtraDistanceBits[dcode])) + ); + } + out_length >>= 3; + if ((matches < (last_lit / 2)) && out_length < in_length / 2) + { + return true; } } - // Fill the window when the lookahead becomes insufficient. - // Updates strstart and lookahead. - // - // IN assertion: lookahead < MIN_LOOKAHEAD - // OUT assertions: strstart <= window_size-MIN_LOOKAHEAD - // At least one byte has been read, or avail_in == 0; reads are - // performed for at least two bytes (required for the zip translate_eol - // option -- not supported here). - private void _fillWindow() - { - int n, - m; - int p; - int more; // Amount of free space at the end of the window. + return (last_lit == lit_bufsize - 1) || (last_lit == lit_bufsize); + // dinoch - wraparound? + // We avoid equality with lit_bufsize because of wraparound at 64K + // on 16 bit machines and because stored blocks are restricted to + // 64K-1 bytes. + } + + // Send the block data compressed using the given Huffman trees + internal void send_compressed_block(short[] ltree, short[] dtree) + { + int distance; // distance of matched string + int lc; // match length or unmatched char (if dist == 0) + var lx = 0; // running index in l_buf + int code; // the code to send + int extra; // number of extra bits to send + + if (last_lit != 0) + { do { - more = (window_size - lookahead - strstart); + var ix = _distanceOffset + (lx * 2); + distance = ((pending[ix] << 8) & 0xff00) | (pending[ix + 1] & 0xff); + lc = (pending[_lengthOffset + lx]) & 0xff; + lx++; - // Deal with !@#$% 64K limit: - if (more == 0 && strstart == 0 && lookahead == 0) + if (distance == 0) { - more = w_size; - } - else if (more == -1) - { - // Very unlikely, but possible on 16 bit machine if strstart == 0 - // and lookahead == 1 (input done one byte at time) - more--; - - // If the window is almost full and there is insufficient lookahead, - // move the upper half to the lower one to make room in the upper half. - } - else if (strstart >= w_size + w_size - MIN_LOOKAHEAD) - { - Array.Copy(window, w_size, window, 0, w_size); - match_start -= w_size; - strstart -= w_size; // we now have strstart >= MAX_DIST - blockStart -= w_size; - - // Slide the hash table (could be avoided with 32 bit values - // at the expense of memory usage). We slide even when level == 0 - // to keep the hash table consistent if we switch back to level > 0 - // later. (Using level 0 permanently is not an optimal usage of - // zlib, so we don't care about this pathological case.) - - n = hash_size; - p = n; - do - { - m = (head[--p] & 0xffff); - head[p] = (short)((m >= w_size) ? (m - w_size) : 0); - } while (--n != 0); - - n = w_size; - p = n; - do - { - m = (prev[--p] & 0xffff); - prev[p] = (short)((m >= w_size) ? (m - w_size) : 0); - - // If n is not on any hash chain, prev[n] is garbage but - // its value will never be used. - } while (--n != 0); - more += w_size; - } - - if (_codec.AvailableBytesIn == 0) - { - return; - } - - // If there was no sliding: - // strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && - // more == window_size - lookahead - strstart - // => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) - // => more >= window_size - 2*WSIZE + 2 - // In the BIG_MEM or MMAP case (not yet supported), - // window_size == input_size + MIN_LOOKAHEAD && - // strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. - // Otherwise, window_size == 2*WSIZE so more >= 2. - // If there was sliding, more >= WSIZE. So in all cases, more >= 2. - - n = _codec.read_buf(window, strstart + lookahead, more); - lookahead += n; - - // Initialize the hash value now that we have some input: - if (lookahead >= MIN_MATCH) - { - ins_h = window[strstart] & 0xff; - ins_h = (((ins_h) << hash_shift) ^ (window[strstart + 1] & 0xff)) & hash_mask; - } - - // If the whole input has less than MIN_MATCH bytes, ins_h is garbage, - // but this is not important since only literal bytes will be emitted. - } while (lookahead < MIN_LOOKAHEAD && _codec.AvailableBytesIn != 0); - } - - // Compress as much as possible from the input stream, return the current - // block state. - // This function does not perform lazy evaluation of matches and inserts - // new strings in the dictionary only for unmatched strings or for short - // matches. It is used only for the fast compression options. - internal BlockState DeflateFast(FlushType flush) - { - // short hash_head = 0; // head of the hash chain - int hash_head = 0; // head of the hash chain - bool bflush; // set if current block must be flushed - - while (true) - { - // Make sure that we always have enough lookahead, except - // at the end of the input file. We need MAX_MATCH bytes - // for the next match, plus MIN_MATCH bytes to insert the - // string following the next match. - if (lookahead < MIN_LOOKAHEAD) - { - _fillWindow(); - if (lookahead < MIN_LOOKAHEAD && flush == FlushType.None) - { - return BlockState.NeedMore; - } - if (lookahead == 0) - { - break; // flush the current block - } - } - - // Insert the string window[strstart .. strstart+2] in the - // dictionary, and set hash_head to the head of the hash chain: - if (lookahead >= MIN_MATCH) - { - ins_h = - (((ins_h) << hash_shift) ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff)) - & hash_mask; - - // prev[strstart&w_mask]=hash_head=head[ins_h]; - hash_head = (head[ins_h] & 0xffff); - prev[strstart & w_mask] = head[ins_h]; - head[ins_h] = unchecked((short)strstart); - } - - // Find the longest match, discarding those <= prev_length. - // At this point we have always match_length < MIN_MATCH - - if (hash_head != 0L && ((strstart - hash_head) & 0xffff) <= w_size - MIN_LOOKAHEAD) - { - // To simplify the code, we prevent matches with the string - // of window index 0 (in particular we have to avoid a match - // of the string with itself at the start of the input file). - if (compressionStrategy != CompressionStrategy.HuffmanOnly) - { - match_length = longest_match(hash_head); - } - - // longest_match() sets match_start - } - if (match_length >= MIN_MATCH) - { - // check_match(strstart, match_start, match_length); - - bflush = _tr_tally(strstart - match_start, match_length - MIN_MATCH); - - lookahead -= match_length; - - // Insert new strings in the hash table only if the match length - // is not too large. This saves time but degrades compression. - if (match_length <= config.MaxLazy && lookahead >= MIN_MATCH) - { - match_length--; // string at strstart already in hash table - do - { - strstart++; - - ins_h = - ( - (ins_h << hash_shift) - ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff) - ) & hash_mask; - - // prev[strstart&w_mask]=hash_head=head[ins_h]; - hash_head = (head[ins_h] & 0xffff); - prev[strstart & w_mask] = head[ins_h]; - head[ins_h] = unchecked((short)strstart); - - // strstart never exceeds WSIZE-MAX_MATCH, so there are - // always MIN_MATCH bytes ahead. - } while (--match_length != 0); - strstart++; - } - else - { - strstart += match_length; - match_length = 0; - ins_h = window[strstart] & 0xff; - - ins_h = - (((ins_h) << hash_shift) ^ (window[strstart + 1] & 0xff)) & hash_mask; - - // If lookahead < MIN_MATCH, ins_h is garbage, but it does not - // matter since it will be recomputed at next deflate call. - } + send_code(lc, ltree); // send a literal byte } else { - // No match, output a literal byte + // literal or match pair + // Here, lc is the match length - MIN_MATCH + code = Tree.LengthCode[lc]; - bflush = _tr_tally(0, window[strstart] & 0xff); - lookahead--; + // send the length code + send_code(code + InternalConstants.LITERALS + 1, ltree); + extra = ExtraLengthBits[code]; + if (extra != 0) + { + // send the extra length bits + lc -= Tree.LengthBase[code]; + send_bits(lc, extra); + } + distance--; // dist is now the match distance - 1 + code = Tree.DistanceCode(distance); + + // send the distance code + send_code(code, dtree); + + extra = ExtraDistanceBits[code]; + if (extra != 0) + { + // send the extra distance bits + distance -= Tree.DistanceBase[code]; + send_bits(distance, extra); + } + } + + // Check that the overlay between pending and d_buf+l_buf is ok: + } while (lx < last_lit); + } + + send_code(END_BLOCK, ltree); + last_eob_len = ltree[(END_BLOCK * 2) + 1]; + } + + // Set the data type to ASCII or BINARY, using a crude approximation: + // binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise. + // IN assertion: the fields freq of dyn_ltree are set and the total of all + // frequencies does not exceed 64K (to fit in an int on 16 bit machines). + internal void set_data_type() + { + var n = 0; + var ascii_freq = 0; + var bin_freq = 0; + while (n < 7) + { + bin_freq += dyn_ltree[n * 2]; + n++; + } + while (n < 128) + { + ascii_freq += dyn_ltree[n * 2]; + n++; + } + while (n < InternalConstants.LITERALS) + { + bin_freq += dyn_ltree[n * 2]; + n++; + } + data_type = (sbyte)(bin_freq > (ascii_freq >> 2) ? Z_BINARY : Z_ASCII); + } + + // Flush the bit buffer, keeping at most 7 bits in it. + internal void bi_flush() + { + if (bi_valid == 16) + { + pending[pendingCount++] = (byte)bi_buf; + pending[pendingCount++] = (byte)(bi_buf >> 8); + bi_buf = 0; + bi_valid = 0; + } + else if (bi_valid >= 8) + { + //put_byte((byte)bi_buf); + pending[pendingCount++] = (byte)bi_buf; + bi_buf >>= 8; + bi_valid -= 8; + } + } + + // Flush the bit buffer and align the output on a byte boundary + internal void bi_windup() + { + if (bi_valid > 8) + { + pending[pendingCount++] = (byte)bi_buf; + pending[pendingCount++] = (byte)(bi_buf >> 8); + } + else if (bi_valid > 0) + { + //put_byte((byte)bi_buf); + pending[pendingCount++] = (byte)bi_buf; + } + bi_buf = 0; + bi_valid = 0; + } + + // Copy a stored block, storing first the length and its + // one's complement if requested. + internal void copy_block(int buf, int len, bool header) + { + bi_windup(); // align on byte boundary + last_eob_len = 8; // enough lookahead for inflate + + if (header) + { + unchecked + { + //put_short((short)len); + pending[pendingCount++] = (byte)len; + pending[pendingCount++] = (byte)(len >> 8); + + //put_short((short)~len); + pending[pendingCount++] = (byte)~len; + pending[pendingCount++] = (byte)(~len >> 8); + } + } + + put_bytes(window, buf, len); + } + + internal void flush_block_only(bool eof) + { + _tr_flush_block(blockStart >= 0 ? blockStart : -1, strstart - blockStart, eof); + blockStart = strstart; + _codec.flush_pending(); + } + + // Copy without compression as much as possible from the input stream, return + // the current block state. + // This function does not insert new strings in the dictionary since + // uncompressible data is probably not useful. This function is used + // only for the level=0 compression option. + // NOTE: this function should be optimized to avoid extra copying from + // window to pending_buf. + internal BlockState DeflateNone(FlushType flush) + { + // Stored blocks are limited to 0xffff bytes, pending is limited + // to pending_buf_size, and each stored block has a 5 byte header: + + var max_block_size = 0xffff; + int max_start; + + if (max_block_size > pending.Length - 5) + { + max_block_size = pending.Length - 5; + } + + // Copy as much as possible from input to output: + while (true) + { + // Fill the window as much as possible: + if (lookahead <= 1) + { + _fillWindow(); + if (lookahead == 0 && flush == FlushType.None) + { + return BlockState.NeedMore; + } + if (lookahead == 0) + { + break; // flush the current block + } + } + + strstart += lookahead; + lookahead = 0; + + // Emit a stored block if pending will be full: + max_start = blockStart + max_block_size; + if (strstart == 0 || strstart >= max_start) + { + // strstart == 0 is possible when wraparound on 16-bit machine + lookahead = strstart - max_start; + strstart = max_start; + + flush_block_only(false); + if (_codec.AvailableBytesOut == 0) + { + return BlockState.NeedMore; + } + } + + // Flush if we may have to slide, otherwise block_start may become + // negative and the data will be gone: + if (strstart - blockStart >= w_size - MIN_LOOKAHEAD) + { + flush_block_only(false); + if (_codec.AvailableBytesOut == 0) + { + return BlockState.NeedMore; + } + } + } + + flush_block_only(flush == FlushType.Finish); + if (_codec.AvailableBytesOut == 0) + { + return (flush == FlushType.Finish) ? BlockState.FinishStarted : BlockState.NeedMore; + } + + return flush == FlushType.Finish ? BlockState.FinishDone : BlockState.BlockDone; + } + + // Send a stored block + internal void _tr_stored_block(int buf, int stored_len, bool eof) + { + send_bits((STORED_BLOCK << 1) + (eof ? 1 : 0), 3); // send block type + copy_block(buf, stored_len, true); // with header + } + + // Determine the best encoding for the current block: dynamic trees, static + // trees or store, and output the encoded block to the zip file. + internal void _tr_flush_block(int buf, int stored_len, bool eof) + { + int opt_lenb, + static_lenb; // opt_len and static_len in bytes + var max_blindex = 0; // index of last bit length code of non zero freq + + // Build the Huffman trees unless a stored block is forced + if (compressionLevel > 0) + { + // Check if the file is ascii or binary + if (data_type == Z_UNKNOWN) + { + set_data_type(); + } + + // Construct the literal and distance trees + treeLiterals.build_tree(this); + + treeDistances.build_tree(this); + + // At this point, opt_len and static_len are the total bit lengths of + // the compressed block data, excluding the tree representations. + + // Build the bit length tree for the above two trees, and get the index + // in bl_order of the last bit length code to send. + max_blindex = BuildBlTree(); + + // Determine the best encoding. Compute first the block length in bytes + opt_lenb = (opt_len + 3 + 7) >> 3; + static_lenb = (static_len + 3 + 7) >> 3; + + if (static_lenb <= opt_lenb) + { + opt_lenb = static_lenb; + } + } + else + { + opt_lenb = static_lenb = stored_len + 5; // force a stored block + } + + if (stored_len + 4 <= opt_lenb && buf != -1) + { + // 4: two words for the lengths + // The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + // Otherwise we can't have processed more than WSIZE input bytes since + // the last block flush, because compression would have been + // successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + // transform a block into a stored block. + _tr_stored_block(buf, stored_len, eof); + } + else if (static_lenb == opt_lenb) + { + send_bits((STATIC_TREES << 1) + (eof ? 1 : 0), 3); + send_compressed_block( + StaticTree.lengthAndLiteralsTreeCodes, + StaticTree.distTreeCodes + ); + } + else + { + send_bits((DYN_TREES << 1) + (eof ? 1 : 0), 3); + send_all_trees( + treeLiterals.max_code + 1, + treeDistances.max_code + 1, + max_blindex + 1 + ); + send_compressed_block(dyn_ltree, dyn_dtree); + } + + // The above check is made mod 2^32, for files larger than 512 MB + // and uLong implemented on 32 bits. + + _InitializeBlocks(); + + if (eof) + { + bi_windup(); + } + } + + // Fill the window when the lookahead becomes insufficient. + // Updates strstart and lookahead. + // + // IN assertion: lookahead < MIN_LOOKAHEAD + // OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + // At least one byte has been read, or avail_in == 0; reads are + // performed for at least two bytes (required for the zip translate_eol + // option -- not supported here). + private void _fillWindow() + { + int n, + m; + int p; + int more; // Amount of free space at the end of the window. + + do + { + more = (window_size - lookahead - strstart); + + // Deal with !@#$% 64K limit: + if (more == 0 && strstart == 0 && lookahead == 0) + { + more = w_size; + } + else if (more == -1) + { + // Very unlikely, but possible on 16 bit machine if strstart == 0 + // and lookahead == 1 (input done one byte at time) + more--; + + // If the window is almost full and there is insufficient lookahead, + // move the upper half to the lower one to make room in the upper half. + } + else if (strstart >= w_size + w_size - MIN_LOOKAHEAD) + { + Array.Copy(window, w_size, window, 0, w_size); + match_start -= w_size; + strstart -= w_size; // we now have strstart >= MAX_DIST + blockStart -= w_size; + + // Slide the hash table (could be avoided with 32 bit values + // at the expense of memory usage). We slide even when level == 0 + // to keep the hash table consistent if we switch back to level > 0 + // later. (Using level 0 permanently is not an optimal usage of + // zlib, so we don't care about this pathological case.) + + n = hash_size; + p = n; + do + { + m = (head[--p] & 0xffff); + head[p] = (short)((m >= w_size) ? (m - w_size) : 0); + } while (--n != 0); + + n = w_size; + p = n; + do + { + m = (prev[--p] & 0xffff); + prev[p] = (short)((m >= w_size) ? (m - w_size) : 0); + + // If n is not on any hash chain, prev[n] is garbage but + // its value will never be used. + } while (--n != 0); + more += w_size; + } + + if (_codec.AvailableBytesIn == 0) + { + return; + } + + // If there was no sliding: + // strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + // more == window_size - lookahead - strstart + // => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + // => more >= window_size - 2*WSIZE + 2 + // In the BIG_MEM or MMAP case (not yet supported), + // window_size == input_size + MIN_LOOKAHEAD && + // strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + // Otherwise, window_size == 2*WSIZE so more >= 2. + // If there was sliding, more >= WSIZE. So in all cases, more >= 2. + + n = _codec.read_buf(window, strstart + lookahead, more); + lookahead += n; + + // Initialize the hash value now that we have some input: + if (lookahead >= MIN_MATCH) + { + ins_h = window[strstart] & 0xff; + ins_h = (((ins_h) << hash_shift) ^ (window[strstart + 1] & 0xff)) & hash_mask; + } + + // If the whole input has less than MIN_MATCH bytes, ins_h is garbage, + // but this is not important since only literal bytes will be emitted. + } while (lookahead < MIN_LOOKAHEAD && _codec.AvailableBytesIn != 0); + } + + // Compress as much as possible from the input stream, return the current + // block state. + // This function does not perform lazy evaluation of matches and inserts + // new strings in the dictionary only for unmatched strings or for short + // matches. It is used only for the fast compression options. + internal BlockState DeflateFast(FlushType flush) + { + // short hash_head = 0; // head of the hash chain + var hash_head = 0; // head of the hash chain + bool bflush; // set if current block must be flushed + + while (true) + { + // Make sure that we always have enough lookahead, except + // at the end of the input file. We need MAX_MATCH bytes + // for the next match, plus MIN_MATCH bytes to insert the + // string following the next match. + if (lookahead < MIN_LOOKAHEAD) + { + _fillWindow(); + if (lookahead < MIN_LOOKAHEAD && flush == FlushType.None) + { + return BlockState.NeedMore; + } + if (lookahead == 0) + { + break; // flush the current block + } + } + + // Insert the string window[strstart .. strstart+2] in the + // dictionary, and set hash_head to the head of the hash chain: + if (lookahead >= MIN_MATCH) + { + ins_h = + (((ins_h) << hash_shift) ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff)) + & hash_mask; + + // prev[strstart&w_mask]=hash_head=head[ins_h]; + hash_head = (head[ins_h] & 0xffff); + prev[strstart & w_mask] = head[ins_h]; + head[ins_h] = unchecked((short)strstart); + } + + // Find the longest match, discarding those <= prev_length. + // At this point we have always match_length < MIN_MATCH + + if (hash_head != 0L && ((strstart - hash_head) & 0xffff) <= w_size - MIN_LOOKAHEAD) + { + // To simplify the code, we prevent matches with the string + // of window index 0 (in particular we have to avoid a match + // of the string with itself at the start of the input file). + if (compressionStrategy != CompressionStrategy.HuffmanOnly) + { + match_length = longest_match(hash_head); + } + + // longest_match() sets match_start + } + if (match_length >= MIN_MATCH) + { + // check_match(strstart, match_start, match_length); + + bflush = _tr_tally(strstart - match_start, match_length - MIN_MATCH); + + lookahead -= match_length; + + // Insert new strings in the hash table only if the match length + // is not too large. This saves time but degrades compression. + if (match_length <= config.MaxLazy && lookahead >= MIN_MATCH) + { + match_length--; // string at strstart already in hash table + do + { + strstart++; + + ins_h = + ( + (ins_h << hash_shift) + ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff) + ) & hash_mask; + + // prev[strstart&w_mask]=hash_head=head[ins_h]; + hash_head = (head[ins_h] & 0xffff); + prev[strstart & w_mask] = head[ins_h]; + head[ins_h] = unchecked((short)strstart); + + // strstart never exceeds WSIZE-MAX_MATCH, so there are + // always MIN_MATCH bytes ahead. + } while (--match_length != 0); strstart++; } + else + { + strstart += match_length; + match_length = 0; + ins_h = window[strstart] & 0xff; + + ins_h = + (((ins_h) << hash_shift) ^ (window[strstart + 1] & 0xff)) & hash_mask; + + // If lookahead < MIN_MATCH, ins_h is garbage, but it does not + // matter since it will be recomputed at next deflate call. + } + } + else + { + // No match, output a literal byte + + bflush = _tr_tally(0, window[strstart] & 0xff); + lookahead--; + strstart++; + } + if (bflush) + { + flush_block_only(false); + if (_codec.AvailableBytesOut == 0) + { + return BlockState.NeedMore; + } + } + } + + flush_block_only(flush == FlushType.Finish); + if (_codec.AvailableBytesOut == 0) + { + if (flush == FlushType.Finish) + { + return BlockState.FinishStarted; + } + return BlockState.NeedMore; + } + return flush == FlushType.Finish ? BlockState.FinishDone : BlockState.BlockDone; + } + + // Same as above, but achieves better compression. We use a lazy + // evaluation for matches: a match is finally adopted only if there is + // no better match at the next window position. + internal BlockState DeflateSlow(FlushType flush) + { + // short hash_head = 0; // head of hash chain + var hash_head = 0; // head of hash chain + bool bflush; // set if current block must be flushed + + // Process the input block. + while (true) + { + // Make sure that we always have enough lookahead, except + // at the end of the input file. We need MAX_MATCH bytes + // for the next match, plus MIN_MATCH bytes to insert the + // string following the next match. + + if (lookahead < MIN_LOOKAHEAD) + { + _fillWindow(); + if (lookahead < MIN_LOOKAHEAD && flush == FlushType.None) + { + return BlockState.NeedMore; + } + + if (lookahead == 0) + { + break; // flush the current block + } + } + + // Insert the string window[strstart .. strstart+2] in the + // dictionary, and set hash_head to the head of the hash chain: + + if (lookahead >= MIN_MATCH) + { + ins_h = + (((ins_h) << hash_shift) ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff)) + & hash_mask; + + // prev[strstart&w_mask]=hash_head=head[ins_h]; + hash_head = (head[ins_h] & 0xffff); + prev[strstart & w_mask] = head[ins_h]; + head[ins_h] = unchecked((short)strstart); + } + + // Find the longest match, discarding those <= prev_length. + prev_length = match_length; + prev_match = match_start; + match_length = MIN_MATCH - 1; + + if ( + hash_head != 0 + && prev_length < config.MaxLazy + && ((strstart - hash_head) & 0xffff) <= w_size - MIN_LOOKAHEAD + ) + { + // To simplify the code, we prevent matches with the string + // of window index 0 (in particular we have to avoid a match + // of the string with itself at the start of the input file). + + if (compressionStrategy != CompressionStrategy.HuffmanOnly) + { + match_length = longest_match(hash_head); + } + + // longest_match() sets match_start + + if ( + match_length <= 5 + && ( + compressionStrategy == CompressionStrategy.Filtered + || (match_length == MIN_MATCH && strstart - match_start > 4096) + ) + ) + { + // If prev_match is also MIN_MATCH, match_start is garbage + // but we will ignore the current match anyway. + match_length = MIN_MATCH - 1; + } + } + + // If there was a match at the previous step and the current + // match is not better, output the previous match: + if (prev_length >= MIN_MATCH && match_length <= prev_length) + { + var max_insert = strstart + lookahead - MIN_MATCH; + + // Do not insert strings in hash table beyond this. + + // check_match(strstart-1, prev_match, prev_length); + + bflush = _tr_tally(strstart - 1 - prev_match, prev_length - MIN_MATCH); + + // Insert in hash table all strings up to the end of the match. + // strstart-1 and strstart are already inserted. If there is not + // enough lookahead, the last two strings are not inserted in + // the hash table. + lookahead -= (prev_length - 1); + prev_length -= 2; + do + { + if (++strstart <= max_insert) + { + ins_h = + ( + ((ins_h) << hash_shift) + ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff) + ) & hash_mask; + + //prev[strstart&w_mask]=hash_head=head[ins_h]; + hash_head = (head[ins_h] & 0xffff); + prev[strstart & w_mask] = head[ins_h]; + head[ins_h] = unchecked((short)strstart); + } + } while (--prev_length != 0); + match_available = 0; + match_length = MIN_MATCH - 1; + strstart++; + if (bflush) { flush_block_only(false); @@ -1397,707 +1539,565 @@ namespace SharpCompress.Compressors.Deflate } } } - - flush_block_only(flush == FlushType.Finish); - if (_codec.AvailableBytesOut == 0) + else if (match_available != 0) { - if (flush == FlushType.Finish) + // If there was no match at the previous position, output a + // single literal. If there was a match but the current match + // is longer, truncate the previous match to a single literal. + + bflush = _tr_tally(0, window[strstart - 1] & 0xff); + + if (bflush) { - return BlockState.FinishStarted; + flush_block_only(false); + } + strstart++; + lookahead--; + if (_codec.AvailableBytesOut == 0) + { + return BlockState.NeedMore; } - return BlockState.NeedMore; } - return flush == FlushType.Finish ? BlockState.FinishDone : BlockState.BlockDone; + else + { + // There is no previous match to compare with, wait for + // the next step to decide. + + match_available = 1; + strstart++; + lookahead--; + } } - // Same as above, but achieves better compression. We use a lazy - // evaluation for matches: a match is finally adopted only if there is - // no better match at the next window position. - internal BlockState DeflateSlow(FlushType flush) + if (match_available != 0) { - // short hash_head = 0; // head of hash chain - int hash_head = 0; // head of hash chain - bool bflush; // set if current block must be flushed + bflush = _tr_tally(0, window[strstart - 1] & 0xff); + match_available = 0; + } + flush_block_only(flush == FlushType.Finish); - // Process the input block. - while (true) + if (_codec.AvailableBytesOut == 0) + { + if (flush == FlushType.Finish) { - // Make sure that we always have enough lookahead, except - // at the end of the input file. We need MAX_MATCH bytes - // for the next match, plus MIN_MATCH bytes to insert the - // string following the next match. + return BlockState.FinishStarted; + } + return BlockState.NeedMore; + } - if (lookahead < MIN_LOOKAHEAD) + return flush == FlushType.Finish ? BlockState.FinishDone : BlockState.BlockDone; + } + + internal int longest_match(int cur_match) + { + var chain_length = config.MaxChainLength; // max hash chain length + var scan = strstart; // current string + int match; // matched string + int len; // length of current match + var best_len = prev_length; // best match length so far + var limit = + strstart > (w_size - MIN_LOOKAHEAD) ? strstart - (w_size - MIN_LOOKAHEAD) : 0; + + var niceLength = config.NiceLength; + + // Stop when cur_match becomes <= limit. To simplify the code, + // we prevent matches with the string of window index 0. + + var wmask = w_mask; + + var strend = strstart + MAX_MATCH; + var scan_end1 = window[scan + best_len - 1]; + var scan_end = window[scan + best_len]; + + // The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + // It is easy to get rid of this optimization if necessary. + + // Do not waste too much time if we already have a good match: + if (prev_length >= config.GoodLength) + { + chain_length >>= 2; + } + + // Do not look for matches beyond the end of the input. This is necessary + // to make deflate deterministic. + if (niceLength > lookahead) + { + niceLength = lookahead; + } + + do + { + match = cur_match; + + // Skip to next match if the match length cannot increase + // or if the match length is less than 2: + if ( + window[match + best_len] != scan_end + || window[match + best_len - 1] != scan_end1 + || window[match] != window[scan] + || window[++match] != window[scan + 1] + ) + { + continue; + } + + // The check at best_len-1 can be removed because it will be made + // again later. (This heuristic is not always a win.) + // It is not necessary to compare scan[2] and match[2] since they + // are always equal when the other bytes match, given that + // the hash keys are equal and that HASH_BITS >= 8. + scan += 2; + match++; + + // We check for insufficient lookahead only every 8th comparison; + // the 256th check will be made at strstart+258. + do + { } while ( + window[++scan] == window[++match] + && window[++scan] == window[++match] + && window[++scan] == window[++match] + && window[++scan] == window[++match] + && window[++scan] == window[++match] + && window[++scan] == window[++match] + && window[++scan] == window[++match] + && window[++scan] == window[++match] + && scan < strend + ); + + len = MAX_MATCH - (strend - scan); + scan = strend - MAX_MATCH; + + if (len > best_len) + { + match_start = cur_match; + best_len = len; + if (len >= niceLength) { - _fillWindow(); - if (lookahead < MIN_LOOKAHEAD && flush == FlushType.None) - { - return BlockState.NeedMore; - } - - if (lookahead == 0) - { - break; // flush the current block - } + break; } + scan_end1 = window[scan + best_len - 1]; + scan_end = window[scan + best_len]; + } + } while ( + (cur_match = (prev[cur_match & wmask] & 0xffff)) > limit && --chain_length != 0 + ); - // Insert the string window[strstart .. strstart+2] in the - // dictionary, and set hash_head to the head of the hash chain: + if (best_len <= lookahead) + { + return best_len; + } + return lookahead; + } - if (lookahead >= MIN_MATCH) + private bool Rfc1950BytesEmitted; + + internal bool WantRfc1950HeaderBytes { get; set; } = true; + + internal int Initialize(ZlibCodec codec, CompressionLevel level) + { + return Initialize(codec, level, ZlibConstants.WindowBitsMax); + } + + internal int Initialize(ZlibCodec codec, CompressionLevel level, int bits) + { + return Initialize(codec, level, bits, MEM_LEVEL_DEFAULT, CompressionStrategy.Default); + } + + internal int Initialize( + ZlibCodec codec, + CompressionLevel level, + int bits, + CompressionStrategy compressionStrategy + ) + { + return Initialize(codec, level, bits, MEM_LEVEL_DEFAULT, compressionStrategy); + } + + internal int Initialize( + ZlibCodec codec, + CompressionLevel level, + int windowBits, + int memLevel, + CompressionStrategy strategy + ) + { + _codec = codec; + _codec.Message = null; + + // validation + if (windowBits < 9 || windowBits > 15) + { + throw new ZlibException("windowBits must be in the range 9..15."); + } + + if (memLevel < 1 || memLevel > MEM_LEVEL_MAX) + { + throw new ZlibException( + string.Format("memLevel must be in the range 1.. {0}", MEM_LEVEL_MAX) + ); + } + + _codec.dstate = this; + + w_bits = windowBits; + w_size = 1 << w_bits; + w_mask = w_size - 1; + + hash_bits = memLevel + 7; + hash_size = 1 << hash_bits; + hash_mask = hash_size - 1; + hash_shift = ((hash_bits + MIN_MATCH - 1) / MIN_MATCH); + + window = new byte[w_size * 2]; + prev = new short[w_size]; + head = new short[hash_size]; + + // for memLevel==8, this will be 16384, 16k + lit_bufsize = 1 << (memLevel + 6); + + // Use a single array as the buffer for data pending compression, + // the output distance codes, and the output length codes (aka tree). + // orig comment: This works just fine since the average + // output size for (length,distance) codes is <= 24 bits. + pending = new byte[lit_bufsize * 4]; + _distanceOffset = lit_bufsize; + _lengthOffset = (1 + 2) * lit_bufsize; + + // So, for memLevel 8, the length of the pending buffer is 65536. 64k. + // The first 16k are pending bytes. + // The middle slice, of 32k, is used for distance codes. + // The final 16k are length codes. + + compressionLevel = level; + compressionStrategy = strategy; + + Reset(); + return ZlibConstants.Z_OK; + } + + internal void Reset() + { + _codec.TotalBytesIn = _codec.TotalBytesOut = 0; + _codec.Message = null; + + //strm.data_type = Z_UNKNOWN; + + pendingCount = 0; + nextPending = 0; + + Rfc1950BytesEmitted = false; + + status = (WantRfc1950HeaderBytes) ? INIT_STATE : BUSY_STATE; + _codec._adler32 = 1; + + last_flush = (int)FlushType.None; + + _InitializeTreeData(); + _InitializeLazyMatch(); + } + + internal int End() + { + if (status != INIT_STATE && status != BUSY_STATE && status != FINISH_STATE) + { + return ZlibConstants.Z_STREAM_ERROR; + } + + // Deallocate in reverse order of allocations: + pending = null; + head = null; + prev = null; + window = null; + + // free + // dstate=null; + return status == BUSY_STATE ? ZlibConstants.Z_DATA_ERROR : ZlibConstants.Z_OK; + } + + private void SetDeflater() + { + switch (config.Flavor) + { + case DeflateFlavor.Store: + DeflateFunction = DeflateNone; + break; + case DeflateFlavor.Fast: + DeflateFunction = DeflateFast; + break; + case DeflateFlavor.Slow: + DeflateFunction = DeflateSlow; + break; + } + } + + internal int SetParams(CompressionLevel level, CompressionStrategy strategy) + { + var result = ZlibConstants.Z_OK; + + if (compressionLevel != level) + { + var newConfig = Config.Lookup(level); + + // change in the deflate flavor (Fast vs slow vs none)? + if (newConfig.Flavor != config.Flavor && _codec.TotalBytesIn != 0) + { + // Flush the last buffer: + result = _codec.Deflate(FlushType.Partial); + } + + compressionLevel = level; + config = newConfig; + SetDeflater(); + } + + // no need to flush with change in strategy? Really? + compressionStrategy = strategy; + + return result; + } + + internal int SetDictionary(byte[] dictionary) + { + var length = dictionary.Length; + var index = 0; + + if (dictionary is null || status != INIT_STATE) + { + throw new ZlibException("Stream error."); + } + + _codec._adler32 = Adler32.Calculate(_codec._adler32, dictionary); + + if (length < MIN_MATCH) + { + return ZlibConstants.Z_OK; + } + if (length > w_size - MIN_LOOKAHEAD) + { + length = w_size - MIN_LOOKAHEAD; + index = dictionary.Length - length; // use the tail of the dictionary + } + Array.Copy(dictionary, index, window, 0, length); + strstart = length; + blockStart = length; + + // Insert all strings in the hash table (except for the last two bytes). + // s->lookahead stays null, so s->ins_h will be recomputed at the next + // call of fill_window. + + ins_h = window[0] & 0xff; + ins_h = (((ins_h) << hash_shift) ^ (window[1] & 0xff)) & hash_mask; + + for (var n = 0; n <= length - MIN_MATCH; n++) + { + ins_h = + (((ins_h) << hash_shift) ^ (window[(n) + (MIN_MATCH - 1)] & 0xff)) & hash_mask; + prev[n & w_mask] = head[ins_h]; + head[ins_h] = (short)n; + } + return ZlibConstants.Z_OK; + } + + internal int Deflate(FlushType flush) + { + int old_flush; + + if ( + _codec.OutputBuffer is null + || (_codec.InputBuffer is null && _codec.AvailableBytesIn != 0) + || (status == FINISH_STATE && flush != FlushType.Finish) + ) + { + _codec.Message = _ErrorMessage[ + ZlibConstants.Z_NEED_DICT - (ZlibConstants.Z_STREAM_ERROR) + ]; + throw new ZlibException(string.Format("Something is fishy. [{0}]", _codec.Message)); + + //return ZlibConstants.Z_STREAM_ERROR; + } + if (_codec.AvailableBytesOut == 0) + { + _codec.Message = _ErrorMessage[ + ZlibConstants.Z_NEED_DICT - (ZlibConstants.Z_BUF_ERROR) + ]; + throw new ZlibException("OutputBuffer is full (AvailableBytesOut == 0)"); + + //return ZlibConstants.Z_BUF_ERROR; + } + + old_flush = last_flush; + last_flush = (int)flush; + + // Write the zlib (rfc1950) header bytes + if (status == INIT_STATE) + { + var header = (Z_DEFLATED + ((w_bits - 8) << 4)) << 8; + var level_flags = (((int)compressionLevel - 1) & 0xff) >> 1; + + if (level_flags > 3) + { + level_flags = 3; + } + header |= (level_flags << 6); + if (strstart != 0) + { + header |= PRESET_DICT; + } + header += 31 - (header % 31); + + status = BUSY_STATE; + //putShortMSB(header); + unchecked + { + pending[pendingCount++] = (byte)(header >> 8); + pending[pendingCount++] = (byte)header; + } + + // Save the adler32 of the preset dictionary: + if (strstart != 0) + { + ////putShortMSB((int)(SharedUtils.URShift(_codec._Adler32, 16))); + //putShortMSB((int)((UInt64)_codec._Adler32 >> 16)); + //putShortMSB((int)(_codec._Adler32 & 0xffff)); + pending[pendingCount++] = (byte)((_codec._adler32 & 0xFF000000) >> 24); + pending[pendingCount++] = (byte)((_codec._adler32 & 0x00FF0000) >> 16); + pending[pendingCount++] = (byte)((_codec._adler32 & 0x0000FF00) >> 8); + pending[pendingCount++] = (byte)(_codec._adler32 & 0x000000FF); + } + _codec._adler32 = 1; + } + + // Flush as much pending output as possible + if (pendingCount != 0) + { + _codec.flush_pending(); + if (_codec.AvailableBytesOut == 0) + { + //System.out.println(" avail_out==0"); + // Since avail_out is 0, deflate will be called again with + // more output space, but possibly with both pending and + // avail_in equal to zero. There won't be anything to do, + // but this is not an error situation so make sure we + // return OK instead of BUF_ERROR at next call of deflate: + last_flush = -1; + return ZlibConstants.Z_OK; + } + + // Make sure there is something to do and avoid duplicate consecutive + // flushes. For repeated and useless calls with Z_FINISH, we keep + // returning Z_STREAM_END instead of Z_BUFF_ERROR. + } + else if ( + _codec.AvailableBytesIn == 0 && (int)flush <= old_flush && flush != FlushType.Finish + ) + { + // workitem 8557 + // Not sure why this needs to be an error. + // pendingCount == 0, which means there's nothing to deflate. + // And the caller has not asked for a FlushType.Finish, but... + // that seems very non-fatal. We can just say "OK" and do nthing. + + // _codec.Message = z_errmsg[ZlibConstants.Z_NEED_DICT - (ZlibConstants.Z_BUF_ERROR)]; + // throw new ZlibException("AvailableBytesIn == 0 && flush<=old_flush && flush != FlushType.Finish"); + + return ZlibConstants.Z_OK; + } + + // User must not provide more input after the first FINISH: + if (status == FINISH_STATE && _codec.AvailableBytesIn != 0) + { + _codec.Message = _ErrorMessage[ + ZlibConstants.Z_NEED_DICT - (ZlibConstants.Z_BUF_ERROR) + ]; + throw new ZlibException("status == FINISH_STATE && _codec.AvailableBytesIn != 0"); + } + + // Start a new block or continue the current one. + if ( + _codec.AvailableBytesIn != 0 + || lookahead != 0 + || (flush != FlushType.None && status != FINISH_STATE) + ) + { + var bstate = DeflateFunction(flush); + + if (bstate == BlockState.FinishStarted || bstate == BlockState.FinishDone) + { + status = FINISH_STATE; + } + if (bstate == BlockState.NeedMore || bstate == BlockState.FinishStarted) + { + if (_codec.AvailableBytesOut == 0) { - ins_h = - (((ins_h) << hash_shift) ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff)) - & hash_mask; - - // prev[strstart&w_mask]=hash_head=head[ins_h]; - hash_head = (head[ins_h] & 0xffff); - prev[strstart & w_mask] = head[ins_h]; - head[ins_h] = unchecked((short)strstart); + last_flush = -1; // avoid BUF_ERROR next call, see above } + return ZlibConstants.Z_OK; - // Find the longest match, discarding those <= prev_length. - prev_length = match_length; - prev_match = match_start; - match_length = MIN_MATCH - 1; + // If flush != Z_NO_FLUSH && avail_out == 0, the next call + // of deflate should use the same flush parameter to make sure + // that the flush is complete. So we don't have to output an + // empty block here, this will be done at next call. This also + // ensures that for a very small output buffer, we emit at most + // one empty block. + } - if ( - hash_head != 0 - && prev_length < config.MaxLazy - && ((strstart - hash_head) & 0xffff) <= w_size - MIN_LOOKAHEAD - ) + if (bstate == BlockState.BlockDone) + { + if (flush == FlushType.Partial) { - // To simplify the code, we prevent matches with the string - // of window index 0 (in particular we have to avoid a match - // of the string with itself at the start of the input file). - - if (compressionStrategy != CompressionStrategy.HuffmanOnly) - { - match_length = longest_match(hash_head); - } - - // longest_match() sets match_start - - if ( - match_length <= 5 - && ( - compressionStrategy == CompressionStrategy.Filtered - || (match_length == MIN_MATCH && strstart - match_start > 4096) - ) - ) - { - // If prev_match is also MIN_MATCH, match_start is garbage - // but we will ignore the current match anyway. - match_length = MIN_MATCH - 1; - } - } - - // If there was a match at the previous step and the current - // match is not better, output the previous match: - if (prev_length >= MIN_MATCH && match_length <= prev_length) - { - int max_insert = strstart + lookahead - MIN_MATCH; - - // Do not insert strings in hash table beyond this. - - // check_match(strstart-1, prev_match, prev_length); - - bflush = _tr_tally(strstart - 1 - prev_match, prev_length - MIN_MATCH); - - // Insert in hash table all strings up to the end of the match. - // strstart-1 and strstart are already inserted. If there is not - // enough lookahead, the last two strings are not inserted in - // the hash table. - lookahead -= (prev_length - 1); - prev_length -= 2; - do - { - if (++strstart <= max_insert) - { - ins_h = - ( - ((ins_h) << hash_shift) - ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff) - ) & hash_mask; - - //prev[strstart&w_mask]=hash_head=head[ins_h]; - hash_head = (head[ins_h] & 0xffff); - prev[strstart & w_mask] = head[ins_h]; - head[ins_h] = unchecked((short)strstart); - } - } while (--prev_length != 0); - match_available = 0; - match_length = MIN_MATCH - 1; - strstart++; - - if (bflush) - { - flush_block_only(false); - if (_codec.AvailableBytesOut == 0) - { - return BlockState.NeedMore; - } - } - } - else if (match_available != 0) - { - // If there was no match at the previous position, output a - // single literal. If there was a match but the current match - // is longer, truncate the previous match to a single literal. - - bflush = _tr_tally(0, window[strstart - 1] & 0xff); - - if (bflush) - { - flush_block_only(false); - } - strstart++; - lookahead--; - if (_codec.AvailableBytesOut == 0) - { - return BlockState.NeedMore; - } + _tr_align(); } else { - // There is no previous match to compare with, wait for - // the next step to decide. + // FlushType.Full or FlushType.Sync + _tr_stored_block(0, 0, false); - match_available = 1; - strstart++; - lookahead--; - } - } - - if (match_available != 0) - { - bflush = _tr_tally(0, window[strstart - 1] & 0xff); - match_available = 0; - } - flush_block_only(flush == FlushType.Finish); - - if (_codec.AvailableBytesOut == 0) - { - if (flush == FlushType.Finish) - { - return BlockState.FinishStarted; - } - return BlockState.NeedMore; - } - - return flush == FlushType.Finish ? BlockState.FinishDone : BlockState.BlockDone; - } - - internal int longest_match(int cur_match) - { - int chain_length = config.MaxChainLength; // max hash chain length - int scan = strstart; // current string - int match; // matched string - int len; // length of current match - int best_len = prev_length; // best match length so far - int limit = - strstart > (w_size - MIN_LOOKAHEAD) ? strstart - (w_size - MIN_LOOKAHEAD) : 0; - - int niceLength = config.NiceLength; - - // Stop when cur_match becomes <= limit. To simplify the code, - // we prevent matches with the string of window index 0. - - int wmask = w_mask; - - int strend = strstart + MAX_MATCH; - byte scan_end1 = window[scan + best_len - 1]; - byte scan_end = window[scan + best_len]; - - // The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. - // It is easy to get rid of this optimization if necessary. - - // Do not waste too much time if we already have a good match: - if (prev_length >= config.GoodLength) - { - chain_length >>= 2; - } - - // Do not look for matches beyond the end of the input. This is necessary - // to make deflate deterministic. - if (niceLength > lookahead) - { - niceLength = lookahead; - } - - do - { - match = cur_match; - - // Skip to next match if the match length cannot increase - // or if the match length is less than 2: - if ( - window[match + best_len] != scan_end - || window[match + best_len - 1] != scan_end1 - || window[match] != window[scan] - || window[++match] != window[scan + 1] - ) - { - continue; - } - - // The check at best_len-1 can be removed because it will be made - // again later. (This heuristic is not always a win.) - // It is not necessary to compare scan[2] and match[2] since they - // are always equal when the other bytes match, given that - // the hash keys are equal and that HASH_BITS >= 8. - scan += 2; - match++; - - // We check for insufficient lookahead only every 8th comparison; - // the 256th check will be made at strstart+258. - do { } while ( - window[++scan] == window[++match] - && window[++scan] == window[++match] - && window[++scan] == window[++match] - && window[++scan] == window[++match] - && window[++scan] == window[++match] - && window[++scan] == window[++match] - && window[++scan] == window[++match] - && window[++scan] == window[++match] - && scan < strend - ); - - len = MAX_MATCH - (strend - scan); - scan = strend - MAX_MATCH; - - if (len > best_len) - { - match_start = cur_match; - best_len = len; - if (len >= niceLength) + // For a full flush, this empty block will be recognized + // as a special marker by inflate_sync(). + if (flush == FlushType.Full) { - break; + // clear hash (forget the history) + for (var i = 0; i < hash_size; i++) + { + head[i] = 0; + } } - scan_end1 = window[scan + best_len - 1]; - scan_end = window[scan + best_len]; } - } while ( - (cur_match = (prev[cur_match & wmask] & 0xffff)) > limit && --chain_length != 0 - ); - - if (best_len <= lookahead) - { - return best_len; - } - return lookahead; - } - - private bool Rfc1950BytesEmitted; - - internal bool WantRfc1950HeaderBytes { get; set; } = true; - - internal int Initialize(ZlibCodec codec, CompressionLevel level) - { - return Initialize(codec, level, ZlibConstants.WindowBitsMax); - } - - internal int Initialize(ZlibCodec codec, CompressionLevel level, int bits) - { - return Initialize(codec, level, bits, MEM_LEVEL_DEFAULT, CompressionStrategy.Default); - } - - internal int Initialize( - ZlibCodec codec, - CompressionLevel level, - int bits, - CompressionStrategy compressionStrategy - ) - { - return Initialize(codec, level, bits, MEM_LEVEL_DEFAULT, compressionStrategy); - } - - internal int Initialize( - ZlibCodec codec, - CompressionLevel level, - int windowBits, - int memLevel, - CompressionStrategy strategy - ) - { - _codec = codec; - _codec.Message = null; - - // validation - if (windowBits < 9 || windowBits > 15) - { - throw new ZlibException("windowBits must be in the range 9..15."); - } - - if (memLevel < 1 || memLevel > MEM_LEVEL_MAX) - { - throw new ZlibException( - String.Format("memLevel must be in the range 1.. {0}", MEM_LEVEL_MAX) - ); - } - - _codec.dstate = this; - - w_bits = windowBits; - w_size = 1 << w_bits; - w_mask = w_size - 1; - - hash_bits = memLevel + 7; - hash_size = 1 << hash_bits; - hash_mask = hash_size - 1; - hash_shift = ((hash_bits + MIN_MATCH - 1) / MIN_MATCH); - - window = new byte[w_size * 2]; - prev = new short[w_size]; - head = new short[hash_size]; - - // for memLevel==8, this will be 16384, 16k - lit_bufsize = 1 << (memLevel + 6); - - // Use a single array as the buffer for data pending compression, - // the output distance codes, and the output length codes (aka tree). - // orig comment: This works just fine since the average - // output size for (length,distance) codes is <= 24 bits. - pending = new byte[lit_bufsize * 4]; - _distanceOffset = lit_bufsize; - _lengthOffset = (1 + 2) * lit_bufsize; - - // So, for memLevel 8, the length of the pending buffer is 65536. 64k. - // The first 16k are pending bytes. - // The middle slice, of 32k, is used for distance codes. - // The final 16k are length codes. - - compressionLevel = level; - compressionStrategy = strategy; - - Reset(); - return ZlibConstants.Z_OK; - } - - internal void Reset() - { - _codec.TotalBytesIn = _codec.TotalBytesOut = 0; - _codec.Message = null; - - //strm.data_type = Z_UNKNOWN; - - pendingCount = 0; - nextPending = 0; - - Rfc1950BytesEmitted = false; - - status = (WantRfc1950HeaderBytes) ? INIT_STATE : BUSY_STATE; - _codec._adler32 = 1; - - last_flush = (int)FlushType.None; - - _InitializeTreeData(); - _InitializeLazyMatch(); - } - - internal int End() - { - if (status != INIT_STATE && status != BUSY_STATE && status != FINISH_STATE) - { - return ZlibConstants.Z_STREAM_ERROR; - } - - // Deallocate in reverse order of allocations: - pending = null; - head = null; - prev = null; - window = null; - - // free - // dstate=null; - return status == BUSY_STATE ? ZlibConstants.Z_DATA_ERROR : ZlibConstants.Z_OK; - } - - private void SetDeflater() - { - switch (config.Flavor) - { - case DeflateFlavor.Store: - DeflateFunction = DeflateNone; - break; - case DeflateFlavor.Fast: - DeflateFunction = DeflateFast; - break; - case DeflateFlavor.Slow: - DeflateFunction = DeflateSlow; - break; - } - } - - internal int SetParams(CompressionLevel level, CompressionStrategy strategy) - { - int result = ZlibConstants.Z_OK; - - if (compressionLevel != level) - { - Config newConfig = Config.Lookup(level); - - // change in the deflate flavor (Fast vs slow vs none)? - if (newConfig.Flavor != config.Flavor && _codec.TotalBytesIn != 0) - { - // Flush the last buffer: - result = _codec.Deflate(FlushType.Partial); - } - - compressionLevel = level; - config = newConfig; - SetDeflater(); - } - - // no need to flush with change in strategy? Really? - compressionStrategy = strategy; - - return result; - } - - internal int SetDictionary(byte[] dictionary) - { - int length = dictionary.Length; - int index = 0; - - if (dictionary is null || status != INIT_STATE) - { - throw new ZlibException("Stream error."); - } - - _codec._adler32 = Adler32.Calculate(_codec._adler32, dictionary); - - if (length < MIN_MATCH) - { - return ZlibConstants.Z_OK; - } - if (length > w_size - MIN_LOOKAHEAD) - { - length = w_size - MIN_LOOKAHEAD; - index = dictionary.Length - length; // use the tail of the dictionary - } - Array.Copy(dictionary, index, window, 0, length); - strstart = length; - blockStart = length; - - // Insert all strings in the hash table (except for the last two bytes). - // s->lookahead stays null, so s->ins_h will be recomputed at the next - // call of fill_window. - - ins_h = window[0] & 0xff; - ins_h = (((ins_h) << hash_shift) ^ (window[1] & 0xff)) & hash_mask; - - for (int n = 0; n <= length - MIN_MATCH; n++) - { - ins_h = - (((ins_h) << hash_shift) ^ (window[(n) + (MIN_MATCH - 1)] & 0xff)) & hash_mask; - prev[n & w_mask] = head[ins_h]; - head[ins_h] = (short)n; - } - return ZlibConstants.Z_OK; - } - - internal int Deflate(FlushType flush) - { - int old_flush; - - if ( - _codec.OutputBuffer is null - || (_codec.InputBuffer is null && _codec.AvailableBytesIn != 0) - || (status == FINISH_STATE && flush != FlushType.Finish) - ) - { - _codec.Message = _ErrorMessage[ - ZlibConstants.Z_NEED_DICT - (ZlibConstants.Z_STREAM_ERROR) - ]; - throw new ZlibException(String.Format("Something is fishy. [{0}]", _codec.Message)); - - //return ZlibConstants.Z_STREAM_ERROR; - } - if (_codec.AvailableBytesOut == 0) - { - _codec.Message = _ErrorMessage[ - ZlibConstants.Z_NEED_DICT - (ZlibConstants.Z_BUF_ERROR) - ]; - throw new ZlibException("OutputBuffer is full (AvailableBytesOut == 0)"); - - //return ZlibConstants.Z_BUF_ERROR; - } - - old_flush = last_flush; - last_flush = (int)flush; - - // Write the zlib (rfc1950) header bytes - if (status == INIT_STATE) - { - int header = (Z_DEFLATED + ((w_bits - 8) << 4)) << 8; - int level_flags = (((int)compressionLevel - 1) & 0xff) >> 1; - - if (level_flags > 3) - { - level_flags = 3; - } - header |= (level_flags << 6); - if (strstart != 0) - { - header |= PRESET_DICT; - } - header += 31 - (header % 31); - - status = BUSY_STATE; - //putShortMSB(header); - unchecked - { - pending[pendingCount++] = (byte)(header >> 8); - pending[pendingCount++] = (byte)header; - } - - // Save the adler32 of the preset dictionary: - if (strstart != 0) - { - ////putShortMSB((int)(SharedUtils.URShift(_codec._Adler32, 16))); - //putShortMSB((int)((UInt64)_codec._Adler32 >> 16)); - //putShortMSB((int)(_codec._Adler32 & 0xffff)); - pending[pendingCount++] = (byte)((_codec._adler32 & 0xFF000000) >> 24); - pending[pendingCount++] = (byte)((_codec._adler32 & 0x00FF0000) >> 16); - pending[pendingCount++] = (byte)((_codec._adler32 & 0x0000FF00) >> 8); - pending[pendingCount++] = (byte)(_codec._adler32 & 0x000000FF); - } - _codec._adler32 = 1; - } - - // Flush as much pending output as possible - if (pendingCount != 0) - { _codec.flush_pending(); if (_codec.AvailableBytesOut == 0) { - //System.out.println(" avail_out==0"); - // Since avail_out is 0, deflate will be called again with - // more output space, but possibly with both pending and - // avail_in equal to zero. There won't be anything to do, - // but this is not an error situation so make sure we - // return OK instead of BUF_ERROR at next call of deflate: - last_flush = -1; + last_flush = -1; // avoid BUF_ERROR at next call, see above return ZlibConstants.Z_OK; } - - // Make sure there is something to do and avoid duplicate consecutive - // flushes. For repeated and useless calls with Z_FINISH, we keep - // returning Z_STREAM_END instead of Z_BUFF_ERROR. } - else if ( - _codec.AvailableBytesIn == 0 && (int)flush <= old_flush && flush != FlushType.Finish - ) - { - // workitem 8557 - // Not sure why this needs to be an error. - // pendingCount == 0, which means there's nothing to deflate. - // And the caller has not asked for a FlushType.Finish, but... - // that seems very non-fatal. We can just say "OK" and do nthing. - - // _codec.Message = z_errmsg[ZlibConstants.Z_NEED_DICT - (ZlibConstants.Z_BUF_ERROR)]; - // throw new ZlibException("AvailableBytesIn == 0 && flush<=old_flush && flush != FlushType.Finish"); - - return ZlibConstants.Z_OK; - } - - // User must not provide more input after the first FINISH: - if (status == FINISH_STATE && _codec.AvailableBytesIn != 0) - { - _codec.Message = _ErrorMessage[ - ZlibConstants.Z_NEED_DICT - (ZlibConstants.Z_BUF_ERROR) - ]; - throw new ZlibException("status == FINISH_STATE && _codec.AvailableBytesIn != 0"); - } - - // Start a new block or continue the current one. - if ( - _codec.AvailableBytesIn != 0 - || lookahead != 0 - || (flush != FlushType.None && status != FINISH_STATE) - ) - { - BlockState bstate = DeflateFunction(flush); - - if (bstate == BlockState.FinishStarted || bstate == BlockState.FinishDone) - { - status = FINISH_STATE; - } - if (bstate == BlockState.NeedMore || bstate == BlockState.FinishStarted) - { - if (_codec.AvailableBytesOut == 0) - { - last_flush = -1; // avoid BUF_ERROR next call, see above - } - return ZlibConstants.Z_OK; - - // If flush != Z_NO_FLUSH && avail_out == 0, the next call - // of deflate should use the same flush parameter to make sure - // that the flush is complete. So we don't have to output an - // empty block here, this will be done at next call. This also - // ensures that for a very small output buffer, we emit at most - // one empty block. - } - - if (bstate == BlockState.BlockDone) - { - if (flush == FlushType.Partial) - { - _tr_align(); - } - else - { - // FlushType.Full or FlushType.Sync - _tr_stored_block(0, 0, false); - - // For a full flush, this empty block will be recognized - // as a special marker by inflate_sync(). - if (flush == FlushType.Full) - { - // clear hash (forget the history) - for (int i = 0; i < hash_size; i++) - { - head[i] = 0; - } - } - } - _codec.flush_pending(); - if (_codec.AvailableBytesOut == 0) - { - last_flush = -1; // avoid BUF_ERROR at next call, see above - return ZlibConstants.Z_OK; - } - } - } - - if (flush != FlushType.Finish) - { - return ZlibConstants.Z_OK; - } - - if (!WantRfc1950HeaderBytes || Rfc1950BytesEmitted) - { - return ZlibConstants.Z_STREAM_END; - } - - // Write the zlib trailer (adler32) - pending[pendingCount++] = (byte)((_codec._adler32 & 0xFF000000) >> 24); - pending[pendingCount++] = (byte)((_codec._adler32 & 0x00FF0000) >> 16); - pending[pendingCount++] = (byte)((_codec._adler32 & 0x0000FF00) >> 8); - pending[pendingCount++] = (byte)(_codec._adler32 & 0x000000FF); - - //putShortMSB((int)(SharedUtils.URShift(_codec._Adler32, 16))); - //putShortMSB((int)(_codec._Adler32 & 0xffff)); - - _codec.flush_pending(); - - // If avail_out is zero, the application will call deflate again - // to flush the rest. - - Rfc1950BytesEmitted = true; // write the trailer only once! - - return pendingCount != 0 ? ZlibConstants.Z_OK : ZlibConstants.Z_STREAM_END; } + + if (flush != FlushType.Finish) + { + return ZlibConstants.Z_OK; + } + + if (!WantRfc1950HeaderBytes || Rfc1950BytesEmitted) + { + return ZlibConstants.Z_STREAM_END; + } + + // Write the zlib trailer (adler32) + pending[pendingCount++] = (byte)((_codec._adler32 & 0xFF000000) >> 24); + pending[pendingCount++] = (byte)((_codec._adler32 & 0x00FF0000) >> 16); + pending[pendingCount++] = (byte)((_codec._adler32 & 0x0000FF00) >> 8); + pending[pendingCount++] = (byte)(_codec._adler32 & 0x000000FF); + + //putShortMSB((int)(SharedUtils.URShift(_codec._Adler32, 16))); + //putShortMSB((int)(_codec._Adler32 & 0xffff)); + + _codec.flush_pending(); + + // If avail_out is zero, the application will call deflate again + // to flush the rest. + + Rfc1950BytesEmitted = true; // write the trailer only once! + + return pendingCount != 0 ? ZlibConstants.Z_OK : ZlibConstants.Z_STREAM_END; } } diff --git a/src/SharpCompress/Compressors/Deflate/DeflateStream.cs b/src/SharpCompress/Compressors/Deflate/DeflateStream.cs index c34b8282..cb7512a6 100644 --- a/src/SharpCompress/Compressors/Deflate/DeflateStream.cs +++ b/src/SharpCompress/Compressors/Deflate/DeflateStream.cs @@ -28,356 +28,355 @@ using System; using System.IO; using System.Text; -namespace SharpCompress.Compressors.Deflate +namespace SharpCompress.Compressors.Deflate; + +public class DeflateStream : Stream { - public class DeflateStream : Stream + private readonly ZlibBaseStream _baseStream; + private bool _disposed; + + public DeflateStream( + Stream stream, + CompressionMode mode, + CompressionLevel level = CompressionLevel.Default, + Encoding? forceEncoding = null + ) { - private readonly ZlibBaseStream _baseStream; - private bool _disposed; - - public DeflateStream( - Stream stream, - CompressionMode mode, - CompressionLevel level = CompressionLevel.Default, - Encoding? forceEncoding = null - ) - { - _baseStream = new ZlibBaseStream( - stream, - mode, - level, - ZlibStreamFlavor.DEFLATE, - forceEncoding - ); - } - - #region Zlib properties - - /// - /// This property sets the flush behavior on the stream. - /// - /// See the ZLIB documentation for the meaning of the flush behavior. - /// - public virtual FlushType FlushMode - { - get => (_baseStream._flushMode); - set - { - if (_disposed) - { - throw new ObjectDisposedException("DeflateStream"); - } - _baseStream._flushMode = value; - } - } - - /// - /// The size of the working buffer for the compression codec. - /// - /// - /// - /// - /// The working buffer is used for all stream operations. The default size is - /// 1024 bytes. The minimum size is 128 bytes. You may get better performance - /// with a larger buffer. Then again, you might not. You would have to test - /// it. - /// - /// - /// - /// Set this before the first call to Read() or Write() on the - /// stream. If you try to set it afterwards, it will throw. - /// - /// - public int BufferSize - { - get => _baseStream._bufferSize; - set - { - if (_disposed) - { - throw new ObjectDisposedException("DeflateStream"); - } - if (_baseStream._workingBuffer != null) - { - throw new ZlibException("The working buffer is already set."); - } - if (value < ZlibConstants.WorkingBufferSizeMin) - { - throw new ZlibException( - String.Format( - "Don't be silly. {0} bytes?? Use a bigger buffer, at least {1}.", - value, - ZlibConstants.WorkingBufferSizeMin - ) - ); - } - _baseStream._bufferSize = value; - } - } - - /// - /// The ZLIB strategy to be used during compression. - /// - /// - /// - /// By tweaking this parameter, you may be able to optimize the compression for - /// data with particular characteristics. - /// - public CompressionStrategy Strategy - { - get => _baseStream.Strategy; - set - { - if (_disposed) - { - throw new ObjectDisposedException("DeflateStream"); - } - _baseStream.Strategy = value; - } - } - - /// Returns the total number of bytes input so far. - public virtual long TotalIn => _baseStream._z.TotalBytesIn; - - /// Returns the total number of bytes output so far. - public virtual long TotalOut => _baseStream._z.TotalBytesOut; - - #endregion - - #region System.IO.Stream methods - - /// - /// Indicates whether the stream can be read. - /// - /// - /// The return value depends on whether the captive stream supports reading. - /// - public override bool CanRead - { - get - { - if (_disposed) - { - throw new ObjectDisposedException("DeflateStream"); - } - return _baseStream._stream.CanRead; - } - } - - /// - /// Indicates whether the stream supports Seek operations. - /// - /// - /// Always returns false. - /// - public override bool CanSeek => false; - - /// - /// Indicates whether the stream can be written. - /// - /// - /// The return value depends on whether the captive stream supports writing. - /// - public override bool CanWrite - { - get - { - if (_disposed) - { - throw new ObjectDisposedException("DeflateStream"); - } - return _baseStream._stream.CanWrite; - } - } - - /// - /// Reading this property always throws a . - /// - public override long Length => throw new NotSupportedException(); - - /// - /// The position of the stream pointer. - /// - /// - /// - /// Setting this property always throws a . Reading will return the total bytes - /// written out, if used in writing, or the total bytes read in, if used in - /// reading. The count may refer to compressed bytes or uncompressed bytes, - /// depending on how you've used the stream. - /// - public override long Position - { - get - { - if (_baseStream._streamMode == ZlibBaseStream.StreamMode.Writer) - { - return _baseStream._z.TotalBytesOut; - } - if (_baseStream._streamMode == ZlibBaseStream.StreamMode.Reader) - { - return _baseStream._z.TotalBytesIn; - } - return 0; - } - set => throw new NotSupportedException(); - } - - /// - /// Dispose the stream. - /// - /// - /// This may or may not result in a Close() call on the captive stream. - /// - protected override void Dispose(bool disposing) - { - try - { - if (!_disposed) - { - if (disposing) - { - _baseStream?.Dispose(); - } - _disposed = true; - } - } - finally - { - base.Dispose(disposing); - } - } - - /// - /// Flush the stream. - /// - public override void Flush() - { - if (_disposed) - { - throw new ObjectDisposedException("DeflateStream"); - } - _baseStream.Flush(); - } - - /// - /// Read data from the stream. - /// - /// - /// - /// - /// If you wish to use the DeflateStream to compress data while - /// reading, you can create a DeflateStream with - /// CompressionMode.Compress, providing an uncompressed data stream. - /// Then call Read() on that DeflateStream, and the data read will be - /// compressed as you read. If you wish to use the DeflateStream to - /// decompress data while reading, you can create a DeflateStream with - /// CompressionMode.Decompress, providing a readable compressed data - /// stream. Then call Read() on that DeflateStream, and the data read - /// will be decompressed as you read. - /// - /// - /// - /// A DeflateStream can be used for Read() or Write(), but not both. - /// - /// - /// - /// The buffer into which the read data should be placed. - /// the offset within that data array to put the first byte read. - /// the number of bytes to read. - /// the number of bytes actually read - public override int Read(byte[] buffer, int offset, int count) - { - if (_disposed) - { - throw new ObjectDisposedException("DeflateStream"); - } - return _baseStream.Read(buffer, offset, count); - } - - public override int ReadByte() - { - if (_disposed) - { - throw new ObjectDisposedException("DeflateStream"); - } - return _baseStream.ReadByte(); - } - - /// - /// Calling this method always throws a . - /// - /// this is irrelevant, since it will always throw! - /// this is irrelevant, since it will always throw! - /// irrelevant! - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } - - /// - /// Calling this method always throws a . - /// - /// this is irrelevant, since it will always throw! - public override void SetLength(long value) - { - throw new NotSupportedException(); - } - - /// - /// Write data to the stream. - /// - /// - /// - /// - /// If you wish to use the DeflateStream to compress data while - /// writing, you can create a DeflateStream with - /// CompressionMode.Compress, and a writable output stream. Then call - /// Write() on that DeflateStream, providing uncompressed data - /// as input. The data sent to the output stream will be the compressed form - /// of the data written. If you wish to use the DeflateStream to - /// decompress data while writing, you can create a DeflateStream with - /// CompressionMode.Decompress, and a writable output stream. Then - /// call Write() on that stream, providing previously compressed - /// data. The data sent to the output stream will be the decompressed form of - /// the data written. - /// - /// - /// - /// A DeflateStream can be used for Read() or Write(), - /// but not both. - /// - /// - /// - /// - /// The buffer holding data to write to the stream. - /// the offset within that data array to find the first byte to write. - /// the number of bytes to write. - public override void Write(byte[] buffer, int offset, int count) - { - if (_disposed) - { - throw new ObjectDisposedException("DeflateStream"); - } - _baseStream.Write(buffer, offset, count); - } - - public override void WriteByte(byte value) - { - if (_disposed) - { - throw new ObjectDisposedException("DeflateStream"); - } - _baseStream.WriteByte(value); - } - - #endregion - - public MemoryStream InputBuffer => - new MemoryStream( - _baseStream._z.InputBuffer, - _baseStream._z.NextIn, - _baseStream._z.AvailableBytesIn - ); + _baseStream = new ZlibBaseStream( + stream, + mode, + level, + ZlibStreamFlavor.DEFLATE, + forceEncoding + ); } + + #region Zlib properties + + /// + /// This property sets the flush behavior on the stream. + /// + /// See the ZLIB documentation for the meaning of the flush behavior. + /// + public virtual FlushType FlushMode + { + get => (_baseStream._flushMode); + set + { + if (_disposed) + { + throw new ObjectDisposedException("DeflateStream"); + } + _baseStream._flushMode = value; + } + } + + /// + /// The size of the working buffer for the compression codec. + /// + /// + /// + /// + /// The working buffer is used for all stream operations. The default size is + /// 1024 bytes. The minimum size is 128 bytes. You may get better performance + /// with a larger buffer. Then again, you might not. You would have to test + /// it. + /// + /// + /// + /// Set this before the first call to Read() or Write() on the + /// stream. If you try to set it afterwards, it will throw. + /// + /// + public int BufferSize + { + get => _baseStream._bufferSize; + set + { + if (_disposed) + { + throw new ObjectDisposedException("DeflateStream"); + } + if (_baseStream._workingBuffer != null) + { + throw new ZlibException("The working buffer is already set."); + } + if (value < ZlibConstants.WorkingBufferSizeMin) + { + throw new ZlibException( + string.Format( + "Don't be silly. {0} bytes?? Use a bigger buffer, at least {1}.", + value, + ZlibConstants.WorkingBufferSizeMin + ) + ); + } + _baseStream._bufferSize = value; + } + } + + /// + /// The ZLIB strategy to be used during compression. + /// + /// + /// + /// By tweaking this parameter, you may be able to optimize the compression for + /// data with particular characteristics. + /// + public CompressionStrategy Strategy + { + get => _baseStream.Strategy; + set + { + if (_disposed) + { + throw new ObjectDisposedException("DeflateStream"); + } + _baseStream.Strategy = value; + } + } + + /// Returns the total number of bytes input so far. + public virtual long TotalIn => _baseStream._z.TotalBytesIn; + + /// Returns the total number of bytes output so far. + public virtual long TotalOut => _baseStream._z.TotalBytesOut; + + #endregion + + #region System.IO.Stream methods + + /// + /// Indicates whether the stream can be read. + /// + /// + /// The return value depends on whether the captive stream supports reading. + /// + public override bool CanRead + { + get + { + if (_disposed) + { + throw new ObjectDisposedException("DeflateStream"); + } + return _baseStream._stream.CanRead; + } + } + + /// + /// Indicates whether the stream supports Seek operations. + /// + /// + /// Always returns false. + /// + public override bool CanSeek => false; + + /// + /// Indicates whether the stream can be written. + /// + /// + /// The return value depends on whether the captive stream supports writing. + /// + public override bool CanWrite + { + get + { + if (_disposed) + { + throw new ObjectDisposedException("DeflateStream"); + } + return _baseStream._stream.CanWrite; + } + } + + /// + /// Reading this property always throws a . + /// + public override long Length => throw new NotSupportedException(); + + /// + /// The position of the stream pointer. + /// + /// + /// + /// Setting this property always throws a . Reading will return the total bytes + /// written out, if used in writing, or the total bytes read in, if used in + /// reading. The count may refer to compressed bytes or uncompressed bytes, + /// depending on how you've used the stream. + /// + public override long Position + { + get + { + if (_baseStream._streamMode == ZlibBaseStream.StreamMode.Writer) + { + return _baseStream._z.TotalBytesOut; + } + if (_baseStream._streamMode == ZlibBaseStream.StreamMode.Reader) + { + return _baseStream._z.TotalBytesIn; + } + return 0; + } + set => throw new NotSupportedException(); + } + + /// + /// Dispose the stream. + /// + /// + /// This may or may not result in a Close() call on the captive stream. + /// + protected override void Dispose(bool disposing) + { + try + { + if (!_disposed) + { + if (disposing) + { + _baseStream?.Dispose(); + } + _disposed = true; + } + } + finally + { + base.Dispose(disposing); + } + } + + /// + /// Flush the stream. + /// + public override void Flush() + { + if (_disposed) + { + throw new ObjectDisposedException("DeflateStream"); + } + _baseStream.Flush(); + } + + /// + /// Read data from the stream. + /// + /// + /// + /// + /// If you wish to use the DeflateStream to compress data while + /// reading, you can create a DeflateStream with + /// CompressionMode.Compress, providing an uncompressed data stream. + /// Then call Read() on that DeflateStream, and the data read will be + /// compressed as you read. If you wish to use the DeflateStream to + /// decompress data while reading, you can create a DeflateStream with + /// CompressionMode.Decompress, providing a readable compressed data + /// stream. Then call Read() on that DeflateStream, and the data read + /// will be decompressed as you read. + /// + /// + /// + /// A DeflateStream can be used for Read() or Write(), but not both. + /// + /// + /// + /// The buffer into which the read data should be placed. + /// the offset within that data array to put the first byte read. + /// the number of bytes to read. + /// the number of bytes actually read + public override int Read(byte[] buffer, int offset, int count) + { + if (_disposed) + { + throw new ObjectDisposedException("DeflateStream"); + } + return _baseStream.Read(buffer, offset, count); + } + + public override int ReadByte() + { + if (_disposed) + { + throw new ObjectDisposedException("DeflateStream"); + } + return _baseStream.ReadByte(); + } + + /// + /// Calling this method always throws a . + /// + /// this is irrelevant, since it will always throw! + /// this is irrelevant, since it will always throw! + /// irrelevant! + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } + + /// + /// Calling this method always throws a . + /// + /// this is irrelevant, since it will always throw! + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + /// + /// Write data to the stream. + /// + /// + /// + /// + /// If you wish to use the DeflateStream to compress data while + /// writing, you can create a DeflateStream with + /// CompressionMode.Compress, and a writable output stream. Then call + /// Write() on that DeflateStream, providing uncompressed data + /// as input. The data sent to the output stream will be the compressed form + /// of the data written. If you wish to use the DeflateStream to + /// decompress data while writing, you can create a DeflateStream with + /// CompressionMode.Decompress, and a writable output stream. Then + /// call Write() on that stream, providing previously compressed + /// data. The data sent to the output stream will be the decompressed form of + /// the data written. + /// + /// + /// + /// A DeflateStream can be used for Read() or Write(), + /// but not both. + /// + /// + /// + /// + /// The buffer holding data to write to the stream. + /// the offset within that data array to find the first byte to write. + /// the number of bytes to write. + public override void Write(byte[] buffer, int offset, int count) + { + if (_disposed) + { + throw new ObjectDisposedException("DeflateStream"); + } + _baseStream.Write(buffer, offset, count); + } + + public override void WriteByte(byte value) + { + if (_disposed) + { + throw new ObjectDisposedException("DeflateStream"); + } + _baseStream.WriteByte(value); + } + + #endregion + + public MemoryStream InputBuffer => + new MemoryStream( + _baseStream._z.InputBuffer, + _baseStream._z.NextIn, + _baseStream._z.AvailableBytesIn + ); } diff --git a/src/SharpCompress/Compressors/Deflate/FlushType.cs b/src/SharpCompress/Compressors/Deflate/FlushType.cs index 1cb4eb06..bcf7fe10 100644 --- a/src/SharpCompress/Compressors/Deflate/FlushType.cs +++ b/src/SharpCompress/Compressors/Deflate/FlushType.cs @@ -1,44 +1,43 @@ -namespace SharpCompress.Compressors.Deflate +namespace SharpCompress.Compressors.Deflate; + +/// +/// Describes how to flush the current deflate operation. +/// +/// +/// The different FlushType values are useful when using a Deflate in a streaming application. +/// +public enum FlushType { - /// - /// Describes how to flush the current deflate operation. + /// No flush at all. + None = 0, + + /// Closes the current block, but doesn't flush it to + /// the output. Used internally only in hypothetical + /// scenarios. This was supposed to be removed by Zlib, but it is + /// still in use in some edge cases. /// - /// - /// The different FlushType values are useful when using a Deflate in a streaming application. - /// - public enum FlushType - { - /// No flush at all. - None = 0, + Partial, - /// Closes the current block, but doesn't flush it to - /// the output. Used internally only in hypothetical - /// scenarios. This was supposed to be removed by Zlib, but it is - /// still in use in some edge cases. - /// - Partial, + /// + /// Use this during compression to specify that all pending output should be + /// flushed to the output buffer and the output should be aligned on a byte + /// boundary. You might use this in a streaming communication scenario, so that + /// the decompressor can get all input data available so far. When using this + /// with a ZlibCodec, AvailableBytesIn will be zero after the call if + /// enough output space has been provided before the call. Flushing will + /// degrade compression and so it should be used only when necessary. + /// + Sync, - /// - /// Use this during compression to specify that all pending output should be - /// flushed to the output buffer and the output should be aligned on a byte - /// boundary. You might use this in a streaming communication scenario, so that - /// the decompressor can get all input data available so far. When using this - /// with a ZlibCodec, AvailableBytesIn will be zero after the call if - /// enough output space has been provided before the call. Flushing will - /// degrade compression and so it should be used only when necessary. - /// - Sync, + /// + /// Use this during compression to specify that all output should be flushed, as + /// with FlushType.Sync, but also, the compression state should be reset + /// so that decompression can restart from this point if previous compressed + /// data has been damaged or if random access is desired. Using + /// FlushType.Full too often can significantly degrade the compression. + /// + Full, - /// - /// Use this during compression to specify that all output should be flushed, as - /// with FlushType.Sync, but also, the compression state should be reset - /// so that decompression can restart from this point if previous compressed - /// data has been damaged or if random access is desired. Using - /// FlushType.Full too often can significantly degrade the compression. - /// - Full, - - /// Signals the end of the compression/decompression stream. - Finish - } + /// Signals the end of the compression/decompression stream. + Finish } diff --git a/src/SharpCompress/Compressors/Deflate/GZipStream.cs b/src/SharpCompress/Compressors/Deflate/GZipStream.cs index 572f677e..9c99cd26 100644 --- a/src/SharpCompress/Compressors/Deflate/GZipStream.cs +++ b/src/SharpCompress/Compressors/Deflate/GZipStream.cs @@ -31,461 +31,457 @@ using System.Buffers.Binary; using System.IO; using System.Text; -namespace SharpCompress.Compressors.Deflate +namespace SharpCompress.Compressors.Deflate; + +public class GZipStream : Stream { - public class GZipStream : Stream + internal static readonly DateTime UNIX_EPOCH = new DateTime( + 1970, + 1, + 1, + 0, + 0, + 0, + DateTimeKind.Utc + ); + + private string? _comment; + private string? _fileName; + private DateTime? _lastModified; + + internal ZlibBaseStream BaseStream; + private bool _disposed; + private bool _firstReadDone; + private int _headerByteCount; + + private readonly Encoding _encoding; + + public GZipStream(Stream stream, CompressionMode mode) + : this(stream, mode, CompressionLevel.Default, Encoding.UTF8) { } + + public GZipStream(Stream stream, CompressionMode mode, CompressionLevel level) + : this(stream, mode, level, Encoding.UTF8) { } + + public GZipStream( + Stream stream, + CompressionMode mode, + CompressionLevel level, + Encoding encoding + ) { - internal static readonly DateTime UNIX_EPOCH = new DateTime( - 1970, - 1, - 1, - 0, - 0, - 0, - DateTimeKind.Utc - ); + BaseStream = new ZlibBaseStream(stream, mode, level, ZlibStreamFlavor.GZIP, encoding); + _encoding = encoding; + } - private string? _comment; - private string? _fileName; - private DateTime? _lastModified; + #region Zlib properties - internal ZlibBaseStream BaseStream; - private bool _disposed; - private bool _firstReadDone; - private int _headerByteCount; - - private readonly Encoding _encoding; - - public GZipStream(Stream stream, CompressionMode mode) - : this(stream, mode, CompressionLevel.Default, Encoding.UTF8) { } - - public GZipStream(Stream stream, CompressionMode mode, CompressionLevel level) - : this(stream, mode, level, Encoding.UTF8) { } - - public GZipStream( - Stream stream, - CompressionMode mode, - CompressionLevel level, - Encoding encoding - ) - { - BaseStream = new ZlibBaseStream(stream, mode, level, ZlibStreamFlavor.GZIP, encoding); - _encoding = encoding; - } - - #region Zlib properties - - public virtual FlushType FlushMode - { - get => (BaseStream._flushMode); - set - { - if (_disposed) - { - throw new ObjectDisposedException("GZipStream"); - } - BaseStream._flushMode = value; - } - } - - public int BufferSize - { - get => BaseStream._bufferSize; - set - { - if (_disposed) - { - throw new ObjectDisposedException("GZipStream"); - } - if (BaseStream._workingBuffer != null) - { - throw new ZlibException("The working buffer is already set."); - } - if (value < ZlibConstants.WorkingBufferSizeMin) - { - throw new ZlibException( - String.Format( - "Don't be silly. {0} bytes?? Use a bigger buffer, at least {1}.", - value, - ZlibConstants.WorkingBufferSizeMin - ) - ); - } - BaseStream._bufferSize = value; - } - } - - internal virtual long TotalIn => BaseStream._z.TotalBytesIn; - - internal virtual long TotalOut => BaseStream._z.TotalBytesOut; - - #endregion - - #region Stream methods - - /// - /// Indicates whether the stream can be read. - /// - /// - /// The return value depends on whether the captive stream supports reading. - /// - public override bool CanRead - { - get - { - if (_disposed) - { - throw new ObjectDisposedException("GZipStream"); - } - return BaseStream._stream.CanRead; - } - } - - /// - /// Indicates whether the stream supports Seek operations. - /// - /// - /// Always returns false. - /// - public override bool CanSeek => false; - - /// - /// Indicates whether the stream can be written. - /// - /// - /// The return value depends on whether the captive stream supports writing. - /// - public override bool CanWrite - { - get - { - if (_disposed) - { - throw new ObjectDisposedException("GZipStream"); - } - return BaseStream._stream.CanWrite; - } - } - - /// - /// Reading this property always throws a . - /// - public override long Length => throw new NotSupportedException(); - - /// - /// The position of the stream pointer. - /// - /// - /// - /// Setting this property always throws a . Reading will return the total bytes - /// written out, if used in writing, or the total bytes read in, if used in - /// reading. The count may refer to compressed bytes or uncompressed bytes, - /// depending on how you've used the stream. - /// - public override long Position - { - get - { - if (BaseStream._streamMode == ZlibBaseStream.StreamMode.Writer) - { - return BaseStream._z.TotalBytesOut + _headerByteCount; - } - if (BaseStream._streamMode == ZlibBaseStream.StreamMode.Reader) - { - return BaseStream._z.TotalBytesIn + BaseStream._gzipHeaderByteCount; - } - return 0; - } - set => throw new NotSupportedException(); - } - - /// - /// Dispose the stream. - /// - /// - /// This may or may not result in a Close() call on the captive stream. - /// - protected override void Dispose(bool disposing) - { - try - { - if (!_disposed) - { - if (disposing && (BaseStream != null)) - { - BaseStream.Dispose(); - Crc32 = BaseStream.Crc32; - } - _disposed = true; - } - } - finally - { - base.Dispose(disposing); - } - } - - /// - /// Flush the stream. - /// - public override void Flush() + public virtual FlushType FlushMode + { + get => (BaseStream._flushMode); + set { if (_disposed) { throw new ObjectDisposedException("GZipStream"); } - BaseStream.Flush(); - } - - /// - /// Read and decompress data from the source stream. - /// - /// - /// - /// With a GZipStream, decompression is done through reading. - /// - /// - /// - /// - /// byte[] working = new byte[WORKING_BUFFER_SIZE]; - /// using (System.IO.Stream input = System.IO.File.OpenRead(_CompressedFile)) - /// { - /// using (Stream decompressor= new Ionic.Zlib.GZipStream(input, CompressionMode.Decompress, true)) - /// { - /// using (var output = System.IO.File.Create(_DecompressedFile)) - /// { - /// int n; - /// while ((n= decompressor.Read(working, 0, working.Length)) !=0) - /// { - /// output.Write(working, 0, n); - /// } - /// } - /// } - /// } - /// - /// - /// The buffer into which the decompressed data should be placed. - /// the offset within that data array to put the first byte read. - /// the number of bytes to read. - /// the number of bytes actually read - public override int Read(byte[] buffer, int offset, int count) - { - if (_disposed) - { - throw new ObjectDisposedException("GZipStream"); - } - int n = BaseStream.Read(buffer, offset, count); - - // Console.WriteLine("GZipStream::Read(buffer, off({0}), c({1}) = {2}", offset, count, n); - // Console.WriteLine( Util.FormatByteArray(buffer, offset, n) ); - - if (!_firstReadDone) - { - _firstReadDone = true; - FileName = BaseStream._GzipFileName; - Comment = BaseStream._GzipComment; - LastModified = BaseStream._GzipMtime; - } - return n; - } - - /// - /// Calling this method always throws a . - /// - /// irrelevant; it will always throw! - /// irrelevant; it will always throw! - /// irrelevant! - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } - - /// - /// Calling this method always throws a . - /// - /// irrelevant; this method will always throw! - public override void SetLength(long value) - { - throw new NotSupportedException(); - } - - /// - /// Write data to the stream. - /// - /// - /// - /// - /// If you wish to use the GZipStream to compress data while writing, - /// you can create a GZipStream with CompressionMode.Compress, and a - /// writable output stream. Then call Write() on that GZipStream, - /// providing uncompressed data as input. The data sent to the output stream - /// will be the compressed form of the data written. - /// - /// - /// - /// A GZipStream can be used for Read() or Write(), but not - /// both. Writing implies compression. Reading implies decompression. - /// - /// - /// - /// The buffer holding data to write to the stream. - /// the offset within that data array to find the first byte to write. - /// the number of bytes to write. - public override void Write(byte[] buffer, int offset, int count) - { - if (_disposed) - { - throw new ObjectDisposedException("GZipStream"); - } - if (BaseStream._streamMode == ZlibBaseStream.StreamMode.Undefined) - { - //Console.WriteLine("GZipStream: First write"); - if (BaseStream._wantCompress) - { - // first write in compression, therefore, emit the GZIP header - _headerByteCount = EmitHeader(); - } - else - { - throw new InvalidOperationException(); - } - } - - BaseStream.Write(buffer, offset, count); - } - - #endregion Stream methods - - public string? Comment - { - get => _comment; - set - { - if (_disposed) - { - throw new ObjectDisposedException(nameof(GZipStream)); - } - _comment = value; - } - } - - public DateTime? LastModified - { - get => _lastModified; - set - { - if (_disposed) - { - throw new ObjectDisposedException(nameof(GZipStream)); - } - _lastModified = value; - } - } - - public string? FileName - { - get => _fileName; - set - { - if (_disposed) - { - throw new ObjectDisposedException(nameof(GZipStream)); - } - _fileName = value; - if (_fileName is null) - { - return; - } - if (_fileName.Contains('/')) - { - _fileName = _fileName.Replace('/', '\\'); - } - if (_fileName.EndsWith('\\')) - { - throw new InvalidOperationException("Illegal filename"); - } - - if (_fileName.Contains('\\')) - { - // trim any leading path - _fileName = Path.GetFileName(_fileName); - } - } - } - - public int Crc32 { get; private set; } - - private int EmitHeader() - { - byte[]? commentBytes = (Comment is null) ? null : _encoding.GetBytes(Comment); - byte[]? filenameBytes = (FileName is null) ? null : _encoding.GetBytes(FileName); - - int cbLength = commentBytes?.Length + 1 ?? 0; - int fnLength = filenameBytes?.Length + 1 ?? 0; - - int bufferLength = 10 + cbLength + fnLength; - var header = new byte[bufferLength]; - int i = 0; - - // ID - header[i++] = 0x1F; - header[i++] = 0x8B; - - // compression method - header[i++] = 8; - byte flag = 0; - if (Comment != null) - { - flag ^= 0x10; - } - if (FileName != null) - { - flag ^= 0x8; - } - - // flag - header[i++] = flag; - - // mtime - if (LastModified is null) - { - LastModified = DateTime.Now; - } - TimeSpan delta = LastModified.Value - UNIX_EPOCH; - var timet = (int)delta.TotalSeconds; - BinaryPrimitives.WriteInt32LittleEndian(header.AsSpan(i), timet); - i += 4; - - // xflg - header[i++] = 0; // this field is totally useless - - // OS - header[i++] = 0xFF; // 0xFF == unspecified - - // extra field length - only if FEXTRA is set, which it is not. - //header[i++]= 0; - //header[i++]= 0; - - // filename - if (fnLength != 0) - { - Array.Copy(filenameBytes!, 0, header, i, fnLength - 1); - i += fnLength - 1; - header[i++] = 0; // terminate - } - - // comment - if (cbLength != 0) - { - Array.Copy(commentBytes!, 0, header, i, cbLength - 1); - i += cbLength - 1; - header[i++] = 0; // terminate - } - - BaseStream._stream.Write(header, 0, header.Length); - - return header.Length; // bytes written + BaseStream._flushMode = value; } } + + public int BufferSize + { + get => BaseStream._bufferSize; + set + { + if (_disposed) + { + throw new ObjectDisposedException("GZipStream"); + } + if (BaseStream._workingBuffer != null) + { + throw new ZlibException("The working buffer is already set."); + } + if (value < ZlibConstants.WorkingBufferSizeMin) + { + throw new ZlibException( + string.Format( + "Don't be silly. {0} bytes?? Use a bigger buffer, at least {1}.", + value, + ZlibConstants.WorkingBufferSizeMin + ) + ); + } + BaseStream._bufferSize = value; + } + } + + internal virtual long TotalIn => BaseStream._z.TotalBytesIn; + + internal virtual long TotalOut => BaseStream._z.TotalBytesOut; + + #endregion + + #region Stream methods + + /// + /// Indicates whether the stream can be read. + /// + /// + /// The return value depends on whether the captive stream supports reading. + /// + public override bool CanRead + { + get + { + if (_disposed) + { + throw new ObjectDisposedException("GZipStream"); + } + return BaseStream._stream.CanRead; + } + } + + /// + /// Indicates whether the stream supports Seek operations. + /// + /// + /// Always returns false. + /// + public override bool CanSeek => false; + + /// + /// Indicates whether the stream can be written. + /// + /// + /// The return value depends on whether the captive stream supports writing. + /// + public override bool CanWrite + { + get + { + if (_disposed) + { + throw new ObjectDisposedException("GZipStream"); + } + return BaseStream._stream.CanWrite; + } + } + + /// + /// Reading this property always throws a . + /// + public override long Length => throw new NotSupportedException(); + + /// + /// The position of the stream pointer. + /// + /// + /// + /// Setting this property always throws a . Reading will return the total bytes + /// written out, if used in writing, or the total bytes read in, if used in + /// reading. The count may refer to compressed bytes or uncompressed bytes, + /// depending on how you've used the stream. + /// + public override long Position + { + get + { + if (BaseStream._streamMode == ZlibBaseStream.StreamMode.Writer) + { + return BaseStream._z.TotalBytesOut + _headerByteCount; + } + if (BaseStream._streamMode == ZlibBaseStream.StreamMode.Reader) + { + return BaseStream._z.TotalBytesIn + BaseStream._gzipHeaderByteCount; + } + return 0; + } + set => throw new NotSupportedException(); + } + + /// + /// Dispose the stream. + /// + /// + /// This may or may not result in a Close() call on the captive stream. + /// + protected override void Dispose(bool disposing) + { + try + { + if (!_disposed) + { + if (disposing && (BaseStream != null)) + { + BaseStream.Dispose(); + Crc32 = BaseStream.Crc32; + } + _disposed = true; + } + } + finally + { + base.Dispose(disposing); + } + } + + /// + /// Flush the stream. + /// + public override void Flush() + { + if (_disposed) + { + throw new ObjectDisposedException("GZipStream"); + } + BaseStream.Flush(); + } + + /// + /// Read and decompress data from the source stream. + /// + /// + /// + /// With a GZipStream, decompression is done through reading. + /// + /// + /// + /// + /// byte[] working = new byte[WORKING_BUFFER_SIZE]; + /// using (System.IO.Stream input = System.IO.File.OpenRead(_CompressedFile)) + /// { + /// using (Stream decompressor= new Ionic.Zlib.GZipStream(input, CompressionMode.Decompress, true)) + /// { + /// using (var output = System.IO.File.Create(_DecompressedFile)) + /// { + /// int n; + /// while ((n= decompressor.Read(working, 0, working.Length)) !=0) + /// { + /// output.Write(working, 0, n); + /// } + /// } + /// } + /// } + /// + /// + /// The buffer into which the decompressed data should be placed. + /// the offset within that data array to put the first byte read. + /// the number of bytes to read. + /// the number of bytes actually read + public override int Read(byte[] buffer, int offset, int count) + { + if (_disposed) + { + throw new ObjectDisposedException("GZipStream"); + } + var n = BaseStream.Read(buffer, offset, count); + + // Console.WriteLine("GZipStream::Read(buffer, off({0}), c({1}) = {2}", offset, count, n); + // Console.WriteLine( Util.FormatByteArray(buffer, offset, n) ); + + if (!_firstReadDone) + { + _firstReadDone = true; + FileName = BaseStream._GzipFileName; + Comment = BaseStream._GzipComment; + LastModified = BaseStream._GzipMtime; + } + return n; + } + + /// + /// Calling this method always throws a . + /// + /// irrelevant; it will always throw! + /// irrelevant; it will always throw! + /// irrelevant! + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } + + /// + /// Calling this method always throws a . + /// + /// irrelevant; this method will always throw! + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + /// + /// Write data to the stream. + /// + /// + /// + /// + /// If you wish to use the GZipStream to compress data while writing, + /// you can create a GZipStream with CompressionMode.Compress, and a + /// writable output stream. Then call Write() on that GZipStream, + /// providing uncompressed data as input. The data sent to the output stream + /// will be the compressed form of the data written. + /// + /// + /// + /// A GZipStream can be used for Read() or Write(), but not + /// both. Writing implies compression. Reading implies decompression. + /// + /// + /// + /// The buffer holding data to write to the stream. + /// the offset within that data array to find the first byte to write. + /// the number of bytes to write. + public override void Write(byte[] buffer, int offset, int count) + { + if (_disposed) + { + throw new ObjectDisposedException("GZipStream"); + } + if (BaseStream._streamMode == ZlibBaseStream.StreamMode.Undefined) + { + //Console.WriteLine("GZipStream: First write"); + if (BaseStream._wantCompress) + { + // first write in compression, therefore, emit the GZIP header + _headerByteCount = EmitHeader(); + } + else + { + throw new InvalidOperationException(); + } + } + + BaseStream.Write(buffer, offset, count); + } + + #endregion Stream methods + + public string? Comment + { + get => _comment; + set + { + if (_disposed) + { + throw new ObjectDisposedException(nameof(GZipStream)); + } + _comment = value; + } + } + + public DateTime? LastModified + { + get => _lastModified; + set + { + if (_disposed) + { + throw new ObjectDisposedException(nameof(GZipStream)); + } + _lastModified = value; + } + } + + public string? FileName + { + get => _fileName; + set + { + if (_disposed) + { + throw new ObjectDisposedException(nameof(GZipStream)); + } + _fileName = value; + if (_fileName is null) + { + return; + } + if (_fileName.Contains('/')) + { + _fileName = _fileName.Replace('/', '\\'); + } + if (_fileName.EndsWith('\\')) + { + throw new InvalidOperationException("Illegal filename"); + } + + if (_fileName.Contains('\\')) + { + // trim any leading path + _fileName = Path.GetFileName(_fileName); + } + } + } + + public int Crc32 { get; private set; } + + private int EmitHeader() + { + var commentBytes = (Comment is null) ? null : _encoding.GetBytes(Comment); + var filenameBytes = (FileName is null) ? null : _encoding.GetBytes(FileName); + + var cbLength = commentBytes?.Length + 1 ?? 0; + var fnLength = filenameBytes?.Length + 1 ?? 0; + + var bufferLength = 10 + cbLength + fnLength; + var header = new byte[bufferLength]; + var i = 0; + + // ID + header[i++] = 0x1F; + header[i++] = 0x8B; + + // compression method + header[i++] = 8; + byte flag = 0; + if (Comment != null) + { + flag ^= 0x10; + } + if (FileName != null) + { + flag ^= 0x8; + } + + // flag + header[i++] = flag; + + // mtime + LastModified ??= DateTime.Now; + var delta = LastModified.Value - UNIX_EPOCH; + var timet = (int)delta.TotalSeconds; + BinaryPrimitives.WriteInt32LittleEndian(header.AsSpan(i), timet); + i += 4; + + // xflg + header[i++] = 0; // this field is totally useless + + // OS + header[i++] = 0xFF; // 0xFF == unspecified + + // extra field length - only if FEXTRA is set, which it is not. + //header[i++]= 0; + //header[i++]= 0; + + // filename + if (fnLength != 0) + { + Array.Copy(filenameBytes!, 0, header, i, fnLength - 1); + i += fnLength - 1; + header[i++] = 0; // terminate + } + + // comment + if (cbLength != 0) + { + Array.Copy(commentBytes!, 0, header, i, cbLength - 1); + i += cbLength - 1; + header[i++] = 0; // terminate + } + + BaseStream._stream.Write(header, 0, header.Length); + + return header.Length; // bytes written + } } diff --git a/src/SharpCompress/Compressors/Deflate/InfTree.cs b/src/SharpCompress/Compressors/Deflate/InfTree.cs index 9d8e4fe6..89f02d7a 100644 --- a/src/SharpCompress/Compressors/Deflate/InfTree.cs +++ b/src/SharpCompress/Compressors/Deflate/InfTree.cs @@ -63,2182 +63,2175 @@ using System; -namespace SharpCompress.Compressors.Deflate +namespace SharpCompress.Compressors.Deflate; + +internal sealed class InfTree { - internal sealed class InfTree + private const int MANY = 1440; + + private const int Z_OK = 0; + private const int Z_DATA_ERROR = -3; + private const int Z_MEM_ERROR = -4; + private const int Z_BUF_ERROR = -5; + internal const int fixed_bl = 9; + internal const int fixed_bd = 5; + internal const int BMAX = 15; // maximum bit length of any code + + //UPGRADE_NOTE: Final was removed from the declaration of 'fixed_tl'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + internal static readonly int[] fixed_tl = { - private const int MANY = 1440; + 96, + 7, + 256, + 0, + 8, + 80, + 0, + 8, + 16, + 84, + 8, + 115, + 82, + 7, + 31, + 0, + 8, + 112, + 0, + 8, + 48, + 0, + 9, + 192, + 80, + 7, + 10, + 0, + 8, + 96, + 0, + 8, + 32, + 0, + 9, + 160, + 0, + 8, + 0, + 0, + 8, + 128, + 0, + 8, + 64, + 0, + 9, + 224, + 80, + 7, + 6, + 0, + 8, + 88, + 0, + 8, + 24, + 0, + 9, + 144, + 83, + 7, + 59, + 0, + 8, + 120, + 0, + 8, + 56, + 0, + 9, + 208, + 81, + 7, + 17, + 0, + 8, + 104, + 0, + 8, + 40, + 0, + 9, + 176, + 0, + 8, + 8, + 0, + 8, + 136, + 0, + 8, + 72, + 0, + 9, + 240, + 80, + 7, + 4, + 0, + 8, + 84, + 0, + 8, + 20, + 85, + 8, + 227, + 83, + 7, + 43, + 0, + 8, + 116, + 0, + 8, + 52, + 0, + 9, + 200, + 81, + 7, + 13, + 0, + 8, + 100, + 0, + 8, + 36, + 0, + 9, + 168, + 0, + 8, + 4, + 0, + 8, + 132, + 0, + 8, + 68, + 0, + 9, + 232, + 80, + 7, + 8, + 0, + 8, + 92, + 0, + 8, + 28, + 0, + 9, + 152, + 84, + 7, + 83, + 0, + 8, + 124, + 0, + 8, + 60, + 0, + 9, + 216, + 82, + 7, + 23, + 0, + 8, + 108, + 0, + 8, + 44, + 0, + 9, + 184, + 0, + 8, + 12, + 0, + 8, + 140, + 0, + 8, + 76, + 0, + 9, + 248, + 80, + 7, + 3, + 0, + 8, + 82, + 0, + 8, + 18, + 85, + 8, + 163, + 83, + 7, + 35, + 0, + 8, + 114, + 0, + 8, + 50, + 0, + 9, + 196, + 81, + 7, + 11, + 0, + 8, + 98, + 0, + 8, + 34, + 0, + 9, + 164, + 0, + 8, + 2, + 0, + 8, + 130, + 0, + 8, + 66, + 0, + 9, + 228, + 80, + 7, + 7, + 0, + 8, + 90, + 0, + 8, + 26, + 0, + 9, + 148, + 84, + 7, + 67, + 0, + 8, + 122, + 0, + 8, + 58, + 0, + 9, + 212, + 82, + 7, + 19, + 0, + 8, + 106, + 0, + 8, + 42, + 0, + 9, + 180, + 0, + 8, + 10, + 0, + 8, + 138, + 0, + 8, + 74, + 0, + 9, + 244, + 80, + 7, + 5, + 0, + 8, + 86, + 0, + 8, + 22, + 192, + 8, + 0, + 83, + 7, + 51, + 0, + 8, + 118, + 0, + 8, + 54, + 0, + 9, + 204, + 81, + 7, + 15, + 0, + 8, + 102, + 0, + 8, + 38, + 0, + 9, + 172, + 0, + 8, + 6, + 0, + 8, + 134, + 0, + 8, + 70, + 0, + 9, + 236, + 80, + 7, + 9, + 0, + 8, + 94, + 0, + 8, + 30, + 0, + 9, + 156, + 84, + 7, + 99, + 0, + 8, + 126, + 0, + 8, + 62, + 0, + 9, + 220, + 82, + 7, + 27, + 0, + 8, + 110, + 0, + 8, + 46, + 0, + 9, + 188, + 0, + 8, + 14, + 0, + 8, + 142, + 0, + 8, + 78, + 0, + 9, + 252, + 96, + 7, + 256, + 0, + 8, + 81, + 0, + 8, + 17, + 85, + 8, + 131, + 82, + 7, + 31, + 0, + 8, + 113, + 0, + 8, + 49, + 0, + 9, + 194, + 80, + 7, + 10, + 0, + 8, + 97, + 0, + 8, + 33, + 0, + 9, + 162, + 0, + 8, + 1, + 0, + 8, + 129, + 0, + 8, + 65, + 0, + 9, + 226, + 80, + 7, + 6, + 0, + 8, + 89, + 0, + 8, + 25, + 0, + 9, + 146, + 83, + 7, + 59, + 0, + 8, + 121, + 0, + 8, + 57, + 0, + 9, + 210, + 81, + 7, + 17, + 0, + 8, + 105, + 0, + 8, + 41, + 0, + 9, + 178, + 0, + 8, + 9, + 0, + 8, + 137, + 0, + 8, + 73, + 0, + 9, + 242, + 80, + 7, + 4, + 0, + 8, + 85, + 0, + 8, + 21, + 80, + 8, + 258, + 83, + 7, + 43, + 0, + 8, + 117, + 0, + 8, + 53, + 0, + 9, + 202, + 81, + 7, + 13, + 0, + 8, + 101, + 0, + 8, + 37, + 0, + 9, + 170, + 0, + 8, + 5, + 0, + 8, + 133, + 0, + 8, + 69, + 0, + 9, + 234, + 80, + 7, + 8, + 0, + 8, + 93, + 0, + 8, + 29, + 0, + 9, + 154, + 84, + 7, + 83, + 0, + 8, + 125, + 0, + 8, + 61, + 0, + 9, + 218, + 82, + 7, + 23, + 0, + 8, + 109, + 0, + 8, + 45, + 0, + 9, + 186, + 0, + 8, + 13, + 0, + 8, + 141, + 0, + 8, + 77, + 0, + 9, + 250, + 80, + 7, + 3, + 0, + 8, + 83, + 0, + 8, + 19, + 85, + 8, + 195, + 83, + 7, + 35, + 0, + 8, + 115, + 0, + 8, + 51, + 0, + 9, + 198, + 81, + 7, + 11, + 0, + 8, + 99, + 0, + 8, + 35, + 0, + 9, + 166, + 0, + 8, + 3, + 0, + 8, + 131, + 0, + 8, + 67, + 0, + 9, + 230, + 80, + 7, + 7, + 0, + 8, + 91, + 0, + 8, + 27, + 0, + 9, + 150, + 84, + 7, + 67, + 0, + 8, + 123, + 0, + 8, + 59, + 0, + 9, + 214, + 82, + 7, + 19, + 0, + 8, + 107, + 0, + 8, + 43, + 0, + 9, + 182, + 0, + 8, + 11, + 0, + 8, + 139, + 0, + 8, + 75, + 0, + 9, + 246, + 80, + 7, + 5, + 0, + 8, + 87, + 0, + 8, + 23, + 192, + 8, + 0, + 83, + 7, + 51, + 0, + 8, + 119, + 0, + 8, + 55, + 0, + 9, + 206, + 81, + 7, + 15, + 0, + 8, + 103, + 0, + 8, + 39, + 0, + 9, + 174, + 0, + 8, + 7, + 0, + 8, + 135, + 0, + 8, + 71, + 0, + 9, + 238, + 80, + 7, + 9, + 0, + 8, + 95, + 0, + 8, + 31, + 0, + 9, + 158, + 84, + 7, + 99, + 0, + 8, + 127, + 0, + 8, + 63, + 0, + 9, + 222, + 82, + 7, + 27, + 0, + 8, + 111, + 0, + 8, + 47, + 0, + 9, + 190, + 0, + 8, + 15, + 0, + 8, + 143, + 0, + 8, + 79, + 0, + 9, + 254, + 96, + 7, + 256, + 0, + 8, + 80, + 0, + 8, + 16, + 84, + 8, + 115, + 82, + 7, + 31, + 0, + 8, + 112, + 0, + 8, + 48, + 0, + 9, + 193, + 80, + 7, + 10, + 0, + 8, + 96, + 0, + 8, + 32, + 0, + 9, + 161, + 0, + 8, + 0, + 0, + 8, + 128, + 0, + 8, + 64, + 0, + 9, + 225, + 80, + 7, + 6, + 0, + 8, + 88, + 0, + 8, + 24, + 0, + 9, + 145, + 83, + 7, + 59, + 0, + 8, + 120, + 0, + 8, + 56, + 0, + 9, + 209, + 81, + 7, + 17, + 0, + 8, + 104, + 0, + 8, + 40, + 0, + 9, + 177, + 0, + 8, + 8, + 0, + 8, + 136, + 0, + 8, + 72, + 0, + 9, + 241, + 80, + 7, + 4, + 0, + 8, + 84, + 0, + 8, + 20, + 85, + 8, + 227, + 83, + 7, + 43, + 0, + 8, + 116, + 0, + 8, + 52, + 0, + 9, + 201, + 81, + 7, + 13, + 0, + 8, + 100, + 0, + 8, + 36, + 0, + 9, + 169, + 0, + 8, + 4, + 0, + 8, + 132, + 0, + 8, + 68, + 0, + 9, + 233, + 80, + 7, + 8, + 0, + 8, + 92, + 0, + 8, + 28, + 0, + 9, + 153, + 84, + 7, + 83, + 0, + 8, + 124, + 0, + 8, + 60, + 0, + 9, + 217, + 82, + 7, + 23, + 0, + 8, + 108, + 0, + 8, + 44, + 0, + 9, + 185, + 0, + 8, + 12, + 0, + 8, + 140, + 0, + 8, + 76, + 0, + 9, + 249, + 80, + 7, + 3, + 0, + 8, + 82, + 0, + 8, + 18, + 85, + 8, + 163, + 83, + 7, + 35, + 0, + 8, + 114, + 0, + 8, + 50, + 0, + 9, + 197, + 81, + 7, + 11, + 0, + 8, + 98, + 0, + 8, + 34, + 0, + 9, + 165, + 0, + 8, + 2, + 0, + 8, + 130, + 0, + 8, + 66, + 0, + 9, + 229, + 80, + 7, + 7, + 0, + 8, + 90, + 0, + 8, + 26, + 0, + 9, + 149, + 84, + 7, + 67, + 0, + 8, + 122, + 0, + 8, + 58, + 0, + 9, + 213, + 82, + 7, + 19, + 0, + 8, + 106, + 0, + 8, + 42, + 0, + 9, + 181, + 0, + 8, + 10, + 0, + 8, + 138, + 0, + 8, + 74, + 0, + 9, + 245, + 80, + 7, + 5, + 0, + 8, + 86, + 0, + 8, + 22, + 192, + 8, + 0, + 83, + 7, + 51, + 0, + 8, + 118, + 0, + 8, + 54, + 0, + 9, + 205, + 81, + 7, + 15, + 0, + 8, + 102, + 0, + 8, + 38, + 0, + 9, + 173, + 0, + 8, + 6, + 0, + 8, + 134, + 0, + 8, + 70, + 0, + 9, + 237, + 80, + 7, + 9, + 0, + 8, + 94, + 0, + 8, + 30, + 0, + 9, + 157, + 84, + 7, + 99, + 0, + 8, + 126, + 0, + 8, + 62, + 0, + 9, + 221, + 82, + 7, + 27, + 0, + 8, + 110, + 0, + 8, + 46, + 0, + 9, + 189, + 0, + 8, + 14, + 0, + 8, + 142, + 0, + 8, + 78, + 0, + 9, + 253, + 96, + 7, + 256, + 0, + 8, + 81, + 0, + 8, + 17, + 85, + 8, + 131, + 82, + 7, + 31, + 0, + 8, + 113, + 0, + 8, + 49, + 0, + 9, + 195, + 80, + 7, + 10, + 0, + 8, + 97, + 0, + 8, + 33, + 0, + 9, + 163, + 0, + 8, + 1, + 0, + 8, + 129, + 0, + 8, + 65, + 0, + 9, + 227, + 80, + 7, + 6, + 0, + 8, + 89, + 0, + 8, + 25, + 0, + 9, + 147, + 83, + 7, + 59, + 0, + 8, + 121, + 0, + 8, + 57, + 0, + 9, + 211, + 81, + 7, + 17, + 0, + 8, + 105, + 0, + 8, + 41, + 0, + 9, + 179, + 0, + 8, + 9, + 0, + 8, + 137, + 0, + 8, + 73, + 0, + 9, + 243, + 80, + 7, + 4, + 0, + 8, + 85, + 0, + 8, + 21, + 80, + 8, + 258, + 83, + 7, + 43, + 0, + 8, + 117, + 0, + 8, + 53, + 0, + 9, + 203, + 81, + 7, + 13, + 0, + 8, + 101, + 0, + 8, + 37, + 0, + 9, + 171, + 0, + 8, + 5, + 0, + 8, + 133, + 0, + 8, + 69, + 0, + 9, + 235, + 80, + 7, + 8, + 0, + 8, + 93, + 0, + 8, + 29, + 0, + 9, + 155, + 84, + 7, + 83, + 0, + 8, + 125, + 0, + 8, + 61, + 0, + 9, + 219, + 82, + 7, + 23, + 0, + 8, + 109, + 0, + 8, + 45, + 0, + 9, + 187, + 0, + 8, + 13, + 0, + 8, + 141, + 0, + 8, + 77, + 0, + 9, + 251, + 80, + 7, + 3, + 0, + 8, + 83, + 0, + 8, + 19, + 85, + 8, + 195, + 83, + 7, + 35, + 0, + 8, + 115, + 0, + 8, + 51, + 0, + 9, + 199, + 81, + 7, + 11, + 0, + 8, + 99, + 0, + 8, + 35, + 0, + 9, + 167, + 0, + 8, + 3, + 0, + 8, + 131, + 0, + 8, + 67, + 0, + 9, + 231, + 80, + 7, + 7, + 0, + 8, + 91, + 0, + 8, + 27, + 0, + 9, + 151, + 84, + 7, + 67, + 0, + 8, + 123, + 0, + 8, + 59, + 0, + 9, + 215, + 82, + 7, + 19, + 0, + 8, + 107, + 0, + 8, + 43, + 0, + 9, + 183, + 0, + 8, + 11, + 0, + 8, + 139, + 0, + 8, + 75, + 0, + 9, + 247, + 80, + 7, + 5, + 0, + 8, + 87, + 0, + 8, + 23, + 192, + 8, + 0, + 83, + 7, + 51, + 0, + 8, + 119, + 0, + 8, + 55, + 0, + 9, + 207, + 81, + 7, + 15, + 0, + 8, + 103, + 0, + 8, + 39, + 0, + 9, + 175, + 0, + 8, + 7, + 0, + 8, + 135, + 0, + 8, + 71, + 0, + 9, + 239, + 80, + 7, + 9, + 0, + 8, + 95, + 0, + 8, + 31, + 0, + 9, + 159, + 84, + 7, + 99, + 0, + 8, + 127, + 0, + 8, + 63, + 0, + 9, + 223, + 82, + 7, + 27, + 0, + 8, + 111, + 0, + 8, + 47, + 0, + 9, + 191, + 0, + 8, + 15, + 0, + 8, + 143, + 0, + 8, + 79, + 0, + 9, + 255 + }; - private const int Z_OK = 0; - private const int Z_STREAM_END = 1; - private const int Z_NEED_DICT = 2; - private const int Z_ERRNO = -1; - private const int Z_STREAM_ERROR = -2; - private const int Z_DATA_ERROR = -3; - private const int Z_MEM_ERROR = -4; - private const int Z_BUF_ERROR = -5; - private const int Z_VERSION_ERROR = -6; + //UPGRADE_NOTE: Final was removed from the declaration of 'fixed_td'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + internal static readonly int[] fixed_td = + { + 80, + 5, + 1, + 87, + 5, + 257, + 83, + 5, + 17, + 91, + 5, + 4097, + 81, + 5, + 5, + 89, + 5, + 1025, + 85, + 5, + 65, + 93, + 5, + 16385, + 80, + 5, + 3, + 88, + 5, + 513, + 84, + 5, + 33, + 92, + 5, + 8193, + 82, + 5, + 9, + 90, + 5, + 2049, + 86, + 5, + 129, + 192, + 5, + 24577, + 80, + 5, + 2, + 87, + 5, + 385, + 83, + 5, + 25, + 91, + 5, + 6145, + 81, + 5, + 7, + 89, + 5, + 1537, + 85, + 5, + 97, + 93, + 5, + 24577, + 80, + 5, + 4, + 88, + 5, + 769, + 84, + 5, + 49, + 92, + 5, + 12289, + 82, + 5, + 13, + 90, + 5, + 3073, + 86, + 5, + 193, + 192, + 5, + 24577 + }; - internal const int fixed_bl = 9; - internal const int fixed_bd = 5; - internal const int BMAX = 15; // maximum bit length of any code + // Tables for deflate from PKZIP's appnote.txt. + //UPGRADE_NOTE: Final was removed from the declaration of 'cplens'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + internal static readonly int[] cplens = + { + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 13, + 15, + 17, + 19, + 23, + 27, + 31, + 35, + 43, + 51, + 59, + 67, + 83, + 99, + 115, + 131, + 163, + 195, + 227, + 258, + 0, + 0 + }; - //UPGRADE_NOTE: Final was removed from the declaration of 'fixed_tl'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - internal static readonly int[] fixed_tl = + // see note #13 above about 258 + //UPGRADE_NOTE: Final was removed from the declaration of 'cplext'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + internal static readonly int[] cplext = + { + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 4, + 4, + 4, + 4, + 5, + 5, + 5, + 5, + 0, + 112, + 112 + }; + + //UPGRADE_NOTE: Final was removed from the declaration of 'cpdist'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + internal static readonly int[] cpdist = + { + 1, + 2, + 3, + 4, + 5, + 7, + 9, + 13, + 17, + 25, + 33, + 49, + 65, + 97, + 129, + 193, + 257, + 385, + 513, + 769, + 1025, + 1537, + 2049, + 3073, + 4097, + 6145, + 8193, + 12289, + 16385, + 24577 + }; + + //UPGRADE_NOTE: Final was removed from the declaration of 'cpdext'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + internal static readonly int[] cpdext = + { + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 2, + 3, + 3, + 4, + 4, + 5, + 5, + 6, + 6, + 7, + 7, + 8, + 8, + 9, + 9, + 10, + 10, + 11, + 11, + 12, + 12, + 13, + 13 + }; + + // If BMAX needs to be larger than 16, then h and x[] should be uLong. + internal int[] c; // bit length count table + internal int[] hn; // hufts used in space + internal int[] r; // table entry for structure assignment + internal int[] u; // table stack + internal int[] v; // work area for huft_build + internal int[] x; // bit offsets, then code stack + + private int huft_build( + int[] b, + int bindex, + int n, + int s, + int[] d, + int[] e, + int[] t, + int[] m, + int[] hp, + int[] hn, + int[] v + ) + { + // Given a list of code lengths and a maximum table size, make a set of + // tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR + // if the given code set is incomplete (the tables are still built in this + // case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of + // lengths), or Z_MEM_ERROR if not enough memory. + + int a; // counter for codes of length k + int f; // i repeats in table every f entries + int g; // maximum code length + int h; // table level + int i; // counter, current code + int j; // counter + int k; // number of bits in current code + int l; // bits per table (returned in m) + int mask; // (1 << w) - 1, to avoid cc -O bug on HP + int p; // pointer into c[], b[], or v[] + int q; // points to current table + int w; // bits before this table == (l * h) + int xp; // pointer into x + int y; // number of dummy codes added + int z; // number of entries in current table + + // Generate counts for each bit length + + p = 0; + i = n; + do { - 96, - 7, - 256, - 0, - 8, - 80, - 0, - 8, - 16, - 84, - 8, - 115, - 82, - 7, - 31, - 0, - 8, - 112, - 0, - 8, - 48, - 0, - 9, - 192, - 80, - 7, - 10, - 0, - 8, - 96, - 0, - 8, - 32, - 0, - 9, - 160, - 0, - 8, - 0, - 0, - 8, - 128, - 0, - 8, - 64, - 0, - 9, - 224, - 80, - 7, - 6, - 0, - 8, - 88, - 0, - 8, - 24, - 0, - 9, - 144, - 83, - 7, - 59, - 0, - 8, - 120, - 0, - 8, - 56, - 0, - 9, - 208, - 81, - 7, - 17, - 0, - 8, - 104, - 0, - 8, - 40, - 0, - 9, - 176, - 0, - 8, - 8, - 0, - 8, - 136, - 0, - 8, - 72, - 0, - 9, - 240, - 80, - 7, - 4, - 0, - 8, - 84, - 0, - 8, - 20, - 85, - 8, - 227, - 83, - 7, - 43, - 0, - 8, - 116, - 0, - 8, - 52, - 0, - 9, - 200, - 81, - 7, - 13, - 0, - 8, - 100, - 0, - 8, - 36, - 0, - 9, - 168, - 0, - 8, - 4, - 0, - 8, - 132, - 0, - 8, - 68, - 0, - 9, - 232, - 80, - 7, - 8, - 0, - 8, - 92, - 0, - 8, - 28, - 0, - 9, - 152, - 84, - 7, - 83, - 0, - 8, - 124, - 0, - 8, - 60, - 0, - 9, - 216, - 82, - 7, - 23, - 0, - 8, - 108, - 0, - 8, - 44, - 0, - 9, - 184, - 0, - 8, - 12, - 0, - 8, - 140, - 0, - 8, - 76, - 0, - 9, - 248, - 80, - 7, - 3, - 0, - 8, - 82, - 0, - 8, - 18, - 85, - 8, - 163, - 83, - 7, - 35, - 0, - 8, - 114, - 0, - 8, - 50, - 0, - 9, - 196, - 81, - 7, - 11, - 0, - 8, - 98, - 0, - 8, - 34, - 0, - 9, - 164, - 0, - 8, - 2, - 0, - 8, - 130, - 0, - 8, - 66, - 0, - 9, - 228, - 80, - 7, - 7, - 0, - 8, - 90, - 0, - 8, - 26, - 0, - 9, - 148, - 84, - 7, - 67, - 0, - 8, - 122, - 0, - 8, - 58, - 0, - 9, - 212, - 82, - 7, - 19, - 0, - 8, - 106, - 0, - 8, - 42, - 0, - 9, - 180, - 0, - 8, - 10, - 0, - 8, - 138, - 0, - 8, - 74, - 0, - 9, - 244, - 80, - 7, - 5, - 0, - 8, - 86, - 0, - 8, - 22, - 192, - 8, - 0, - 83, - 7, - 51, - 0, - 8, - 118, - 0, - 8, - 54, - 0, - 9, - 204, - 81, - 7, - 15, - 0, - 8, - 102, - 0, - 8, - 38, - 0, - 9, - 172, - 0, - 8, - 6, - 0, - 8, - 134, - 0, - 8, - 70, - 0, - 9, - 236, - 80, - 7, - 9, - 0, - 8, - 94, - 0, - 8, - 30, - 0, - 9, - 156, - 84, - 7, - 99, - 0, - 8, - 126, - 0, - 8, - 62, - 0, - 9, - 220, - 82, - 7, - 27, - 0, - 8, - 110, - 0, - 8, - 46, - 0, - 9, - 188, - 0, - 8, - 14, - 0, - 8, - 142, - 0, - 8, - 78, - 0, - 9, - 252, - 96, - 7, - 256, - 0, - 8, - 81, - 0, - 8, - 17, - 85, - 8, - 131, - 82, - 7, - 31, - 0, - 8, - 113, - 0, - 8, - 49, - 0, - 9, - 194, - 80, - 7, - 10, - 0, - 8, - 97, - 0, - 8, - 33, - 0, - 9, - 162, - 0, - 8, - 1, - 0, - 8, - 129, - 0, - 8, - 65, - 0, - 9, - 226, - 80, - 7, - 6, - 0, - 8, - 89, - 0, - 8, - 25, - 0, - 9, - 146, - 83, - 7, - 59, - 0, - 8, - 121, - 0, - 8, - 57, - 0, - 9, - 210, - 81, - 7, - 17, - 0, - 8, - 105, - 0, - 8, - 41, - 0, - 9, - 178, - 0, - 8, - 9, - 0, - 8, - 137, - 0, - 8, - 73, - 0, - 9, - 242, - 80, - 7, - 4, - 0, - 8, - 85, - 0, - 8, - 21, - 80, - 8, - 258, - 83, - 7, - 43, - 0, - 8, - 117, - 0, - 8, - 53, - 0, - 9, - 202, - 81, - 7, - 13, - 0, - 8, - 101, - 0, - 8, - 37, - 0, - 9, - 170, - 0, - 8, - 5, - 0, - 8, - 133, - 0, - 8, - 69, - 0, - 9, - 234, - 80, - 7, - 8, - 0, - 8, - 93, - 0, - 8, - 29, - 0, - 9, - 154, - 84, - 7, - 83, - 0, - 8, - 125, - 0, - 8, - 61, - 0, - 9, - 218, - 82, - 7, - 23, - 0, - 8, - 109, - 0, - 8, - 45, - 0, - 9, - 186, - 0, - 8, - 13, - 0, - 8, - 141, - 0, - 8, - 77, - 0, - 9, - 250, - 80, - 7, - 3, - 0, - 8, - 83, - 0, - 8, - 19, - 85, - 8, - 195, - 83, - 7, - 35, - 0, - 8, - 115, - 0, - 8, - 51, - 0, - 9, - 198, - 81, - 7, - 11, - 0, - 8, - 99, - 0, - 8, - 35, - 0, - 9, - 166, - 0, - 8, - 3, - 0, - 8, - 131, - 0, - 8, - 67, - 0, - 9, - 230, - 80, - 7, - 7, - 0, - 8, - 91, - 0, - 8, - 27, - 0, - 9, - 150, - 84, - 7, - 67, - 0, - 8, - 123, - 0, - 8, - 59, - 0, - 9, - 214, - 82, - 7, - 19, - 0, - 8, - 107, - 0, - 8, - 43, - 0, - 9, - 182, - 0, - 8, - 11, - 0, - 8, - 139, - 0, - 8, - 75, - 0, - 9, - 246, - 80, - 7, - 5, - 0, - 8, - 87, - 0, - 8, - 23, - 192, - 8, - 0, - 83, - 7, - 51, - 0, - 8, - 119, - 0, - 8, - 55, - 0, - 9, - 206, - 81, - 7, - 15, - 0, - 8, - 103, - 0, - 8, - 39, - 0, - 9, - 174, - 0, - 8, - 7, - 0, - 8, - 135, - 0, - 8, - 71, - 0, - 9, - 238, - 80, - 7, - 9, - 0, - 8, - 95, - 0, - 8, - 31, - 0, - 9, - 158, - 84, - 7, - 99, - 0, - 8, - 127, - 0, - 8, - 63, - 0, - 9, - 222, - 82, - 7, - 27, - 0, - 8, - 111, - 0, - 8, - 47, - 0, - 9, - 190, - 0, - 8, - 15, - 0, - 8, - 143, - 0, - 8, - 79, - 0, - 9, - 254, - 96, - 7, - 256, - 0, - 8, - 80, - 0, - 8, - 16, - 84, - 8, - 115, - 82, - 7, - 31, - 0, - 8, - 112, - 0, - 8, - 48, - 0, - 9, - 193, - 80, - 7, - 10, - 0, - 8, - 96, - 0, - 8, - 32, - 0, - 9, - 161, - 0, - 8, - 0, - 0, - 8, - 128, - 0, - 8, - 64, - 0, - 9, - 225, - 80, - 7, - 6, - 0, - 8, - 88, - 0, - 8, - 24, - 0, - 9, - 145, - 83, - 7, - 59, - 0, - 8, - 120, - 0, - 8, - 56, - 0, - 9, - 209, - 81, - 7, - 17, - 0, - 8, - 104, - 0, - 8, - 40, - 0, - 9, - 177, - 0, - 8, - 8, - 0, - 8, - 136, - 0, - 8, - 72, - 0, - 9, - 241, - 80, - 7, - 4, - 0, - 8, - 84, - 0, - 8, - 20, - 85, - 8, - 227, - 83, - 7, - 43, - 0, - 8, - 116, - 0, - 8, - 52, - 0, - 9, - 201, - 81, - 7, - 13, - 0, - 8, - 100, - 0, - 8, - 36, - 0, - 9, - 169, - 0, - 8, - 4, - 0, - 8, - 132, - 0, - 8, - 68, - 0, - 9, - 233, - 80, - 7, - 8, - 0, - 8, - 92, - 0, - 8, - 28, - 0, - 9, - 153, - 84, - 7, - 83, - 0, - 8, - 124, - 0, - 8, - 60, - 0, - 9, - 217, - 82, - 7, - 23, - 0, - 8, - 108, - 0, - 8, - 44, - 0, - 9, - 185, - 0, - 8, - 12, - 0, - 8, - 140, - 0, - 8, - 76, - 0, - 9, - 249, - 80, - 7, - 3, - 0, - 8, - 82, - 0, - 8, - 18, - 85, - 8, - 163, - 83, - 7, - 35, - 0, - 8, - 114, - 0, - 8, - 50, - 0, - 9, - 197, - 81, - 7, - 11, - 0, - 8, - 98, - 0, - 8, - 34, - 0, - 9, - 165, - 0, - 8, - 2, - 0, - 8, - 130, - 0, - 8, - 66, - 0, - 9, - 229, - 80, - 7, - 7, - 0, - 8, - 90, - 0, - 8, - 26, - 0, - 9, - 149, - 84, - 7, - 67, - 0, - 8, - 122, - 0, - 8, - 58, - 0, - 9, - 213, - 82, - 7, - 19, - 0, - 8, - 106, - 0, - 8, - 42, - 0, - 9, - 181, - 0, - 8, - 10, - 0, - 8, - 138, - 0, - 8, - 74, - 0, - 9, - 245, - 80, - 7, - 5, - 0, - 8, - 86, - 0, - 8, - 22, - 192, - 8, - 0, - 83, - 7, - 51, - 0, - 8, - 118, - 0, - 8, - 54, - 0, - 9, - 205, - 81, - 7, - 15, - 0, - 8, - 102, - 0, - 8, - 38, - 0, - 9, - 173, - 0, - 8, - 6, - 0, - 8, - 134, - 0, - 8, - 70, - 0, - 9, - 237, - 80, - 7, - 9, - 0, - 8, - 94, - 0, - 8, - 30, - 0, - 9, - 157, - 84, - 7, - 99, - 0, - 8, - 126, - 0, - 8, - 62, - 0, - 9, - 221, - 82, - 7, - 27, - 0, - 8, - 110, - 0, - 8, - 46, - 0, - 9, - 189, - 0, - 8, - 14, - 0, - 8, - 142, - 0, - 8, - 78, - 0, - 9, - 253, - 96, - 7, - 256, - 0, - 8, - 81, - 0, - 8, - 17, - 85, - 8, - 131, - 82, - 7, - 31, - 0, - 8, - 113, - 0, - 8, - 49, - 0, - 9, - 195, - 80, - 7, - 10, - 0, - 8, - 97, - 0, - 8, - 33, - 0, - 9, - 163, - 0, - 8, - 1, - 0, - 8, - 129, - 0, - 8, - 65, - 0, - 9, - 227, - 80, - 7, - 6, - 0, - 8, - 89, - 0, - 8, - 25, - 0, - 9, - 147, - 83, - 7, - 59, - 0, - 8, - 121, - 0, - 8, - 57, - 0, - 9, - 211, - 81, - 7, - 17, - 0, - 8, - 105, - 0, - 8, - 41, - 0, - 9, - 179, - 0, - 8, - 9, - 0, - 8, - 137, - 0, - 8, - 73, - 0, - 9, - 243, - 80, - 7, - 4, - 0, - 8, - 85, - 0, - 8, - 21, - 80, - 8, - 258, - 83, - 7, - 43, - 0, - 8, - 117, - 0, - 8, - 53, - 0, - 9, - 203, - 81, - 7, - 13, - 0, - 8, - 101, - 0, - 8, - 37, - 0, - 9, - 171, - 0, - 8, - 5, - 0, - 8, - 133, - 0, - 8, - 69, - 0, - 9, - 235, - 80, - 7, - 8, - 0, - 8, - 93, - 0, - 8, - 29, - 0, - 9, - 155, - 84, - 7, - 83, - 0, - 8, - 125, - 0, - 8, - 61, - 0, - 9, - 219, - 82, - 7, - 23, - 0, - 8, - 109, - 0, - 8, - 45, - 0, - 9, - 187, - 0, - 8, - 13, - 0, - 8, - 141, - 0, - 8, - 77, - 0, - 9, - 251, - 80, - 7, - 3, - 0, - 8, - 83, - 0, - 8, - 19, - 85, - 8, - 195, - 83, - 7, - 35, - 0, - 8, - 115, - 0, - 8, - 51, - 0, - 9, - 199, - 81, - 7, - 11, - 0, - 8, - 99, - 0, - 8, - 35, - 0, - 9, - 167, - 0, - 8, - 3, - 0, - 8, - 131, - 0, - 8, - 67, - 0, - 9, - 231, - 80, - 7, - 7, - 0, - 8, - 91, - 0, - 8, - 27, - 0, - 9, - 151, - 84, - 7, - 67, - 0, - 8, - 123, - 0, - 8, - 59, - 0, - 9, - 215, - 82, - 7, - 19, - 0, - 8, - 107, - 0, - 8, - 43, - 0, - 9, - 183, - 0, - 8, - 11, - 0, - 8, - 139, - 0, - 8, - 75, - 0, - 9, - 247, - 80, - 7, - 5, - 0, - 8, - 87, - 0, - 8, - 23, - 192, - 8, - 0, - 83, - 7, - 51, - 0, - 8, - 119, - 0, - 8, - 55, - 0, - 9, - 207, - 81, - 7, - 15, - 0, - 8, - 103, - 0, - 8, - 39, - 0, - 9, - 175, - 0, - 8, - 7, - 0, - 8, - 135, - 0, - 8, - 71, - 0, - 9, - 239, - 80, - 7, - 9, - 0, - 8, - 95, - 0, - 8, - 31, - 0, - 9, - 159, - 84, - 7, - 99, - 0, - 8, - 127, - 0, - 8, - 63, - 0, - 9, - 223, - 82, - 7, - 27, - 0, - 8, - 111, - 0, - 8, - 47, - 0, - 9, - 191, - 0, - 8, - 15, - 0, - 8, - 143, - 0, - 8, - 79, - 0, - 9, - 255 - }; + c[b[bindex + p]]++; + p++; + i--; // assume all entries <= BMAX + } while (i != 0); - //UPGRADE_NOTE: Final was removed from the declaration of 'fixed_td'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - internal static readonly int[] fixed_td = + if (c[0] == n) { - 80, - 5, - 1, - 87, - 5, - 257, - 83, - 5, - 17, - 91, - 5, - 4097, - 81, - 5, - 5, - 89, - 5, - 1025, - 85, - 5, - 65, - 93, - 5, - 16385, - 80, - 5, - 3, - 88, - 5, - 513, - 84, - 5, - 33, - 92, - 5, - 8193, - 82, - 5, - 9, - 90, - 5, - 2049, - 86, - 5, - 129, - 192, - 5, - 24577, - 80, - 5, - 2, - 87, - 5, - 385, - 83, - 5, - 25, - 91, - 5, - 6145, - 81, - 5, - 7, - 89, - 5, - 1537, - 85, - 5, - 97, - 93, - 5, - 24577, - 80, - 5, - 4, - 88, - 5, - 769, - 84, - 5, - 49, - 92, - 5, - 12289, - 82, - 5, - 13, - 90, - 5, - 3073, - 86, - 5, - 193, - 192, - 5, - 24577 - }; + // null input--all zero length codes + t[0] = -1; + m[0] = 0; + return Z_OK; + } - // Tables for deflate from PKZIP's appnote.txt. - //UPGRADE_NOTE: Final was removed from the declaration of 'cplens'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - internal static readonly int[] cplens = + // Find minimum and maximum length, bound *m by those + l = m[0]; + for (j = 1; j <= BMAX; j++) { - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 13, - 15, - 17, - 19, - 23, - 27, - 31, - 35, - 43, - 51, - 59, - 67, - 83, - 99, - 115, - 131, - 163, - 195, - 227, - 258, - 0, - 0 - }; - - // see note #13 above about 258 - //UPGRADE_NOTE: Final was removed from the declaration of 'cplext'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - internal static readonly int[] cplext = - { - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1, - 1, - 1, - 1, - 2, - 2, - 2, - 2, - 3, - 3, - 3, - 3, - 4, - 4, - 4, - 4, - 5, - 5, - 5, - 5, - 0, - 112, - 112 - }; - - //UPGRADE_NOTE: Final was removed from the declaration of 'cpdist'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - internal static readonly int[] cpdist = - { - 1, - 2, - 3, - 4, - 5, - 7, - 9, - 13, - 17, - 25, - 33, - 49, - 65, - 97, - 129, - 193, - 257, - 385, - 513, - 769, - 1025, - 1537, - 2049, - 3073, - 4097, - 6145, - 8193, - 12289, - 16385, - 24577 - }; - - //UPGRADE_NOTE: Final was removed from the declaration of 'cpdext'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - internal static readonly int[] cpdext = - { - 0, - 0, - 0, - 0, - 1, - 1, - 2, - 2, - 3, - 3, - 4, - 4, - 5, - 5, - 6, - 6, - 7, - 7, - 8, - 8, - 9, - 9, - 10, - 10, - 11, - 11, - 12, - 12, - 13, - 13 - }; - - // If BMAX needs to be larger than 16, then h and x[] should be uLong. - internal int[] c; // bit length count table - internal int[] hn; // hufts used in space - internal int[] r; // table entry for structure assignment - internal int[] u; // table stack - internal int[] v; // work area for huft_build - internal int[] x; // bit offsets, then code stack - - private int huft_build( - int[] b, - int bindex, - int n, - int s, - int[] d, - int[] e, - int[] t, - int[] m, - int[] hp, - int[] hn, - int[] v - ) - { - // Given a list of code lengths and a maximum table size, make a set of - // tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR - // if the given code set is incomplete (the tables are still built in this - // case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of - // lengths), or Z_MEM_ERROR if not enough memory. - - int a; // counter for codes of length k - int f; // i repeats in table every f entries - int g; // maximum code length - int h; // table level - int i; // counter, current code - int j; // counter - int k; // number of bits in current code - int l; // bits per table (returned in m) - int mask; // (1 << w) - 1, to avoid cc -O bug on HP - int p; // pointer into c[], b[], or v[] - int q; // points to current table - int w; // bits before this table == (l * h) - int xp; // pointer into x - int y; // number of dummy codes added - int z; // number of entries in current table - - // Generate counts for each bit length - - p = 0; - i = n; - do + if (c[j] != 0) { - c[b[bindex + p]]++; - p++; - i--; // assume all entries <= BMAX - } while (i != 0); - - if (c[0] == n) - { - // null input--all zero length codes - t[0] = -1; - m[0] = 0; - return Z_OK; + break; } + } + k = j; // minimum code length + if (l < j) + { + l = j; + } + for (i = BMAX; i != 0; i--) + { + if (c[i] != 0) + { + break; + } + } + g = i; // maximum code length + if (l > i) + { + l = i; + } + m[0] = l; - // Find minimum and maximum length, bound *m by those - l = m[0]; - for (j = 1; j <= BMAX; j++) - { - if (c[j] != 0) - { - break; - } - } - k = j; // minimum code length - if (l < j) - { - l = j; - } - for (i = BMAX; i != 0; i--) - { - if (c[i] != 0) - { - break; - } - } - g = i; // maximum code length - if (l > i) - { - l = i; - } - m[0] = l; - - // Adjust last length count to fill out codes, if needed - for (y = 1 << j; j < i; j++, y <<= 1) - { - if ((y -= c[j]) < 0) - { - return Z_DATA_ERROR; - } - } - if ((y -= c[i]) < 0) + // Adjust last length count to fill out codes, if needed + for (y = 1 << j; j < i; j++, y <<= 1) + { + if ((y -= c[j]) < 0) { return Z_DATA_ERROR; } - c[i] += y; + } + if ((y -= c[i]) < 0) + { + return Z_DATA_ERROR; + } + c[i] += y; - // Generate starting offsets into the value table for each length - x[1] = j = 0; - p = 1; - xp = 2; - while (--i != 0) + // Generate starting offsets into the value table for each length + x[1] = j = 0; + p = 1; + xp = 2; + while (--i != 0) + { + // note that i == g from above + x[xp] = (j += c[p]); + xp++; + p++; + } + + // Make a table of values in order of bit lengths + i = 0; + p = 0; + do + { + if ((j = b[bindex + p]) != 0) { - // note that i == g from above - x[xp] = (j += c[p]); - xp++; - p++; + v[x[j]++] = i; } + p++; + } while (++i < n); + n = x[g]; // set n to length of v - // Make a table of values in order of bit lengths - i = 0; - p = 0; - do + // Generate the Huffman codes and for each, make the table entries + x[0] = i = 0; // first Huffman code is zero + p = 0; // grab values in bit order + h = -1; // no tables yet--level -1 + w = -l; // bits decoded == (l * h) + u[0] = 0; // just to keep compilers happy + q = 0; // ditto + z = 0; // ditto + + // go through the bit lengths (k already is bits in shortest code) + for (; k <= g; k++) + { + a = c[k]; + while (a-- != 0) { - if ((j = b[bindex + p]) != 0) + // here i is the Huffman code of length k bits for value *p + // make tables up to required level + while (k > w + l) { - v[x[j]++] = i; - } - p++; - } while (++i < n); - n = x[g]; // set n to length of v + h++; + w += l; // previous table always l bits - // Generate the Huffman codes and for each, make the table entries - x[0] = i = 0; // first Huffman code is zero - p = 0; // grab values in bit order - h = -1; // no tables yet--level -1 - w = -l; // bits decoded == (l * h) - u[0] = 0; // just to keep compilers happy - q = 0; // ditto - z = 0; // ditto - - // go through the bit lengths (k already is bits in shortest code) - for (; k <= g; k++) - { - a = c[k]; - while (a-- != 0) - { - // here i is the Huffman code of length k bits for value *p - // make tables up to required level - while (k > w + l) + // compute minimum size table less than or equal to l bits + z = g - w; + z = (z > l) ? l : z; // table size upper limit + if ((f = 1 << (j = k - w)) > a + 1) { - h++; - w += l; // previous table always l bits - - // compute minimum size table less than or equal to l bits - z = g - w; - z = (z > l) ? l : z; // table size upper limit - if ((f = 1 << (j = k - w)) > a + 1) + // try a k-w bit table + // too few codes for k-w bit table + f -= (a + 1); // deduct codes from patterns left + xp = k; + if (j < z) { - // try a k-w bit table - // too few codes for k-w bit table - f -= (a + 1); // deduct codes from patterns left - xp = k; - if (j < z) + while (++j < z) { - while (++j < z) + // try smaller tables up to z bits + if ((f <<= 1) <= c[++xp]) { - // try smaller tables up to z bits - if ((f <<= 1) <= c[++xp]) - { - break; // enough codes to use up j bits - } - f -= c[xp]; // else deduct codes from patterns + break; // enough codes to use up j bits } + f -= c[xp]; // else deduct codes from patterns } } - z = 1 << j; // table entries for j-bit table - - // allocate new table - if (hn[0] + z > MANY) - { - // (note: doesn't matter for fixed) - return Z_DATA_ERROR; // overflow of MANY - } - u[h] = q = hn[0]; // DEBUG - hn[0] += z; - - // connect to last table, if there is one - if (h != 0) - { - x[h] = i; // save pattern for backing up - r[0] = (sbyte)j; // bits in this table - r[1] = (sbyte)l; // bits to dump before this table - j = SharedUtils.URShift(i, (w - l)); - r[2] = (q - u[h - 1] - j); // offset to this table - Array.Copy(r, 0, hp, (u[h - 1] + j) * 3, 3); // connect to last table - } - else - { - t[0] = q; // first table is returned result - } } + z = 1 << j; // table entries for j-bit table - // set up table entry in r - r[1] = (sbyte)(k - w); - if (p >= n) + // allocate new table + if (hn[0] + z > MANY) { - r[0] = 128 + 64; // out of values--invalid code + // (note: doesn't matter for fixed) + return Z_DATA_ERROR; // overflow of MANY } - else if (v[p] < s) + u[h] = q = hn[0]; // DEBUG + hn[0] += z; + + // connect to last table, if there is one + if (h != 0) { - r[0] = (sbyte)(v[p] < 256 ? 0 : 32 + 64); // 256 is end-of-block - r[2] = v[p++]; // simple code is just the value + x[h] = i; // save pattern for backing up + r[0] = (sbyte)j; // bits in this table + r[1] = (sbyte)l; // bits to dump before this table + j = SharedUtils.URShift(i, (w - l)); + r[2] = (q - u[h - 1] - j); // offset to this table + Array.Copy(r, 0, hp, (u[h - 1] + j) * 3, 3); // connect to last table } else { - r[0] = (sbyte)(e[v[p] - s] + 16 + 64); // non-simple--look up in lists - r[2] = d[v[p++] - s]; - } - - // fill code-like entries with r - f = 1 << (k - w); - for (j = SharedUtils.URShift(i, w); j < z; j += f) - { - Array.Copy(r, 0, hp, (q + j) * 3, 3); - } - - // backwards increment the k-bit code i - for (j = 1 << (k - 1); (i & j) != 0; j = SharedUtils.URShift(j, 1)) - { - i ^= j; - } - i ^= j; - - // backup over finished tables - mask = (1 << w) - 1; // needed on HP, cc -O bug - while ((i & mask) != x[h]) - { - h--; // don't need to update q - w -= l; - mask = (1 << w) - 1; + t[0] = q; // first table is returned result } } - } - // Return Z_BUF_ERROR if we were given an incomplete table - return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK; + // set up table entry in r + r[1] = (sbyte)(k - w); + if (p >= n) + { + r[0] = 128 + 64; // out of values--invalid code + } + else if (v[p] < s) + { + r[0] = (sbyte)(v[p] < 256 ? 0 : 32 + 64); // 256 is end-of-block + r[2] = v[p++]; // simple code is just the value + } + else + { + r[0] = (sbyte)(e[v[p] - s] + 16 + 64); // non-simple--look up in lists + r[2] = d[v[p++] - s]; + } + + // fill code-like entries with r + f = 1 << (k - w); + for (j = SharedUtils.URShift(i, w); j < z; j += f) + { + Array.Copy(r, 0, hp, (q + j) * 3, 3); + } + + // backwards increment the k-bit code i + for (j = 1 << (k - 1); (i & j) != 0; j = SharedUtils.URShift(j, 1)) + { + i ^= j; + } + i ^= j; + + // backup over finished tables + mask = (1 << w) - 1; // needed on HP, cc -O bug + while ((i & mask) != x[h]) + { + h--; // don't need to update q + w -= l; + mask = (1 << w) - 1; + } + } } - internal int inflate_trees_bits(int[] c, int[] bb, int[] tb, int[] hp, ZlibCodec z) - { - int result; - initWorkArea(19); - hn[0] = 0; - result = huft_build(c, 0, 19, 19, null, null, tb, bb, hp, hn, v); + // Return Z_BUF_ERROR if we were given an incomplete table + return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK; + } + internal int inflate_trees_bits(int[] c, int[] bb, int[] tb, int[] hp, ZlibCodec z) + { + int result; + initWorkArea(19); + hn[0] = 0; + result = huft_build(c, 0, 19, 19, null, null, tb, bb, hp, hn, v); + + if (result == Z_DATA_ERROR) + { + z.Message = "oversubscribed dynamic bit lengths tree"; + } + else if (result == Z_BUF_ERROR || bb[0] == 0) + { + z.Message = "incomplete dynamic bit lengths tree"; + result = Z_DATA_ERROR; + } + return result; + } + + internal int inflate_trees_dynamic( + int nl, + int nd, + int[] c, + int[] bl, + int[] bd, + int[] tl, + int[] td, + int[] hp, + ZlibCodec z + ) + { + int result; + + // build literal/length tree + initWorkArea(288); + hn[0] = 0; + result = huft_build(c, 0, nl, 257, cplens, cplext, tl, bl, hp, hn, v); + if (result != Z_OK || bl[0] == 0) + { if (result == Z_DATA_ERROR) { - z.Message = "oversubscribed dynamic bit lengths tree"; + z.Message = "oversubscribed literal/length tree"; } - else if (result == Z_BUF_ERROR || bb[0] == 0) + else if (result != Z_MEM_ERROR) { - z.Message = "incomplete dynamic bit lengths tree"; + z.Message = "incomplete literal/length tree"; result = Z_DATA_ERROR; } return result; } - internal int inflate_trees_dynamic( - int nl, - int nd, - int[] c, - int[] bl, - int[] bd, - int[] tl, - int[] td, - int[] hp, - ZlibCodec z - ) + // build distance tree + initWorkArea(288); + result = huft_build(c, nl, nd, 0, cpdist, cpdext, td, bd, hp, hn, v); + + if (result != Z_OK || (bd[0] == 0 && nl > 257)) { - int result; - - // build literal/length tree - initWorkArea(288); - hn[0] = 0; - result = huft_build(c, 0, nl, 257, cplens, cplext, tl, bl, hp, hn, v); - if (result != Z_OK || bl[0] == 0) + if (result == Z_DATA_ERROR) { - if (result == Z_DATA_ERROR) - { - z.Message = "oversubscribed literal/length tree"; - } - else if (result != Z_MEM_ERROR) - { - z.Message = "incomplete literal/length tree"; - result = Z_DATA_ERROR; - } - return result; + z.Message = "oversubscribed distance tree"; } - - // build distance tree - initWorkArea(288); - result = huft_build(c, nl, nd, 0, cpdist, cpdext, td, bd, hp, hn, v); - - if (result != Z_OK || (bd[0] == 0 && nl > 257)) + else if (result == Z_BUF_ERROR) { - if (result == Z_DATA_ERROR) - { - z.Message = "oversubscribed distance tree"; - } - else if (result == Z_BUF_ERROR) - { - z.Message = "incomplete distance tree"; - result = Z_DATA_ERROR; - } - else if (result != Z_MEM_ERROR) - { - z.Message = "empty distance tree with lengths"; - result = Z_DATA_ERROR; - } - return result; + z.Message = "incomplete distance tree"; + result = Z_DATA_ERROR; } - - return Z_OK; + else if (result != Z_MEM_ERROR) + { + z.Message = "empty distance tree with lengths"; + result = Z_DATA_ERROR; + } + return result; } - internal static int inflate_trees_fixed( - int[] bl, - int[] bd, - int[][] tl, - int[][] td, - ZlibCodec z - ) - { - bl[0] = fixed_bl; - bd[0] = fixed_bd; - tl[0] = fixed_tl; - td[0] = fixed_td; - return Z_OK; - } + return Z_OK; + } - private void initWorkArea(int vsize) + internal static int inflate_trees_fixed( + int[] bl, + int[] bd, + int[][] tl, + int[][] td, + ZlibCodec z + ) + { + bl[0] = fixed_bl; + bd[0] = fixed_bd; + tl[0] = fixed_tl; + td[0] = fixed_td; + return Z_OK; + } + + private void initWorkArea(int vsize) + { + if (hn is null) { - if (hn is null) + hn = new int[1]; + v = new int[vsize]; + c = new int[BMAX + 1]; + r = new int[3]; + u = new int[BMAX]; + x = new int[BMAX + 1]; + } + else + { + if (v.Length < vsize) { - hn = new int[1]; v = new int[vsize]; - c = new int[BMAX + 1]; - r = new int[3]; - u = new int[BMAX]; - x = new int[BMAX + 1]; } - else - { - if (v.Length < vsize) - { - v = new int[vsize]; - } - Array.Clear(v, 0, vsize); - Array.Clear(c, 0, BMAX + 1); - r[0] = 0; - r[1] = 0; - r[2] = 0; + Array.Clear(v, 0, vsize); + Array.Clear(c, 0, BMAX + 1); + r[0] = 0; + r[1] = 0; + r[2] = 0; - // for(int i=0; i> 1) + { + case 0: // stored + b >>= 3; + k -= (3); + t = k & 7; // go to byte boundary + b >>= t; + k -= t; + mode = InflateBlockMode.LENS; // get length of stored block + break; - q = writeAt; - m = (q < readAt ? readAt - q - 1 : end - q); + case 1: // fixed + var bl = new int[1]; + var bd = new int[1]; + var tl = new int[1][]; + var td = new int[1][]; + InfTree.inflate_trees_fixed(bl, bd, tl, td, _codec); + codes.Init(bl[0], bd[0], tl[0], 0, td[0], 0); + b >>= 3; + k -= 3; + mode = InflateBlockMode.CODES; + break; - // process input based on current state - while (true) - { - switch (mode) - { - case InflateBlockMode.TYPE: + case 2: // dynamic + b >>= 3; + k -= 3; + mode = InflateBlockMode.TABLE; + break; + case 3: // illegal + b >>= 3; + k -= 3; + mode = InflateBlockMode.BAD; + _codec.Message = "invalid block type"; + r = ZlibConstants.Z_DATA_ERROR; + bitb = b; + bitk = k; + _codec.AvailableBytesIn = n; + _codec.TotalBytesIn += p - _codec.NextIn; + _codec.NextIn = p; + writeAt = q; + return Flush(r); + } + break; + + case InflateBlockMode.LENS: + + while (k < (32)) + { + if (n != 0) + { + r = ZlibConstants.Z_OK; + } + else + { + bitb = b; + bitk = k; + _codec.AvailableBytesIn = n; + _codec.TotalBytesIn += p - _codec.NextIn; + _codec.NextIn = p; + writeAt = q; + return Flush(r); + } + ; + n--; + b |= (_codec.InputBuffer[p++] & 0xff) << k; + k += 8; + } + + if ((((~b) >> 16) & 0xffff) != (b & 0xffff)) + { + mode = InflateBlockMode.BAD; + _codec.Message = "invalid stored block lengths"; + r = ZlibConstants.Z_DATA_ERROR; + + bitb = b; + bitk = k; + _codec.AvailableBytesIn = n; + _codec.TotalBytesIn += p - _codec.NextIn; + _codec.NextIn = p; + writeAt = q; + return Flush(r); + } + left = (b & 0xffff); + b = k = 0; // dump bits + mode = + left != 0 + ? InflateBlockMode.STORED + : (last != 0 ? InflateBlockMode.DRY : InflateBlockMode.TYPE); + break; + + case InflateBlockMode.STORED: + if (n == 0) + { + bitb = b; + bitk = k; + _codec.AvailableBytesIn = n; + _codec.TotalBytesIn += p - _codec.NextIn; + _codec.NextIn = p; + writeAt = q; + return Flush(r); + } + + if (m == 0) + { + if (q == end && readAt != 0) + { + q = 0; + m = (q < readAt ? readAt - q - 1 : end - q); + } + if (m == 0) + { + writeAt = q; + r = Flush(r); + q = writeAt; + m = (q < readAt ? readAt - q - 1 : end - q); + if (q == end && readAt != 0) + { + q = 0; + m = (q < readAt ? readAt - q - 1 : end - q); + } + if (m == 0) + { + bitb = b; + bitk = k; + _codec.AvailableBytesIn = n; + _codec.TotalBytesIn += p - _codec.NextIn; + _codec.NextIn = p; + writeAt = q; + return Flush(r); + } + } + } + r = ZlibConstants.Z_OK; + + t = left; + if (t > n) + { + t = n; + } + if (t > m) + { + t = m; + } + Array.Copy(_codec.InputBuffer, p, window, q, t); + p += t; + n -= t; + q += t; + m -= t; + if ((left -= t) != 0) + { + break; + } + mode = last != 0 ? InflateBlockMode.DRY : InflateBlockMode.TYPE; + break; + + case InflateBlockMode.TABLE: + + while (k < (14)) + { + if (n != 0) + { + r = ZlibConstants.Z_OK; + } + else + { + bitb = b; + bitk = k; + _codec.AvailableBytesIn = n; + _codec.TotalBytesIn += p - _codec.NextIn; + _codec.NextIn = p; + writeAt = q; + return Flush(r); + } + + n--; + b |= (_codec.InputBuffer[p++] & 0xff) << k; + k += 8; + } + + table = t = (b & 0x3fff); + if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29) + { + mode = InflateBlockMode.BAD; + _codec.Message = "too many length or distance symbols"; + r = ZlibConstants.Z_DATA_ERROR; + + bitb = b; + bitk = k; + _codec.AvailableBytesIn = n; + _codec.TotalBytesIn += p - _codec.NextIn; + _codec.NextIn = p; + writeAt = q; + return Flush(r); + } + t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f); + if (blens is null || blens.Length < t) + { + blens = new int[t]; + } + else + { + Array.Clear(blens, 0, t); + + // for (int i = 0; i < t; i++) + // { + // blens[i] = 0; + // } + } + + b >>= 14; + k -= 14; + + index = 0; + mode = InflateBlockMode.BTREE; + goto case InflateBlockMode.BTREE; + + case InflateBlockMode.BTREE: + while (index < 4 + (table >> 10)) + { while (k < (3)) { if (n != 0) @@ -194,168 +438,58 @@ namespace SharpCompress.Compressors.Deflate b |= (_codec.InputBuffer[p++] & 0xff) << k; k += 8; } - t = (b & 7); - last = t & 1; - switch ((uint)t >> 1) - { - case 0: // stored - b >>= 3; - k -= (3); - t = k & 7; // go to byte boundary - b >>= t; - k -= t; - mode = InflateBlockMode.LENS; // get length of stored block - break; - - case 1: // fixed - var bl = new int[1]; - var bd = new int[1]; - var tl = new int[1][]; - var td = new int[1][]; - InfTree.inflate_trees_fixed(bl, bd, tl, td, _codec); - codes.Init(bl[0], bd[0], tl[0], 0, td[0], 0); - b >>= 3; - k -= 3; - mode = InflateBlockMode.CODES; - break; - - case 2: // dynamic - b >>= 3; - k -= 3; - mode = InflateBlockMode.TABLE; - break; - - case 3: // illegal - b >>= 3; - k -= 3; - mode = InflateBlockMode.BAD; - _codec.Message = "invalid block type"; - r = ZlibConstants.Z_DATA_ERROR; - bitb = b; - bitk = k; - _codec.AvailableBytesIn = n; - _codec.TotalBytesIn += p - _codec.NextIn; - _codec.NextIn = p; - writeAt = q; - return Flush(r); - } - break; - - case InflateBlockMode.LENS: - - while (k < (32)) - { - if (n != 0) - { - r = ZlibConstants.Z_OK; - } - else - { - bitb = b; - bitk = k; - _codec.AvailableBytesIn = n; - _codec.TotalBytesIn += p - _codec.NextIn; - _codec.NextIn = p; - writeAt = q; - return Flush(r); - } - ; - n--; - b |= (_codec.InputBuffer[p++] & 0xff) << k; - k += 8; - } - - if ((((~b) >> 16) & 0xffff) != (b & 0xffff)) + blens[border[index++]] = b & 7; + + b >>= 3; + k -= 3; + } + + while (index < 19) + { + blens[border[index++]] = 0; + } + + bb[0] = 7; + t = inftree.inflate_trees_bits(blens, bb, tb, hufts, _codec); + if (t != ZlibConstants.Z_OK) + { + r = t; + if (r == ZlibConstants.Z_DATA_ERROR) { + blens = null; mode = InflateBlockMode.BAD; - _codec.Message = "invalid stored block lengths"; - r = ZlibConstants.Z_DATA_ERROR; - - bitb = b; - bitk = k; - _codec.AvailableBytesIn = n; - _codec.TotalBytesIn += p - _codec.NextIn; - _codec.NextIn = p; - writeAt = q; - return Flush(r); - } - left = (b & 0xffff); - b = k = 0; // dump bits - mode = - left != 0 - ? InflateBlockMode.STORED - : (last != 0 ? InflateBlockMode.DRY : InflateBlockMode.TYPE); - break; - - case InflateBlockMode.STORED: - if (n == 0) - { - bitb = b; - bitk = k; - _codec.AvailableBytesIn = n; - _codec.TotalBytesIn += p - _codec.NextIn; - _codec.NextIn = p; - writeAt = q; - return Flush(r); } - if (m == 0) - { - if (q == end && readAt != 0) - { - q = 0; - m = (q < readAt ? readAt - q - 1 : end - q); - } - if (m == 0) - { - writeAt = q; - r = Flush(r); - q = writeAt; - m = (q < readAt ? readAt - q - 1 : end - q); - if (q == end && readAt != 0) - { - q = 0; - m = (q < readAt ? readAt - q - 1 : end - q); - } - if (m == 0) - { - bitb = b; - bitk = k; - _codec.AvailableBytesIn = n; - _codec.TotalBytesIn += p - _codec.NextIn; - _codec.NextIn = p; - writeAt = q; - return Flush(r); - } - } - } - r = ZlibConstants.Z_OK; + bitb = b; + bitk = k; + _codec.AvailableBytesIn = n; + _codec.TotalBytesIn += p - _codec.NextIn; + _codec.NextIn = p; + writeAt = q; + return Flush(r); + } - t = left; - if (t > n) - { - t = n; - } - if (t > m) - { - t = m; - } - Array.Copy(_codec.InputBuffer, p, window, q, t); - p += t; - n -= t; - q += t; - m -= t; - if ((left -= t) != 0) + index = 0; + mode = InflateBlockMode.DTREE; + goto case InflateBlockMode.DTREE; + + case InflateBlockMode.DTREE: + while (true) + { + t = table; + if (!(index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f))) { break; } - mode = last != 0 ? InflateBlockMode.DRY : InflateBlockMode.TYPE; - break; - case InflateBlockMode.TABLE: + int i, + j, + c; - while (k < (14)) + t = bb[0]; + + while (k < t) { if (n != 0) { @@ -377,47 +511,26 @@ namespace SharpCompress.Compressors.Deflate k += 8; } - table = t = (b & 0x3fff); - if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29) - { - mode = InflateBlockMode.BAD; - _codec.Message = "too many length or distance symbols"; - r = ZlibConstants.Z_DATA_ERROR; + t = hufts[ + ((tb[0] + (b & InternalInflateConstants.InflateMask[t])) * 3) + 1 + ]; + c = hufts[ + ((tb[0] + (b & InternalInflateConstants.InflateMask[t])) * 3) + 2 + ]; - bitb = b; - bitk = k; - _codec.AvailableBytesIn = n; - _codec.TotalBytesIn += p - _codec.NextIn; - _codec.NextIn = p; - writeAt = q; - return Flush(r); - } - t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f); - if (blens is null || blens.Length < t) + if (c < 16) { - blens = new int[t]; + b >>= t; + k -= t; + blens[index++] = c; } else { - Array.Clear(blens, 0, t); + // c == 16..18 + i = c == 18 ? 7 : c - 14; + j = c == 18 ? 11 : 3; - // for (int i = 0; i < t; i++) - // { - // blens[i] = 0; - // } - } - - b >>= 14; - k -= 14; - - index = 0; - mode = InflateBlockMode.BTREE; - goto case InflateBlockMode.BTREE; - - case InflateBlockMode.BTREE: - while (index < 4 + (table >> 10)) - { - while (k < (3)) + while (k < (t + i)) { if (n != 0) { @@ -439,27 +552,73 @@ namespace SharpCompress.Compressors.Deflate k += 8; } - blens[border[index++]] = b & 7; + b >>= t; + k -= t; - b >>= 3; - k -= 3; + j += (b & InternalInflateConstants.InflateMask[i]); + + b >>= i; + k -= i; + + i = index; + t = table; + if ( + i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) + || (c == 16 && i < 1) + ) + { + blens = null; + mode = InflateBlockMode.BAD; + _codec.Message = "invalid bit length repeat"; + r = ZlibConstants.Z_DATA_ERROR; + + bitb = b; + bitk = k; + _codec.AvailableBytesIn = n; + _codec.TotalBytesIn += p - _codec.NextIn; + _codec.NextIn = p; + writeAt = q; + return Flush(r); + } + + c = (c == 16) ? blens[i - 1] : 0; + do + { + blens[i++] = c; + } while (--j != 0); + index = i; } + } - while (index < 19) - { - blens[border[index++]] = 0; - } + tb[0] = -1; + + { + var bl = new[] { 9 }; // must be <= 9 for lookahead assumptions + var bd = new[] { 6 }; // must be <= 9 for lookahead assumptions + var tl = new int[1]; + var td = new int[1]; + + t = table; + t = inftree.inflate_trees_dynamic( + 257 + (t & 0x1f), + 1 + ((t >> 5) & 0x1f), + blens, + bl, + bd, + tl, + td, + hufts, + _codec + ); - bb[0] = 7; - t = inftree.inflate_trees_bits(blens, bb, tb, hufts, _codec); if (t != ZlibConstants.Z_OK) { - r = t; - if (r == ZlibConstants.Z_DATA_ERROR) + if (t == ZlibConstants.Z_DATA_ERROR) { blens = null; mode = InflateBlockMode.BAD; } + r = t; bitb = b; bitk = k; @@ -469,469 +628,438 @@ namespace SharpCompress.Compressors.Deflate writeAt = q; return Flush(r); } + codes.Init(bl[0], bd[0], hufts, tl[0], hufts, td[0]); + } + mode = InflateBlockMode.CODES; + goto case InflateBlockMode.CODES; - index = 0; - mode = InflateBlockMode.DTREE; - goto case InflateBlockMode.DTREE; + case InflateBlockMode.CODES: + bitb = b; + bitk = k; + _codec.AvailableBytesIn = n; + _codec.TotalBytesIn += p - _codec.NextIn; + _codec.NextIn = p; + writeAt = q; - case InflateBlockMode.DTREE: - while (true) + r = codes.Process(this, r); + if (r != ZlibConstants.Z_STREAM_END) + { + return Flush(r); + } + + r = ZlibConstants.Z_OK; + p = _codec.NextIn; + n = _codec.AvailableBytesIn; + b = bitb; + k = bitk; + q = writeAt; + m = (q < readAt ? readAt - q - 1 : end - q); + + if (last == 0) + { + mode = InflateBlockMode.TYPE; + break; + } + mode = InflateBlockMode.DRY; + goto case InflateBlockMode.DRY; + + case InflateBlockMode.DRY: + writeAt = q; + r = Flush(r); + q = writeAt; + m = (q < readAt ? readAt - q - 1 : end - q); + if (readAt != writeAt) + { + bitb = b; + bitk = k; + _codec.AvailableBytesIn = n; + _codec.TotalBytesIn += p - _codec.NextIn; + _codec.NextIn = p; + writeAt = q; + return Flush(r); + } + mode = InflateBlockMode.DONE; + goto case InflateBlockMode.DONE; + + case InflateBlockMode.DONE: + r = ZlibConstants.Z_STREAM_END; + bitb = b; + bitk = k; + _codec.AvailableBytesIn = n; + _codec.TotalBytesIn += p - _codec.NextIn; + _codec.NextIn = p; + writeAt = q; + return Flush(r); + + case InflateBlockMode.BAD: + r = ZlibConstants.Z_DATA_ERROR; + + bitb = b; + bitk = k; + _codec.AvailableBytesIn = n; + _codec.TotalBytesIn += p - _codec.NextIn; + _codec.NextIn = p; + writeAt = q; + return Flush(r); + + default: + r = ZlibConstants.Z_STREAM_ERROR; + + bitb = b; + bitk = k; + _codec.AvailableBytesIn = n; + _codec.TotalBytesIn += p - _codec.NextIn; + _codec.NextIn = p; + writeAt = q; + return Flush(r); + } + } + } + + internal void Free() + { + Reset(); + window = null; + hufts = null; + } + + internal void SetDictionary(byte[] d, int start, int n) + { + Array.Copy(d, start, window, 0, n); + readAt = writeAt = n; + } + + // Returns true if inflate is currently at the end of a block generated + // by Z_SYNC_FLUSH or Z_FULL_FLUSH. + internal int SyncPoint() + { + return mode == InflateBlockMode.LENS ? 1 : 0; + } + + // copy as much as possible from the sliding window to the output area + internal int Flush(int r) + { + int nBytes; + + for (var pass = 0; pass < 2; pass++) + { + if (pass == 0) + { + // compute number of bytes to copy as far as end of window + nBytes = ((readAt <= writeAt ? writeAt : end) - readAt); + } + else + { + // compute bytes to copy + nBytes = writeAt - readAt; + } + + // workitem 8870 + if (nBytes == 0) + { + if (r == ZlibConstants.Z_BUF_ERROR) + { + r = ZlibConstants.Z_OK; + } + return r; + } + + if (nBytes > _codec.AvailableBytesOut) + { + nBytes = _codec.AvailableBytesOut; + } + + if (nBytes != 0 && r == ZlibConstants.Z_BUF_ERROR) + { + r = ZlibConstants.Z_OK; + } + + // update counters + _codec.AvailableBytesOut -= nBytes; + _codec.TotalBytesOut += nBytes; + + // update check information + if (checkfn != null) + { + _codec._adler32 = check = Adler32.Calculate( + check, + window.AsSpan(readAt, nBytes) + ); + } + + // copy as far as end of window + Array.Copy(window, readAt, _codec.OutputBuffer, _codec.NextOut, nBytes); + _codec.NextOut += nBytes; + readAt += nBytes; + + // see if more to copy at beginning of window + if (readAt == end && pass == 0) + { + // wrap pointers + readAt = 0; + if (writeAt == end) + { + writeAt = 0; + } + } + else + { + pass++; + } + } + + // done + return r; + } + + #region Nested type: InflateBlockMode + + private enum InflateBlockMode + { + TYPE = 0, // get type bits (3, including end bit) + LENS = 1, // get lengths for stored + STORED = 2, // processing stored block + TABLE = 3, // get table lengths + BTREE = 4, // get bit lengths tree for a dynamic block + DTREE = 5, // get length, distance trees for a dynamic block + CODES = 6, // processing fixed or dynamic block + DRY = 7, // output remaining window bytes + DONE = 8, // finished last block, done + BAD = 9 // ot a data error--stuck here + } + + #endregion +} + +internal static class InternalInflateConstants +{ + // And'ing with mask[n] masks the lower n bits + internal static readonly int[] InflateMask = + { + 0x00000000, + 0x00000001, + 0x00000003, + 0x00000007, + 0x0000000f, + 0x0000001f, + 0x0000003f, + 0x0000007f, + 0x000000ff, + 0x000001ff, + 0x000003ff, + 0x000007ff, + 0x00000fff, + 0x00001fff, + 0x00003fff, + 0x00007fff, + 0x0000ffff + }; +} + +internal sealed class InflateCodes +{ + // waiting for "i:"=input, + // "o:"=output, + // "x:"=nothing + private const int START = 0; // x: set up for LEN + private const int LEN = 1; // i: get length/literal/eob next + private const int LENEXT = 2; // i: getting length extra (have base) + private const int DIST = 3; // i: get distance next + private const int DISTEXT = 4; // i: getting distance extra + private const int COPY = 5; // o: copying bytes in window, waiting for space + private const int LIT = 6; // o: got literal, waiting for output space + private const int WASH = 7; // o: got eob, possibly still output waiting + private const int END = 8; // x: got eob and all data flushed + private const int BADCODE = 9; // x: got error + + // if EXT or COPY, where and how much + internal int bitsToGet; // bits to get for extra + internal byte dbits; // dtree bits decoder per branch + internal int dist; // distance back to copy from + internal int[] dtree; // distance tree + internal int dtree_index; // distance tree + + internal byte lbits; // ltree bits decoded per branch + internal int len; + internal int lit; + internal int[] ltree; // literal/length/eob tree + internal int ltree_index; // literal/length/eob tree + internal int mode; // current inflate_codes mode + internal int need; // bits needed + internal int[] tree; // pointer into tree + internal int tree_index; + + internal void Init(int bl, int bd, int[] tl, int tl_index, int[] td, int td_index) + { + mode = START; + lbits = (byte)bl; + dbits = (byte)bd; + ltree = tl; + ltree_index = tl_index; + dtree = td; + dtree_index = td_index; + tree = null; + } + + internal int Process(InflateBlocks blocks, int r) + { + int j; // temporary storage + int tindex; // temporary pointer + int e; // extra bits or operation + var b = 0; // bit buffer + var k = 0; // bits in bit buffer + var p = 0; // input data pointer + int n; // bytes available there + int q; // output window write pointer + int m; // bytes to end of window or read pointer + int f; // pointer to copy strings from + + var z = blocks._codec; + + // copy input/output information to locals (UPDATE macro restores) + p = z.NextIn; + n = z.AvailableBytesIn; + b = blocks.bitb; + k = blocks.bitk; + q = blocks.writeAt; + m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q; + + // process input and output based on current state + while (true) + { + switch (mode) + { + // waiting for "i:"=input, "o:"=output, "x:"=nothing + case START: // x: set up for LEN + if (m >= 258 && n >= 10) + { + blocks.bitb = b; + blocks.bitk = k; + z.AvailableBytesIn = n; + z.TotalBytesIn += p - z.NextIn; + z.NextIn = p; + blocks.writeAt = q; + r = InflateFast( + lbits, + dbits, + ltree, + ltree_index, + dtree, + dtree_index, + blocks, + z + ); + + p = z.NextIn; + n = z.AvailableBytesIn; + b = blocks.bitb; + k = blocks.bitk; + q = blocks.writeAt; + m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q; + + if (r != ZlibConstants.Z_OK) { - t = table; - if (!(index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f))) + mode = (r == ZlibConstants.Z_STREAM_END) ? WASH : BADCODE; + break; + } + } + need = lbits; + tree = ltree; + tree_index = ltree_index; + + mode = LEN; + goto case LEN; + + case LEN: // i: get length/literal/eob next + j = need; + + while (k < j) + { + if (n != 0) + { + r = ZlibConstants.Z_OK; + } + else + { + // Handling missing trailing bit(s) + var tmp_tindex = + (tree_index + (b & InternalInflateConstants.InflateMask[k])) + * 3; + if (k >= tree[tmp_tindex + 1]) { break; } - int i, - j, - c; - - t = bb[0]; - - while (k < t) - { - if (n != 0) - { - r = ZlibConstants.Z_OK; - } - else - { - bitb = b; - bitk = k; - _codec.AvailableBytesIn = n; - _codec.TotalBytesIn += p - _codec.NextIn; - _codec.NextIn = p; - writeAt = q; - return Flush(r); - } - - n--; - b |= (_codec.InputBuffer[p++] & 0xff) << k; - k += 8; - } - - t = hufts[ - (tb[0] + (b & InternalInflateConstants.InflateMask[t])) * 3 + 1 - ]; - c = hufts[ - (tb[0] + (b & InternalInflateConstants.InflateMask[t])) * 3 + 2 - ]; - - if (c < 16) - { - b >>= t; - k -= t; - blens[index++] = c; - } - else - { - // c == 16..18 - i = c == 18 ? 7 : c - 14; - j = c == 18 ? 11 : 3; - - while (k < (t + i)) - { - if (n != 0) - { - r = ZlibConstants.Z_OK; - } - else - { - bitb = b; - bitk = k; - _codec.AvailableBytesIn = n; - _codec.TotalBytesIn += p - _codec.NextIn; - _codec.NextIn = p; - writeAt = q; - return Flush(r); - } - - n--; - b |= (_codec.InputBuffer[p++] & 0xff) << k; - k += 8; - } - - b >>= t; - k -= t; - - j += (b & InternalInflateConstants.InflateMask[i]); - - b >>= i; - k -= i; - - i = index; - t = table; - if ( - i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) - || (c == 16 && i < 1) - ) - { - blens = null; - mode = InflateBlockMode.BAD; - _codec.Message = "invalid bit length repeat"; - r = ZlibConstants.Z_DATA_ERROR; - - bitb = b; - bitk = k; - _codec.AvailableBytesIn = n; - _codec.TotalBytesIn += p - _codec.NextIn; - _codec.NextIn = p; - writeAt = q; - return Flush(r); - } - - c = (c == 16) ? blens[i - 1] : 0; - do - { - blens[i++] = c; - } while (--j != 0); - index = i; - } + blocks.bitb = b; + blocks.bitk = k; + z.AvailableBytesIn = n; + z.TotalBytesIn += p - z.NextIn; + z.NextIn = p; + blocks.writeAt = q; + return blocks.Flush(r); } - - tb[0] = -1; - - { - var bl = new[] { 9 }; // must be <= 9 for lookahead assumptions - var bd = new[] { 6 }; // must be <= 9 for lookahead assumptions - var tl = new int[1]; - var td = new int[1]; - - t = table; - t = inftree.inflate_trees_dynamic( - 257 + (t & 0x1f), - 1 + ((t >> 5) & 0x1f), - blens, - bl, - bd, - tl, - td, - hufts, - _codec - ); - - if (t != ZlibConstants.Z_OK) - { - if (t == ZlibConstants.Z_DATA_ERROR) - { - blens = null; - mode = InflateBlockMode.BAD; - } - r = t; - - bitb = b; - bitk = k; - _codec.AvailableBytesIn = n; - _codec.TotalBytesIn += p - _codec.NextIn; - _codec.NextIn = p; - writeAt = q; - return Flush(r); - } - codes.Init(bl[0], bd[0], hufts, tl[0], hufts, td[0]); - } - mode = InflateBlockMode.CODES; - goto case InflateBlockMode.CODES; - - case InflateBlockMode.CODES: - bitb = b; - bitk = k; - _codec.AvailableBytesIn = n; - _codec.TotalBytesIn += p - _codec.NextIn; - _codec.NextIn = p; - writeAt = q; - - r = codes.Process(this, r); - if (r != ZlibConstants.Z_STREAM_END) - { - return Flush(r); - } - - r = ZlibConstants.Z_OK; - p = _codec.NextIn; - n = _codec.AvailableBytesIn; - b = bitb; - k = bitk; - q = writeAt; - m = (q < readAt ? readAt - q - 1 : end - q); - - if (last == 0) - { - mode = InflateBlockMode.TYPE; - break; - } - mode = InflateBlockMode.DRY; - goto case InflateBlockMode.DRY; - - case InflateBlockMode.DRY: - writeAt = q; - r = Flush(r); - q = writeAt; - m = (q < readAt ? readAt - q - 1 : end - q); - if (readAt != writeAt) - { - bitb = b; - bitk = k; - _codec.AvailableBytesIn = n; - _codec.TotalBytesIn += p - _codec.NextIn; - _codec.NextIn = p; - writeAt = q; - return Flush(r); - } - mode = InflateBlockMode.DONE; - goto case InflateBlockMode.DONE; - - case InflateBlockMode.DONE: - r = ZlibConstants.Z_STREAM_END; - bitb = b; - bitk = k; - _codec.AvailableBytesIn = n; - _codec.TotalBytesIn += p - _codec.NextIn; - _codec.NextIn = p; - writeAt = q; - return Flush(r); - - case InflateBlockMode.BAD: - r = ZlibConstants.Z_DATA_ERROR; - - bitb = b; - bitk = k; - _codec.AvailableBytesIn = n; - _codec.TotalBytesIn += p - _codec.NextIn; - _codec.NextIn = p; - writeAt = q; - return Flush(r); - - default: - r = ZlibConstants.Z_STREAM_ERROR; - - bitb = b; - bitk = k; - _codec.AvailableBytesIn = n; - _codec.TotalBytesIn += p - _codec.NextIn; - _codec.NextIn = p; - writeAt = q; - return Flush(r); - } - } - } - - internal void Free() - { - Reset(); - window = null; - hufts = null; - } - - internal void SetDictionary(byte[] d, int start, int n) - { - Array.Copy(d, start, window, 0, n); - readAt = writeAt = n; - } - - // Returns true if inflate is currently at the end of a block generated - // by Z_SYNC_FLUSH or Z_FULL_FLUSH. - internal int SyncPoint() - { - return mode == InflateBlockMode.LENS ? 1 : 0; - } - - // copy as much as possible from the sliding window to the output area - internal int Flush(int r) - { - int nBytes; - - for (int pass = 0; pass < 2; pass++) - { - if (pass == 0) - { - // compute number of bytes to copy as far as end of window - nBytes = ((readAt <= writeAt ? writeAt : end) - readAt); - } - else - { - // compute bytes to copy - nBytes = writeAt - readAt; - } - - // workitem 8870 - if (nBytes == 0) - { - if (r == ZlibConstants.Z_BUF_ERROR) - { - r = ZlibConstants.Z_OK; + n--; + b |= (z.InputBuffer[p++] & 0xff) << k; + k += 8; } - return r; - } - if (nBytes > _codec.AvailableBytesOut) - { - nBytes = _codec.AvailableBytesOut; - } + tindex = (tree_index + (b & InternalInflateConstants.InflateMask[j])) * 3; - if (nBytes != 0 && r == ZlibConstants.Z_BUF_ERROR) - { - r = ZlibConstants.Z_OK; - } + b >>= (tree[tindex + 1]); + k -= (tree[tindex + 1]); - // update counters - _codec.AvailableBytesOut -= nBytes; - _codec.TotalBytesOut += nBytes; + e = tree[tindex]; - // update check information - if (checkfn != null) - { - _codec._adler32 = check = Adler32.Calculate( - check, - window.AsSpan(readAt, nBytes) - ); - } - - // copy as far as end of window - Array.Copy(window, readAt, _codec.OutputBuffer, _codec.NextOut, nBytes); - _codec.NextOut += nBytes; - readAt += nBytes; - - // see if more to copy at beginning of window - if (readAt == end && pass == 0) - { - // wrap pointers - readAt = 0; - if (writeAt == end) + if (e == 0) { - writeAt = 0; + // literal + lit = tree[tindex + 2]; + mode = LIT; + break; } - } - else - { - pass++; - } - } + if ((e & 16) != 0) + { + // length + bitsToGet = e & 15; + len = tree[tindex + 2]; + mode = LENEXT; + break; + } + if ((e & 64) == 0) + { + // next table + need = e; + tree_index = (tindex / 3) + tree[tindex + 2]; + break; + } + if ((e & 32) != 0) + { + // end of block + mode = WASH; + break; + } + mode = BADCODE; // invalid code + z.Message = "invalid literal/length code"; + r = ZlibConstants.Z_DATA_ERROR; - // done - return r; - } + blocks.bitb = b; + blocks.bitk = k; + z.AvailableBytesIn = n; + z.TotalBytesIn += p - z.NextIn; + z.NextIn = p; + blocks.writeAt = q; + return blocks.Flush(r); - #region Nested type: InflateBlockMode + case LENEXT: // i: getting length extra (have base) + j = bitsToGet; - private enum InflateBlockMode - { - TYPE = 0, // get type bits (3, including end bit) - LENS = 1, // get lengths for stored - STORED = 2, // processing stored block - TABLE = 3, // get table lengths - BTREE = 4, // get bit lengths tree for a dynamic block - DTREE = 5, // get length, distance trees for a dynamic block - CODES = 6, // processing fixed or dynamic block - DRY = 7, // output remaining window bytes - DONE = 8, // finished last block, done - BAD = 9 // ot a data error--stuck here - } - - #endregion - } - - internal static class InternalInflateConstants - { - // And'ing with mask[n] masks the lower n bits - internal static readonly int[] InflateMask = - { - 0x00000000, - 0x00000001, - 0x00000003, - 0x00000007, - 0x0000000f, - 0x0000001f, - 0x0000003f, - 0x0000007f, - 0x000000ff, - 0x000001ff, - 0x000003ff, - 0x000007ff, - 0x00000fff, - 0x00001fff, - 0x00003fff, - 0x00007fff, - 0x0000ffff - }; - } - - internal sealed class InflateCodes - { - // waiting for "i:"=input, - // "o:"=output, - // "x:"=nothing - private const int START = 0; // x: set up for LEN - private const int LEN = 1; // i: get length/literal/eob next - private const int LENEXT = 2; // i: getting length extra (have base) - private const int DIST = 3; // i: get distance next - private const int DISTEXT = 4; // i: getting distance extra - private const int COPY = 5; // o: copying bytes in window, waiting for space - private const int LIT = 6; // o: got literal, waiting for output space - private const int WASH = 7; // o: got eob, possibly still output waiting - private const int END = 8; // x: got eob and all data flushed - private const int BADCODE = 9; // x: got error - - // if EXT or COPY, where and how much - internal int bitsToGet; // bits to get for extra - internal byte dbits; // dtree bits decoder per branch - internal int dist; // distance back to copy from - internal int[] dtree; // distance tree - internal int dtree_index; // distance tree - - internal byte lbits; // ltree bits decoded per branch - internal int len; - internal int lit; - internal int[] ltree; // literal/length/eob tree - internal int ltree_index; // literal/length/eob tree - internal int mode; // current inflate_codes mode - internal int need; // bits needed - internal int[] tree; // pointer into tree - internal int tree_index; - - internal void Init(int bl, int bd, int[] tl, int tl_index, int[] td, int td_index) - { - mode = START; - lbits = (byte)bl; - dbits = (byte)bd; - ltree = tl; - ltree_index = tl_index; - dtree = td; - dtree_index = td_index; - tree = null; - } - - internal int Process(InflateBlocks blocks, int r) - { - int j; // temporary storage - int tindex; // temporary pointer - int e; // extra bits or operation - int b = 0; // bit buffer - int k = 0; // bits in bit buffer - int p = 0; // input data pointer - int n; // bytes available there - int q; // output window write pointer - int m; // bytes to end of window or read pointer - int f; // pointer to copy strings from - - ZlibCodec z = blocks._codec; - - // copy input/output information to locals (UPDATE macro restores) - p = z.NextIn; - n = z.AvailableBytesIn; - b = blocks.bitb; - k = blocks.bitk; - q = blocks.writeAt; - m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q; - - // process input and output based on current state - while (true) - { - switch (mode) - { - // waiting for "i:"=input, "o:"=output, "x:"=nothing - case START: // x: set up for LEN - if (m >= 258 && n >= 10) + while (k < j) + { + if (n != 0) + { + r = ZlibConstants.Z_OK; + } + else { blocks.bitb = b; blocks.bitk = k; @@ -939,308 +1067,131 @@ namespace SharpCompress.Compressors.Deflate z.TotalBytesIn += p - z.NextIn; z.NextIn = p; blocks.writeAt = q; - r = InflateFast( - lbits, - dbits, - ltree, - ltree_index, - dtree, - dtree_index, - blocks, - z - ); + return blocks.Flush(r); + } + n--; + b |= (z.InputBuffer[p++] & 0xff) << k; + k += 8; + } - p = z.NextIn; - n = z.AvailableBytesIn; - b = blocks.bitb; - k = blocks.bitk; - q = blocks.writeAt; - m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q; + len += (b & InternalInflateConstants.InflateMask[j]); - if (r != ZlibConstants.Z_OK) + b >>= j; + k -= j; + + need = dbits; + tree = dtree; + tree_index = dtree_index; + mode = DIST; + goto case DIST; + + case DIST: // i: get distance next + j = need; + + while (k < j) + { + if (n != 0) + { + r = ZlibConstants.Z_OK; + } + else + { + // Handling missing trailing bit(s) + var tmp_tindex = + (tree_index + (b & InternalInflateConstants.InflateMask[k])) + * 3; + if (k >= tree[tmp_tindex + 1]) { - mode = (r == ZlibConstants.Z_STREAM_END) ? WASH : BADCODE; break; } + + blocks.bitb = b; + blocks.bitk = k; + z.AvailableBytesIn = n; + z.TotalBytesIn += p - z.NextIn; + z.NextIn = p; + blocks.writeAt = q; + return blocks.Flush(r); } - need = lbits; - tree = ltree; - tree_index = ltree_index; + n--; + b |= (z.InputBuffer[p++] & 0xff) << k; + k += 8; + } - mode = LEN; - goto case LEN; + tindex = (tree_index + (b & InternalInflateConstants.InflateMask[j])) * 3; - case LEN: // i: get length/literal/eob next - j = need; + b >>= tree[tindex + 1]; + k -= tree[tindex + 1]; - while (k < j) - { - if (n != 0) - { - r = ZlibConstants.Z_OK; - } - else - { - // Handling missing trailing bit(s) - var tmp_tindex = - (tree_index + (b & InternalInflateConstants.InflateMask[k])) - * 3; - if (k >= tree[tmp_tindex + 1]) - { - break; - } - - blocks.bitb = b; - blocks.bitk = k; - z.AvailableBytesIn = n; - z.TotalBytesIn += p - z.NextIn; - z.NextIn = p; - blocks.writeAt = q; - return blocks.Flush(r); - } - n--; - b |= (z.InputBuffer[p++] & 0xff) << k; - k += 8; - } - - tindex = (tree_index + (b & InternalInflateConstants.InflateMask[j])) * 3; - - b >>= (tree[tindex + 1]); - k -= (tree[tindex + 1]); - - e = tree[tindex]; - - if (e == 0) - { - // literal - lit = tree[tindex + 2]; - mode = LIT; - break; - } - if ((e & 16) != 0) - { - // length - bitsToGet = e & 15; - len = tree[tindex + 2]; - mode = LENEXT; - break; - } - if ((e & 64) == 0) - { - // next table - need = e; - tree_index = tindex / 3 + tree[tindex + 2]; - break; - } - if ((e & 32) != 0) - { - // end of block - mode = WASH; - break; - } - mode = BADCODE; // invalid code - z.Message = "invalid literal/length code"; - r = ZlibConstants.Z_DATA_ERROR; - - blocks.bitb = b; - blocks.bitk = k; - z.AvailableBytesIn = n; - z.TotalBytesIn += p - z.NextIn; - z.NextIn = p; - blocks.writeAt = q; - return blocks.Flush(r); - - case LENEXT: // i: getting length extra (have base) - j = bitsToGet; - - while (k < j) - { - if (n != 0) - { - r = ZlibConstants.Z_OK; - } - else - { - blocks.bitb = b; - blocks.bitk = k; - z.AvailableBytesIn = n; - z.TotalBytesIn += p - z.NextIn; - z.NextIn = p; - blocks.writeAt = q; - return blocks.Flush(r); - } - n--; - b |= (z.InputBuffer[p++] & 0xff) << k; - k += 8; - } - - len += (b & InternalInflateConstants.InflateMask[j]); - - b >>= j; - k -= j; - - need = dbits; - tree = dtree; - tree_index = dtree_index; - mode = DIST; - goto case DIST; - - case DIST: // i: get distance next - j = need; - - while (k < j) - { - if (n != 0) - { - r = ZlibConstants.Z_OK; - } - else - { - // Handling missing trailing bit(s) - var tmp_tindex = - (tree_index + (b & InternalInflateConstants.InflateMask[k])) - * 3; - if (k >= tree[tmp_tindex + 1]) - { - break; - } - - blocks.bitb = b; - blocks.bitk = k; - z.AvailableBytesIn = n; - z.TotalBytesIn += p - z.NextIn; - z.NextIn = p; - blocks.writeAt = q; - return blocks.Flush(r); - } - n--; - b |= (z.InputBuffer[p++] & 0xff) << k; - k += 8; - } - - tindex = (tree_index + (b & InternalInflateConstants.InflateMask[j])) * 3; - - b >>= tree[tindex + 1]; - k -= tree[tindex + 1]; - - e = (tree[tindex]); - if ((e & 0x10) != 0) - { - // distance - bitsToGet = e & 15; - dist = tree[tindex + 2]; - mode = DISTEXT; - break; - } - if ((e & 64) == 0) - { - // next table - need = e; - tree_index = tindex / 3 + tree[tindex + 2]; - break; - } - mode = BADCODE; // invalid code - z.Message = "invalid distance code"; - r = ZlibConstants.Z_DATA_ERROR; - - blocks.bitb = b; - blocks.bitk = k; - z.AvailableBytesIn = n; - z.TotalBytesIn += p - z.NextIn; - z.NextIn = p; - blocks.writeAt = q; - return blocks.Flush(r); - - case DISTEXT: // i: getting distance extra - j = bitsToGet; - - while (k < j) - { - if (n != 0) - { - r = ZlibConstants.Z_OK; - } - else - { - blocks.bitb = b; - blocks.bitk = k; - z.AvailableBytesIn = n; - z.TotalBytesIn += p - z.NextIn; - z.NextIn = p; - blocks.writeAt = q; - return blocks.Flush(r); - } - n--; - b |= (z.InputBuffer[p++] & 0xff) << k; - k += 8; - } - - dist += (b & InternalInflateConstants.InflateMask[j]); - - b >>= j; - k -= j; - - mode = COPY; - goto case COPY; - - case COPY: // o: copying bytes in window, waiting for space - f = q - dist; - while (f < 0) - { - // modulo window size-"while" instead - f += blocks.end; // of "if" handles invalid distances - } - while (len != 0) - { - if (m == 0) - { - if (q == blocks.end && blocks.readAt != 0) - { - q = 0; - m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q; - } - if (m == 0) - { - blocks.writeAt = q; - r = blocks.Flush(r); - q = blocks.writeAt; - m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q; - - if (q == blocks.end && blocks.readAt != 0) - { - q = 0; - m = - q < blocks.readAt - ? blocks.readAt - q - 1 - : blocks.end - q; - } - - if (m == 0) - { - blocks.bitb = b; - blocks.bitk = k; - z.AvailableBytesIn = n; - z.TotalBytesIn += p - z.NextIn; - z.NextIn = p; - blocks.writeAt = q; - return blocks.Flush(r); - } - } - } - - blocks.window[q++] = blocks.window[f++]; - m--; - - if (f == blocks.end) - { - f = 0; - } - len--; - } - mode = START; + e = (tree[tindex]); + if ((e & 0x10) != 0) + { + // distance + bitsToGet = e & 15; + dist = tree[tindex + 2]; + mode = DISTEXT; break; + } + if ((e & 64) == 0) + { + // next table + need = e; + tree_index = (tindex / 3) + tree[tindex + 2]; + break; + } + mode = BADCODE; // invalid code + z.Message = "invalid distance code"; + r = ZlibConstants.Z_DATA_ERROR; - case LIT: // o: got literal, waiting for output space + blocks.bitb = b; + blocks.bitk = k; + z.AvailableBytesIn = n; + z.TotalBytesIn += p - z.NextIn; + z.NextIn = p; + blocks.writeAt = q; + return blocks.Flush(r); + + case DISTEXT: // i: getting distance extra + j = bitsToGet; + + while (k < j) + { + if (n != 0) + { + r = ZlibConstants.Z_OK; + } + else + { + blocks.bitb = b; + blocks.bitk = k; + z.AvailableBytesIn = n; + z.TotalBytesIn += p - z.NextIn; + z.NextIn = p; + blocks.writeAt = q; + return blocks.Flush(r); + } + n--; + b |= (z.InputBuffer[p++] & 0xff) << k; + k += 8; + } + + dist += (b & InternalInflateConstants.InflateMask[j]); + + b >>= j; + k -= j; + + mode = COPY; + goto case COPY; + + case COPY: // o: copying bytes in window, waiting for space + f = q - dist; + while (f < 0) + { + // modulo window size-"while" instead + f += blocks.end; // of "if" handles invalid distances + } + while (len != 0) + { if (m == 0) { if (q == blocks.end && blocks.readAt != 0) @@ -1258,8 +1209,12 @@ namespace SharpCompress.Compressors.Deflate if (q == blocks.end && blocks.readAt != 0) { q = 0; - m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q; + m = + q < blocks.readAt + ? blocks.readAt - q - 1 + : blocks.end - q; } + if (m == 0) { blocks.bitb = b; @@ -1272,814 +1227,855 @@ namespace SharpCompress.Compressors.Deflate } } } - r = ZlibConstants.Z_OK; - blocks.window[q++] = (byte)lit; + blocks.window[q++] = blocks.window[f++]; m--; - mode = START; - break; - - case WASH: // o: got eob, possibly more output - if (k > 7) + if (f == blocks.end) { - // return unused byte, if any - k -= 8; - n++; - p--; // can always return one + f = 0; } + len--; + } + mode = START; + break; - blocks.writeAt = q; - r = blocks.Flush(r); - q = blocks.writeAt; - m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q; - - if (blocks.readAt != blocks.writeAt) - { - blocks.bitb = b; - blocks.bitk = k; - z.AvailableBytesIn = n; - z.TotalBytesIn += p - z.NextIn; - z.NextIn = p; - blocks.writeAt = q; - return blocks.Flush(r); - } - mode = END; - goto case END; - - case END: - r = ZlibConstants.Z_STREAM_END; - blocks.bitb = b; - blocks.bitk = k; - z.AvailableBytesIn = n; - z.TotalBytesIn += p - z.NextIn; - z.NextIn = p; - blocks.writeAt = q; - return blocks.Flush(r); - - case BADCODE: // x: got error - - r = ZlibConstants.Z_DATA_ERROR; - - blocks.bitb = b; - blocks.bitk = k; - z.AvailableBytesIn = n; - z.TotalBytesIn += p - z.NextIn; - z.NextIn = p; - blocks.writeAt = q; - return blocks.Flush(r); - - default: - r = ZlibConstants.Z_STREAM_ERROR; - - blocks.bitb = b; - blocks.bitk = k; - z.AvailableBytesIn = n; - z.TotalBytesIn += p - z.NextIn; - z.NextIn = p; - blocks.writeAt = q; - return blocks.Flush(r); - } - } - } - - // Called with number of bytes left to write in window at least 258 - // (the maximum string length) and number of input bytes available - // at least ten. The ten bytes are six bytes for the longest length/ - // distance pair plus four bytes for overloading the bit buffer. - - internal int InflateFast( - int bl, - int bd, - int[] tl, - int tl_index, - int[] td, - int td_index, - InflateBlocks s, - ZlibCodec z - ) - { - int t; // temporary pointer - int[] tp; // temporary pointer - int tp_index; // temporary pointer - int e; // extra bits or operation - int b; // bit buffer - int k; // bits in bit buffer - int p; // input data pointer - int n; // bytes available there - int q; // output window write pointer - int m; // bytes to end of window or read pointer - int ml; // mask for literal/length tree - int md; // mask for distance tree - int c; // bytes to copy - int d; // distance back to copy from - int r; // copy source pointer - - int tp_index_t_3; // (tp_index+t)*3 - - // load input, output, bit values - p = z.NextIn; - n = z.AvailableBytesIn; - b = s.bitb; - k = s.bitk; - q = s.writeAt; - m = q < s.readAt ? s.readAt - q - 1 : s.end - q; - - // initialize masks - ml = InternalInflateConstants.InflateMask[bl]; - md = InternalInflateConstants.InflateMask[bd]; - - // do until not enough input or output space for fast loop - do - { - // assume called with m >= 258 && n >= 10 - // get literal/length code - while (k < (20)) - { - // max bits for literal/length code - n--; - b |= (z.InputBuffer[p++] & 0xff) << k; - k += 8; - } - - t = b & ml; - tp = tl; - tp_index = tl_index; - tp_index_t_3 = (tp_index + t) * 3; - if ((e = tp[tp_index_t_3]) == 0) - { - b >>= (tp[tp_index_t_3 + 1]); - k -= (tp[tp_index_t_3 + 1]); - - s.window[q++] = (byte)tp[tp_index_t_3 + 2]; - m--; - continue; - } - do - { - b >>= (tp[tp_index_t_3 + 1]); - k -= (tp[tp_index_t_3 + 1]); - - if ((e & 16) != 0) + case LIT: // o: got literal, waiting for output space + if (m == 0) { - e &= 15; - c = tp[tp_index_t_3 + 2] + (b & InternalInflateConstants.InflateMask[e]); - - b >>= e; - k -= e; - - // decode distance base of block to copy - while (k < 15) + if (q == blocks.end && blocks.readAt != 0) { - // max bits for distance code - n--; - b |= (z.InputBuffer[p++] & 0xff) << k; - k += 8; + q = 0; + m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q; } - - t = b & md; - tp = td; - tp_index = td_index; - tp_index_t_3 = (tp_index + t) * 3; - e = tp[tp_index_t_3]; - - do + if (m == 0) { - b >>= (tp[tp_index_t_3 + 1]); - k -= (tp[tp_index_t_3 + 1]); + blocks.writeAt = q; + r = blocks.Flush(r); + q = blocks.writeAt; + m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q; - if ((e & 16) != 0) + if (q == blocks.end && blocks.readAt != 0) { - // get extra bits to add to distance base - e &= 15; - while (k < e) - { - // get extra bits (up to 13) - n--; - b |= (z.InputBuffer[p++] & 0xff) << k; - k += 8; - } - - d = - tp[tp_index_t_3 + 2] - + (b & InternalInflateConstants.InflateMask[e]); - - b >>= e; - k -= e; - - // do the copy - m -= c; - if (q >= d) - { - // offset before dest - // just copy - r = q - d; - if (q - r > 0 && 2 > (q - r)) - { - s.window[q++] = s.window[r++]; // minimum count is three, - s.window[q++] = s.window[r++]; // so unroll loop a little - c -= 2; - } - else - { - Array.Copy(s.window, r, s.window, q, 2); - q += 2; - r += 2; - c -= 2; - } - } - else - { - // else offset after destination - r = q - d; - do - { - r += s.end; // force pointer in window - } while (r < 0); // covers invalid distances - e = s.end - r; - if (c > e) - { - // if source crosses, - c -= e; // wrapped copy - if (q - r > 0 && e > (q - r)) - { - do - { - s.window[q++] = s.window[r++]; - } while (--e != 0); - } - else - { - Array.Copy(s.window, r, s.window, q, e); - q += e; - r += e; - e = 0; - } - r = 0; // copy rest from start of window - } - } - - // copy all or what's left - if (q - r > 0 && c > (q - r)) - { - do - { - s.window[q++] = s.window[r++]; - } while (--c != 0); - } - else - { - Array.Copy(s.window, r, s.window, q, c); - q += c; - r += c; - c = 0; - } - break; + q = 0; + m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q; } - if ((e & 64) == 0) + if (m == 0) { - t += tp[tp_index_t_3 + 2]; - t += (b & InternalInflateConstants.InflateMask[e]); - tp_index_t_3 = (tp_index + t) * 3; - e = tp[tp_index_t_3]; - } - else - { - z.Message = "invalid distance code"; - - c = z.AvailableBytesIn - n; - c = (k >> 3) < c ? k >> 3 : c; - n += c; - p -= c; - k -= (c << 3); - - s.bitb = b; - s.bitk = k; + blocks.bitb = b; + blocks.bitk = k; z.AvailableBytesIn = n; z.TotalBytesIn += p - z.NextIn; z.NextIn = p; - s.writeAt = q; - - return ZlibConstants.Z_DATA_ERROR; + blocks.writeAt = q; + return blocks.Flush(r); } - } while (true); - break; - } - - if ((e & 64) == 0) - { - t += tp[tp_index_t_3 + 2]; - t += (b & InternalInflateConstants.InflateMask[e]); - tp_index_t_3 = (tp_index + t) * 3; - if ((e = tp[tp_index_t_3]) == 0) - { - b >>= (tp[tp_index_t_3 + 1]); - k -= (tp[tp_index_t_3 + 1]); - s.window[q++] = (byte)tp[tp_index_t_3 + 2]; - m--; - break; } } - else if ((e & 32) != 0) - { - c = z.AvailableBytesIn - n; - c = (k >> 3) < c ? k >> 3 : c; - n += c; - p -= c; - k -= (c << 3); + r = ZlibConstants.Z_OK; - s.bitb = b; - s.bitk = k; + blocks.window[q++] = (byte)lit; + m--; + + mode = START; + break; + + case WASH: // o: got eob, possibly more output + if (k > 7) + { + // return unused byte, if any + k -= 8; + n++; + p--; // can always return one + } + + blocks.writeAt = q; + r = blocks.Flush(r); + q = blocks.writeAt; + m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q; + + if (blocks.readAt != blocks.writeAt) + { + blocks.bitb = b; + blocks.bitk = k; z.AvailableBytesIn = n; z.TotalBytesIn += p - z.NextIn; z.NextIn = p; - s.writeAt = q; - - return ZlibConstants.Z_STREAM_END; + blocks.writeAt = q; + return blocks.Flush(r); } - else - { - z.Message = "invalid literal/length code"; + mode = END; + goto case END; - c = z.AvailableBytesIn - n; - c = (k >> 3) < c ? k >> 3 : c; - n += c; - p -= c; - k -= (c << 3); + case END: + r = ZlibConstants.Z_STREAM_END; + blocks.bitb = b; + blocks.bitk = k; + z.AvailableBytesIn = n; + z.TotalBytesIn += p - z.NextIn; + z.NextIn = p; + blocks.writeAt = q; + return blocks.Flush(r); - s.bitb = b; - s.bitk = k; - z.AvailableBytesIn = n; - z.TotalBytesIn += p - z.NextIn; - z.NextIn = p; - s.writeAt = q; + case BADCODE: // x: got error - return ZlibConstants.Z_DATA_ERROR; - } - } while (true); - } while (m >= 258 && n >= 10); + r = ZlibConstants.Z_DATA_ERROR; - // not enough input or output--restore pointers and return - c = z.AvailableBytesIn - n; - c = (k >> 3) < c ? k >> 3 : c; - n += c; - p -= c; - k -= (c << 3); + blocks.bitb = b; + blocks.bitk = k; + z.AvailableBytesIn = n; + z.TotalBytesIn += p - z.NextIn; + z.NextIn = p; + blocks.writeAt = q; + return blocks.Flush(r); - s.bitb = b; - s.bitk = k; - z.AvailableBytesIn = n; - z.TotalBytesIn += p - z.NextIn; - z.NextIn = p; - s.writeAt = q; + default: + r = ZlibConstants.Z_STREAM_ERROR; - return ZlibConstants.Z_OK; + blocks.bitb = b; + blocks.bitk = k; + z.AvailableBytesIn = n; + z.TotalBytesIn += p - z.NextIn; + z.NextIn = p; + blocks.writeAt = q; + return blocks.Flush(r); + } } } - internal sealed class InflateManager + // Called with number of bytes left to write in window at least 258 + // (the maximum string length) and number of input bytes available + // at least ten. The ten bytes are six bytes for the longest length/ + // distance pair plus four bytes for overloading the bit buffer. + + internal int InflateFast( + int bl, + int bd, + int[] tl, + int tl_index, + int[] td, + int td_index, + InflateBlocks s, + ZlibCodec z + ) { - // preset dictionary flag in zlib header - private const int PRESET_DICT = 0x20; + int t; // temporary pointer + int[] tp; // temporary pointer + int tp_index; // temporary pointer + int e; // extra bits or operation + int b; // bit buffer + int k; // bits in bit buffer + int p; // input data pointer + int n; // bytes available there + int q; // output window write pointer + int m; // bytes to end of window or read pointer + int ml; // mask for literal/length tree + int md; // mask for distance tree + int c; // bytes to copy + int d; // distance back to copy from + int r; // copy source pointer - private const int Z_DEFLATED = 8; - private static readonly byte[] mark = { 0, 0, 0xff, 0xff }; + int tp_index_t_3; // (tp_index+t)*3 - internal ZlibCodec _codec; // pointer back to this zlib stream - internal InflateBlocks blocks; // current inflate_blocks state + // load input, output, bit values + p = z.NextIn; + n = z.AvailableBytesIn; + b = s.bitb; + k = s.bitk; + q = s.writeAt; + m = q < s.readAt ? s.readAt - q - 1 : s.end - q; - // mode dependent information + // initialize masks + ml = InternalInflateConstants.InflateMask[bl]; + md = InternalInflateConstants.InflateMask[bd]; - // if CHECK, check values to compare - internal uint computedCheck; // computed check value - internal uint expectedCheck; // stream check value - - // if BAD, inflateSync's marker bytes count - internal int marker; - internal int method; // if FLAGS, method byte - private InflateManagerMode mode; // current inflate mode - - // mode independent information - //internal int nowrap; // flag for no wrapper - - internal int wbits; // log2(window size) (8..15, defaults to 15) - - public InflateManager() { } - - public InflateManager(bool expectRfc1950HeaderBytes) + // do until not enough input or output space for fast loop + do { - HandleRfc1950HeaderBytes = expectRfc1950HeaderBytes; - } - - internal bool HandleRfc1950HeaderBytes { get; set; } = true; - - internal int Reset() - { - _codec.TotalBytesIn = _codec.TotalBytesOut = 0; - _codec.Message = null; - mode = HandleRfc1950HeaderBytes ? InflateManagerMode.METHOD : InflateManagerMode.BLOCKS; - blocks.Reset(); - return ZlibConstants.Z_OK; - } - - internal int End() - { - if (blocks != null) + // assume called with m >= 258 && n >= 10 + // get literal/length code + while (k < (20)) { - blocks.Free(); - } - blocks = null; - return ZlibConstants.Z_OK; - } - - internal int Initialize(ZlibCodec codec, int w) - { - _codec = codec; - _codec.Message = null; - blocks = null; - - // handle undocumented nowrap option (no zlib header or check) - //nowrap = 0; - //if (w < 0) - //{ - // w = - w; - // nowrap = 1; - //} - - // set window size - if (w < 8 || w > 15) - { - End(); - throw new ZlibException("Bad window size."); - - //return ZlibConstants.Z_STREAM_ERROR; - } - wbits = w; - - blocks = new InflateBlocks(codec, HandleRfc1950HeaderBytes ? this : null, 1 << w); - - // reset state - Reset(); - return ZlibConstants.Z_OK; - } - - internal int Inflate(FlushType flush) - { - int b; - - if (_codec.InputBuffer is null) - { - throw new ZlibException("InputBuffer is null. "); + // max bits for literal/length code + n--; + b |= (z.InputBuffer[p++] & 0xff) << k; + k += 8; } - // int f = (flush == FlushType.Finish) - // ? ZlibConstants.Z_BUF_ERROR - // : ZlibConstants.Z_OK; - - // workitem 8870 - int f = ZlibConstants.Z_OK; - int r = ZlibConstants.Z_BUF_ERROR; - - while (true) + t = b & ml; + tp = tl; + tp_index = tl_index; + tp_index_t_3 = (tp_index + t) * 3; + if ((e = tp[tp_index_t_3]) == 0) { - switch (mode) + b >>= (tp[tp_index_t_3 + 1]); + k -= (tp[tp_index_t_3 + 1]); + + s.window[q++] = (byte)tp[tp_index_t_3 + 2]; + m--; + continue; + } + do + { + b >>= (tp[tp_index_t_3 + 1]); + k -= (tp[tp_index_t_3 + 1]); + + if ((e & 16) != 0) { - case InflateManagerMode.METHOD: - if (_codec.AvailableBytesIn == 0) + e &= 15; + c = tp[tp_index_t_3 + 2] + (b & InternalInflateConstants.InflateMask[e]); + + b >>= e; + k -= e; + + // decode distance base of block to copy + while (k < 15) + { + // max bits for distance code + n--; + b |= (z.InputBuffer[p++] & 0xff) << k; + k += 8; + } + + t = b & md; + tp = td; + tp_index = td_index; + tp_index_t_3 = (tp_index + t) * 3; + e = tp[tp_index_t_3]; + + do + { + b >>= (tp[tp_index_t_3 + 1]); + k -= (tp[tp_index_t_3 + 1]); + + if ((e & 16) != 0) { - return r; - } - r = f; - _codec.AvailableBytesIn--; - _codec.TotalBytesIn++; - if (((method = _codec.InputBuffer[_codec.NextIn++]) & 0xf) != Z_DEFLATED) - { - mode = InflateManagerMode.BAD; - _codec.Message = String.Format( - "unknown compression method (0x{0:X2})", - method - ); - marker = 5; // can't try inflateSync + // get extra bits to add to distance base + e &= 15; + while (k < e) + { + // get extra bits (up to 13) + n--; + b |= (z.InputBuffer[p++] & 0xff) << k; + k += 8; + } + + d = + tp[tp_index_t_3 + 2] + + (b & InternalInflateConstants.InflateMask[e]); + + b >>= e; + k -= e; + + // do the copy + m -= c; + if (q >= d) + { + // offset before dest + // just copy + r = q - d; + if (q - r > 0 && 2 > (q - r)) + { + s.window[q++] = s.window[r++]; // minimum count is three, + s.window[q++] = s.window[r++]; // so unroll loop a little + c -= 2; + } + else + { + Array.Copy(s.window, r, s.window, q, 2); + q += 2; + r += 2; + c -= 2; + } + } + else + { + // else offset after destination + r = q - d; + do + { + r += s.end; // force pointer in window + } while (r < 0); // covers invalid distances + e = s.end - r; + if (c > e) + { + // if source crosses, + c -= e; // wrapped copy + if (q - r > 0 && e > (q - r)) + { + do + { + s.window[q++] = s.window[r++]; + } while (--e != 0); + } + else + { + Array.Copy(s.window, r, s.window, q, e); + q += e; + r += e; + e = 0; + } + r = 0; // copy rest from start of window + } + } + + // copy all or what's left + if (q - r > 0 && c > (q - r)) + { + do + { + s.window[q++] = s.window[r++]; + } while (--c != 0); + } + else + { + Array.Copy(s.window, r, s.window, q, c); + q += c; + r += c; + c = 0; + } break; } - if ((method >> 4) + 8 > wbits) + if ((e & 64) == 0) { - mode = InflateManagerMode.BAD; - _codec.Message = String.Format( - "invalid window size ({0})", - (method >> 4) + 8 - ); - marker = 5; // can't try inflateSync - break; + t += tp[tp_index_t_3 + 2]; + t += (b & InternalInflateConstants.InflateMask[e]); + tp_index_t_3 = (tp_index + t) * 3; + e = tp[tp_index_t_3]; } - mode = InflateManagerMode.FLAG; - break; - - case InflateManagerMode.FLAG: - if (_codec.AvailableBytesIn == 0) + else { - return r; + z.Message = "invalid distance code"; + + c = z.AvailableBytesIn - n; + c = (k >> 3) < c ? k >> 3 : c; + n += c; + p -= c; + k -= (c << 3); + + s.bitb = b; + s.bitk = k; + z.AvailableBytesIn = n; + z.TotalBytesIn += p - z.NextIn; + z.NextIn = p; + s.writeAt = q; + + return ZlibConstants.Z_DATA_ERROR; } - r = f; - _codec.AvailableBytesIn--; - _codec.TotalBytesIn++; - b = (_codec.InputBuffer[_codec.NextIn++]) & 0xff; - - if ((((method << 8) + b) % 31) != 0) - { - mode = InflateManagerMode.BAD; - _codec.Message = "incorrect header check"; - marker = 5; // can't try inflateSync - break; - } - - mode = - ((b & PRESET_DICT) == 0) - ? InflateManagerMode.BLOCKS - : InflateManagerMode.DICT4; - break; - - case InflateManagerMode.DICT4: - if (_codec.AvailableBytesIn == 0) - { - return r; - } - r = f; - _codec.AvailableBytesIn--; - _codec.TotalBytesIn++; - expectedCheck = (uint)( - (_codec.InputBuffer[_codec.NextIn++] << 24) & 0xff000000 - ); - mode = InflateManagerMode.DICT3; - break; - - case InflateManagerMode.DICT3: - if (_codec.AvailableBytesIn == 0) - { - return r; - } - r = f; - _codec.AvailableBytesIn--; - _codec.TotalBytesIn++; - expectedCheck += (uint)( - (_codec.InputBuffer[_codec.NextIn++] << 16) & 0x00ff0000 - ); - mode = InflateManagerMode.DICT2; - break; - - case InflateManagerMode.DICT2: - - if (_codec.AvailableBytesIn == 0) - { - return r; - } - r = f; - _codec.AvailableBytesIn--; - _codec.TotalBytesIn++; - expectedCheck += (uint)( - (_codec.InputBuffer[_codec.NextIn++] << 8) & 0x0000ff00 - ); - mode = InflateManagerMode.DICT1; - break; - - case InflateManagerMode.DICT1: - if (_codec.AvailableBytesIn == 0) - { - return r; - } - r = f; - _codec.AvailableBytesIn--; - _codec.TotalBytesIn++; - expectedCheck += (uint)(_codec.InputBuffer[_codec.NextIn++] & 0x000000ff); - _codec._adler32 = expectedCheck; - mode = InflateManagerMode.DICT0; - return ZlibConstants.Z_NEED_DICT; - - case InflateManagerMode.DICT0: - mode = InflateManagerMode.BAD; - _codec.Message = "need dictionary"; - marker = 0; // can try inflateSync - return ZlibConstants.Z_STREAM_ERROR; - - case InflateManagerMode.BLOCKS: - r = blocks.Process(r); - if (r == ZlibConstants.Z_DATA_ERROR) - { - mode = InflateManagerMode.BAD; - marker = 0; // can try inflateSync - break; - } - - if (r == ZlibConstants.Z_OK) - { - r = f; - } - - if (r != ZlibConstants.Z_STREAM_END) - { - return r; - } - - r = f; - computedCheck = blocks.Reset(); - if (!HandleRfc1950HeaderBytes) - { - mode = InflateManagerMode.DONE; - return ZlibConstants.Z_STREAM_END; - } - mode = InflateManagerMode.CHECK4; - break; - - case InflateManagerMode.CHECK4: - if (_codec.AvailableBytesIn == 0) - { - return r; - } - r = f; - _codec.AvailableBytesIn--; - _codec.TotalBytesIn++; - expectedCheck = (uint)( - (_codec.InputBuffer[_codec.NextIn++] << 24) & 0xff000000 - ); - mode = InflateManagerMode.CHECK3; - break; - - case InflateManagerMode.CHECK3: - if (_codec.AvailableBytesIn == 0) - { - return r; - } - r = f; - _codec.AvailableBytesIn--; - _codec.TotalBytesIn++; - expectedCheck += (uint)( - (_codec.InputBuffer[_codec.NextIn++] << 16) & 0x00ff0000 - ); - mode = InflateManagerMode.CHECK2; - break; - - case InflateManagerMode.CHECK2: - if (_codec.AvailableBytesIn == 0) - { - return r; - } - r = f; - _codec.AvailableBytesIn--; - _codec.TotalBytesIn++; - expectedCheck += (uint)( - (_codec.InputBuffer[_codec.NextIn++] << 8) & 0x0000ff00 - ); - mode = InflateManagerMode.CHECK1; - break; - - case InflateManagerMode.CHECK1: - if (_codec.AvailableBytesIn == 0) - { - return r; - } - r = f; - _codec.AvailableBytesIn--; - _codec.TotalBytesIn++; - expectedCheck += (uint)(_codec.InputBuffer[_codec.NextIn++] & 0x000000ff); - if (computedCheck != expectedCheck) - { - mode = InflateManagerMode.BAD; - _codec.Message = "incorrect data check"; - marker = 5; // can't try inflateSync - break; - } - mode = InflateManagerMode.DONE; - return ZlibConstants.Z_STREAM_END; - - case InflateManagerMode.DONE: - return ZlibConstants.Z_STREAM_END; - - case InflateManagerMode.BAD: - throw new ZlibException(String.Format("Bad state ({0})", _codec.Message)); - - default: - throw new ZlibException("Stream error."); + } while (true); + break; } - } - } - internal int SetDictionary(byte[] dictionary) - { - int index = 0; - int length = dictionary.Length; - if (mode != InflateManagerMode.DICT0) - { - throw new ZlibException("Stream error."); - } - - if (Adler32.Calculate(1, dictionary) != _codec._adler32) - { - return ZlibConstants.Z_DATA_ERROR; - } - - _codec._adler32 = 1; - - if (length >= (1 << wbits)) - { - length = (1 << wbits) - 1; - index = dictionary.Length - length; - } - blocks.SetDictionary(dictionary, index, length); - mode = InflateManagerMode.BLOCKS; - return ZlibConstants.Z_OK; - } - - internal int Sync() - { - int n; // number of bytes to look at - int p; // pointer to bytes - int m; // number of marker bytes found in a row - long r, - w; // temporaries to save total_in and total_out - - // set up - if (mode != InflateManagerMode.BAD) - { - mode = InflateManagerMode.BAD; - marker = 0; - } - if ((n = _codec.AvailableBytesIn) == 0) - { - return ZlibConstants.Z_BUF_ERROR; - } - p = _codec.NextIn; - m = marker; - - // search - while (n != 0 && m < 4) - { - if (_codec.InputBuffer[p] == mark[m]) + if ((e & 64) == 0) { - m++; + t += tp[tp_index_t_3 + 2]; + t += (b & InternalInflateConstants.InflateMask[e]); + tp_index_t_3 = (tp_index + t) * 3; + if ((e = tp[tp_index_t_3]) == 0) + { + b >>= (tp[tp_index_t_3 + 1]); + k -= (tp[tp_index_t_3 + 1]); + s.window[q++] = (byte)tp[tp_index_t_3 + 2]; + m--; + break; + } } - else if (_codec.InputBuffer[p] != 0) + else if ((e & 32) != 0) { - m = 0; + c = z.AvailableBytesIn - n; + c = (k >> 3) < c ? k >> 3 : c; + n += c; + p -= c; + k -= (c << 3); + + s.bitb = b; + s.bitk = k; + z.AvailableBytesIn = n; + z.TotalBytesIn += p - z.NextIn; + z.NextIn = p; + s.writeAt = q; + + return ZlibConstants.Z_STREAM_END; } else { - m = 4 - m; + z.Message = "invalid literal/length code"; + + c = z.AvailableBytesIn - n; + c = (k >> 3) < c ? k >> 3 : c; + n += c; + p -= c; + k -= (c << 3); + + s.bitb = b; + s.bitk = k; + z.AvailableBytesIn = n; + z.TotalBytesIn += p - z.NextIn; + z.NextIn = p; + s.writeAt = q; + + return ZlibConstants.Z_DATA_ERROR; } - p++; - n--; - } + } while (true); + } while (m >= 258 && n >= 10); - // restore - _codec.TotalBytesIn += p - _codec.NextIn; - _codec.NextIn = p; - _codec.AvailableBytesIn = n; - marker = m; + // not enough input or output--restore pointers and return + c = z.AvailableBytesIn - n; + c = (k >> 3) < c ? k >> 3 : c; + n += c; + p -= c; + k -= (c << 3); - // return no joy or set up to restart on a new block - if (m != 4) - { - return ZlibConstants.Z_DATA_ERROR; - } - r = _codec.TotalBytesIn; - w = _codec.TotalBytesOut; - Reset(); - _codec.TotalBytesIn = r; - _codec.TotalBytesOut = w; - mode = InflateManagerMode.BLOCKS; - return ZlibConstants.Z_OK; - } + s.bitb = b; + s.bitk = k; + z.AvailableBytesIn = n; + z.TotalBytesIn += p - z.NextIn; + z.NextIn = p; + s.writeAt = q; - // Returns true if inflate is currently at the end of a block generated - // by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP - // implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH - // but removes the length bytes of the resulting empty stored block. When - // decompressing, PPP checks that at the end of input packet, inflate is - // waiting for these length bytes. - internal int SyncPoint(ZlibCodec z) - { - return blocks.SyncPoint(); - } - - #region Nested type: InflateManagerMode - - private enum InflateManagerMode - { - METHOD = 0, // waiting for method byte - FLAG = 1, // waiting for flag byte - DICT4 = 2, // four dictionary check bytes to go - DICT3 = 3, // three dictionary check bytes to go - DICT2 = 4, // two dictionary check bytes to go - DICT1 = 5, // one dictionary check byte to go - DICT0 = 6, // waiting for inflateSetDictionary - BLOCKS = 7, // decompressing blocks - CHECK4 = 8, // four check bytes to go - CHECK3 = 9, // three check bytes to go - CHECK2 = 10, // two check bytes to go - CHECK1 = 11, // one check byte to go - DONE = 12, // finished check, done - BAD = 13 // got an error--stay here - } - - #endregion + return ZlibConstants.Z_OK; } } + +internal sealed class InflateManager +{ + // preset dictionary flag in zlib header + private const int PRESET_DICT = 0x20; + + private const int Z_DEFLATED = 8; + private static readonly byte[] mark = { 0, 0, 0xff, 0xff }; + + internal ZlibCodec _codec; // pointer back to this zlib stream + internal InflateBlocks blocks; // current inflate_blocks state + + // mode dependent information + + // if CHECK, check values to compare + internal uint computedCheck; // computed check value + internal uint expectedCheck; // stream check value + + // if BAD, inflateSync's marker bytes count + internal int marker; + internal int method; // if FLAGS, method byte + private InflateManagerMode mode; // current inflate mode + + // mode independent information + //internal int nowrap; // flag for no wrapper + + internal int wbits; // log2(window size) (8..15, defaults to 15) + + public InflateManager() { } + + public InflateManager(bool expectRfc1950HeaderBytes) + { + HandleRfc1950HeaderBytes = expectRfc1950HeaderBytes; + } + + internal bool HandleRfc1950HeaderBytes { get; set; } = true; + + internal int Reset() + { + _codec.TotalBytesIn = _codec.TotalBytesOut = 0; + _codec.Message = null; + mode = HandleRfc1950HeaderBytes ? InflateManagerMode.METHOD : InflateManagerMode.BLOCKS; + blocks.Reset(); + return ZlibConstants.Z_OK; + } + + internal int End() + { + blocks?.Free(); + blocks = null; + return ZlibConstants.Z_OK; + } + + internal int Initialize(ZlibCodec codec, int w) + { + _codec = codec; + _codec.Message = null; + blocks = null; + + // handle undocumented nowrap option (no zlib header or check) + //nowrap = 0; + //if (w < 0) + //{ + // w = - w; + // nowrap = 1; + //} + + // set window size + if (w < 8 || w > 15) + { + End(); + throw new ZlibException("Bad window size."); + + //return ZlibConstants.Z_STREAM_ERROR; + } + wbits = w; + + blocks = new InflateBlocks(codec, HandleRfc1950HeaderBytes ? this : null, 1 << w); + + // reset state + Reset(); + return ZlibConstants.Z_OK; + } + + internal int Inflate(FlushType flush) + { + int b; + + if (_codec.InputBuffer is null) + { + throw new ZlibException("InputBuffer is null. "); + } + + // int f = (flush == FlushType.Finish) + // ? ZlibConstants.Z_BUF_ERROR + // : ZlibConstants.Z_OK; + + // workitem 8870 + var f = ZlibConstants.Z_OK; + var r = ZlibConstants.Z_BUF_ERROR; + + while (true) + { + switch (mode) + { + case InflateManagerMode.METHOD: + if (_codec.AvailableBytesIn == 0) + { + return r; + } + r = f; + _codec.AvailableBytesIn--; + _codec.TotalBytesIn++; + if (((method = _codec.InputBuffer[_codec.NextIn++]) & 0xf) != Z_DEFLATED) + { + mode = InflateManagerMode.BAD; + _codec.Message = string.Format( + "unknown compression method (0x{0:X2})", + method + ); + marker = 5; // can't try inflateSync + break; + } + if ((method >> 4) + 8 > wbits) + { + mode = InflateManagerMode.BAD; + _codec.Message = string.Format( + "invalid window size ({0})", + (method >> 4) + 8 + ); + marker = 5; // can't try inflateSync + break; + } + mode = InflateManagerMode.FLAG; + break; + + case InflateManagerMode.FLAG: + if (_codec.AvailableBytesIn == 0) + { + return r; + } + r = f; + _codec.AvailableBytesIn--; + _codec.TotalBytesIn++; + b = (_codec.InputBuffer[_codec.NextIn++]) & 0xff; + + if ((((method << 8) + b) % 31) != 0) + { + mode = InflateManagerMode.BAD; + _codec.Message = "incorrect header check"; + marker = 5; // can't try inflateSync + break; + } + + mode = + ((b & PRESET_DICT) == 0) + ? InflateManagerMode.BLOCKS + : InflateManagerMode.DICT4; + break; + + case InflateManagerMode.DICT4: + if (_codec.AvailableBytesIn == 0) + { + return r; + } + r = f; + _codec.AvailableBytesIn--; + _codec.TotalBytesIn++; + expectedCheck = (uint)( + (_codec.InputBuffer[_codec.NextIn++] << 24) & 0xff000000 + ); + mode = InflateManagerMode.DICT3; + break; + + case InflateManagerMode.DICT3: + if (_codec.AvailableBytesIn == 0) + { + return r; + } + r = f; + _codec.AvailableBytesIn--; + _codec.TotalBytesIn++; + expectedCheck += (uint)( + (_codec.InputBuffer[_codec.NextIn++] << 16) & 0x00ff0000 + ); + mode = InflateManagerMode.DICT2; + break; + + case InflateManagerMode.DICT2: + + if (_codec.AvailableBytesIn == 0) + { + return r; + } + r = f; + _codec.AvailableBytesIn--; + _codec.TotalBytesIn++; + expectedCheck += (uint)( + (_codec.InputBuffer[_codec.NextIn++] << 8) & 0x0000ff00 + ); + mode = InflateManagerMode.DICT1; + break; + + case InflateManagerMode.DICT1: + if (_codec.AvailableBytesIn == 0) + { + return r; + } + r = f; + _codec.AvailableBytesIn--; + _codec.TotalBytesIn++; + expectedCheck += (uint)(_codec.InputBuffer[_codec.NextIn++] & 0x000000ff); + _codec._adler32 = expectedCheck; + mode = InflateManagerMode.DICT0; + return ZlibConstants.Z_NEED_DICT; + + case InflateManagerMode.DICT0: + mode = InflateManagerMode.BAD; + _codec.Message = "need dictionary"; + marker = 0; // can try inflateSync + return ZlibConstants.Z_STREAM_ERROR; + + case InflateManagerMode.BLOCKS: + r = blocks.Process(r); + if (r == ZlibConstants.Z_DATA_ERROR) + { + mode = InflateManagerMode.BAD; + marker = 0; // can try inflateSync + break; + } + + if (r == ZlibConstants.Z_OK) + { + r = f; + } + + if (r != ZlibConstants.Z_STREAM_END) + { + return r; + } + + r = f; + computedCheck = blocks.Reset(); + if (!HandleRfc1950HeaderBytes) + { + mode = InflateManagerMode.DONE; + return ZlibConstants.Z_STREAM_END; + } + mode = InflateManagerMode.CHECK4; + break; + + case InflateManagerMode.CHECK4: + if (_codec.AvailableBytesIn == 0) + { + return r; + } + r = f; + _codec.AvailableBytesIn--; + _codec.TotalBytesIn++; + expectedCheck = (uint)( + (_codec.InputBuffer[_codec.NextIn++] << 24) & 0xff000000 + ); + mode = InflateManagerMode.CHECK3; + break; + + case InflateManagerMode.CHECK3: + if (_codec.AvailableBytesIn == 0) + { + return r; + } + r = f; + _codec.AvailableBytesIn--; + _codec.TotalBytesIn++; + expectedCheck += (uint)( + (_codec.InputBuffer[_codec.NextIn++] << 16) & 0x00ff0000 + ); + mode = InflateManagerMode.CHECK2; + break; + + case InflateManagerMode.CHECK2: + if (_codec.AvailableBytesIn == 0) + { + return r; + } + r = f; + _codec.AvailableBytesIn--; + _codec.TotalBytesIn++; + expectedCheck += (uint)( + (_codec.InputBuffer[_codec.NextIn++] << 8) & 0x0000ff00 + ); + mode = InflateManagerMode.CHECK1; + break; + + case InflateManagerMode.CHECK1: + if (_codec.AvailableBytesIn == 0) + { + return r; + } + r = f; + _codec.AvailableBytesIn--; + _codec.TotalBytesIn++; + expectedCheck += (uint)(_codec.InputBuffer[_codec.NextIn++] & 0x000000ff); + if (computedCheck != expectedCheck) + { + mode = InflateManagerMode.BAD; + _codec.Message = "incorrect data check"; + marker = 5; // can't try inflateSync + break; + } + mode = InflateManagerMode.DONE; + return ZlibConstants.Z_STREAM_END; + + case InflateManagerMode.DONE: + return ZlibConstants.Z_STREAM_END; + + case InflateManagerMode.BAD: + throw new ZlibException(string.Format("Bad state ({0})", _codec.Message)); + + default: + throw new ZlibException("Stream error."); + } + } + } + + internal int SetDictionary(byte[] dictionary) + { + var index = 0; + var length = dictionary.Length; + if (mode != InflateManagerMode.DICT0) + { + throw new ZlibException("Stream error."); + } + + if (Adler32.Calculate(1, dictionary) != _codec._adler32) + { + return ZlibConstants.Z_DATA_ERROR; + } + + _codec._adler32 = 1; + + if (length >= (1 << wbits)) + { + length = (1 << wbits) - 1; + index = dictionary.Length - length; + } + blocks.SetDictionary(dictionary, index, length); + mode = InflateManagerMode.BLOCKS; + return ZlibConstants.Z_OK; + } + + internal int Sync() + { + int n; // number of bytes to look at + int p; // pointer to bytes + int m; // number of marker bytes found in a row + long r, + w; // temporaries to save total_in and total_out + + // set up + if (mode != InflateManagerMode.BAD) + { + mode = InflateManagerMode.BAD; + marker = 0; + } + if ((n = _codec.AvailableBytesIn) == 0) + { + return ZlibConstants.Z_BUF_ERROR; + } + p = _codec.NextIn; + m = marker; + + // search + while (n != 0 && m < 4) + { + if (_codec.InputBuffer[p] == mark[m]) + { + m++; + } + else if (_codec.InputBuffer[p] != 0) + { + m = 0; + } + else + { + m = 4 - m; + } + p++; + n--; + } + + // restore + _codec.TotalBytesIn += p - _codec.NextIn; + _codec.NextIn = p; + _codec.AvailableBytesIn = n; + marker = m; + + // return no joy or set up to restart on a new block + if (m != 4) + { + return ZlibConstants.Z_DATA_ERROR; + } + r = _codec.TotalBytesIn; + w = _codec.TotalBytesOut; + Reset(); + _codec.TotalBytesIn = r; + _codec.TotalBytesOut = w; + mode = InflateManagerMode.BLOCKS; + return ZlibConstants.Z_OK; + } + + // Returns true if inflate is currently at the end of a block generated + // by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP + // implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH + // but removes the length bytes of the resulting empty stored block. When + // decompressing, PPP checks that at the end of input packet, inflate is + // waiting for these length bytes. + internal int SyncPoint(ZlibCodec z) + { + return blocks.SyncPoint(); + } + + #region Nested type: InflateManagerMode + + private enum InflateManagerMode + { + METHOD = 0, // waiting for method byte + FLAG = 1, // waiting for flag byte + DICT4 = 2, // four dictionary check bytes to go + DICT3 = 3, // three dictionary check bytes to go + DICT2 = 4, // two dictionary check bytes to go + DICT1 = 5, // one dictionary check byte to go + DICT0 = 6, // waiting for inflateSetDictionary + BLOCKS = 7, // decompressing blocks + CHECK4 = 8, // four check bytes to go + CHECK3 = 9, // three check bytes to go + CHECK2 = 10, // two check bytes to go + CHECK1 = 11, // one check byte to go + DONE = 12, // finished check, done + BAD = 13 // got an error--stay here + } + + #endregion +} diff --git a/src/SharpCompress/Compressors/Deflate/Tree.cs b/src/SharpCompress/Compressors/Deflate/Tree.cs index 3804679d..7056e7a0 100644 --- a/src/SharpCompress/Compressors/Deflate/Tree.cs +++ b/src/SharpCompress/Compressors/Deflate/Tree.cs @@ -64,1171 +64,1170 @@ using System; -namespace SharpCompress.Compressors.Deflate +namespace SharpCompress.Compressors.Deflate; + +internal sealed partial class DeflateManager { - internal sealed partial class DeflateManager + #region Nested type: Tree + + private sealed class Tree { - #region Nested type: Tree + internal const int Buf_size = 8 * 2; + private static readonly int HEAP_SIZE = ((2 * InternalConstants.L_CODES) + 1); - private sealed class Tree + internal static readonly sbyte[] bl_order = { - internal const int Buf_size = 8 * 2; - private static readonly int HEAP_SIZE = (2 * InternalConstants.L_CODES + 1); + 16, + 17, + 18, + 0, + 8, + 7, + 9, + 6, + 10, + 5, + 11, + 4, + 12, + 3, + 13, + 2, + 14, + 1, + 15 + }; - internal static readonly sbyte[] bl_order = + // The lengths of the bit length codes are sent in order of decreasing + // probability, to avoid transmitting the lengths for unused bit + // length codes. + + // see definition of array dist_code below + //internal const int DIST_CODE_LEN = 512; + + private static readonly sbyte[] _dist_code = + { + 0, + 1, + 2, + 3, + 4, + 4, + 5, + 5, + 6, + 6, + 6, + 6, + 7, + 7, + 7, + 7, + 8, + 8, + 8, + 8, + 8, + 8, + 8, + 8, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 10, + 10, + 10, + 10, + 10, + 10, + 10, + 10, + 10, + 10, + 10, + 10, + 10, + 10, + 10, + 10, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 13, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 0, + 0, + 16, + 17, + 18, + 18, + 19, + 19, + 20, + 20, + 20, + 20, + 21, + 21, + 21, + 21, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 28, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 29 + }; + + internal static readonly sbyte[] LengthCode = + { + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 8, + 9, + 9, + 10, + 10, + 11, + 11, + 12, + 12, + 12, + 12, + 13, + 13, + 13, + 13, + 14, + 14, + 14, + 14, + 15, + 15, + 15, + 15, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 17, + 17, + 17, + 17, + 17, + 17, + 17, + 17, + 18, + 18, + 18, + 18, + 18, + 18, + 18, + 18, + 19, + 19, + 19, + 19, + 19, + 19, + 19, + 19, + 20, + 20, + 20, + 20, + 20, + 20, + 20, + 20, + 20, + 20, + 20, + 20, + 20, + 20, + 20, + 20, + 21, + 21, + 21, + 21, + 21, + 21, + 21, + 21, + 21, + 21, + 21, + 21, + 21, + 21, + 21, + 21, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 22, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 23, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 25, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 26, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 27, + 28 + }; + + internal static readonly int[] LengthBase = + { + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 10, + 12, + 14, + 16, + 20, + 24, + 28, + 32, + 40, + 48, + 56, + 64, + 80, + 96, + 112, + 128, + 160, + 192, + 224, + 0 + }; + + internal static readonly int[] DistanceBase = + { + 0, + 1, + 2, + 3, + 4, + 6, + 8, + 12, + 16, + 24, + 32, + 48, + 64, + 96, + 128, + 192, + 256, + 384, + 512, + 768, + 1024, + 1536, + 2048, + 3072, + 4096, + 6144, + 8192, + 12288, + 16384, + 24576 + }; + + internal short[] dyn_tree; // the dynamic tree + internal int max_code; // largest code with non zero frequency + internal StaticTree staticTree; // the corresponding static tree + + /// + /// Map from a distance to a distance code. + /// + /// + /// No side effects. _dist_code[256] and _dist_code[257] are never used. + /// + internal static int DistanceCode(int dist) + { + return (dist < 256) + ? _dist_code[dist] + : _dist_code[256 + SharedUtils.URShift(dist, 7)]; + } + + // Compute the optimal bit lengths for a tree and update the total bit length + // for the current block. + // IN assertion: the fields freq and dad are set, heap[heap_max] and + // above are the tree nodes sorted by increasing frequency. + // OUT assertions: the field len is set to the optimal bit length, the + // array bl_count contains the frequencies for each bit length. + // The length opt_len is updated; static_len is also updated if stree is + // not null. + internal void gen_bitlen(DeflateManager s) + { + var tree = dyn_tree; + var stree = staticTree.treeCodes; + var extra = staticTree.extraBits; + var base_Renamed = staticTree.extraBase; + var max_length = staticTree.maxLength; + int h; // heap index + int n, + m; // iterate over the tree elements + int bits; // bit length + int xbits; // extra bits + short f; // frequency + var overflow = 0; // number of elements with bit length too large + + for (bits = 0; bits <= InternalConstants.MAX_BITS; bits++) { - 16, - 17, - 18, - 0, - 8, - 7, - 9, - 6, - 10, - 5, - 11, - 4, - 12, - 3, - 13, - 2, - 14, - 1, - 15 - }; - - // The lengths of the bit length codes are sent in order of decreasing - // probability, to avoid transmitting the lengths for unused bit - // length codes. - - // see definition of array dist_code below - //internal const int DIST_CODE_LEN = 512; - - private static readonly sbyte[] _dist_code = - { - 0, - 1, - 2, - 3, - 4, - 4, - 5, - 5, - 6, - 6, - 6, - 6, - 7, - 7, - 7, - 7, - 8, - 8, - 8, - 8, - 8, - 8, - 8, - 8, - 9, - 9, - 9, - 9, - 9, - 9, - 9, - 9, - 10, - 10, - 10, - 10, - 10, - 10, - 10, - 10, - 10, - 10, - 10, - 10, - 10, - 10, - 10, - 10, - 11, - 11, - 11, - 11, - 11, - 11, - 11, - 11, - 11, - 11, - 11, - 11, - 11, - 11, - 11, - 11, - 12, - 12, - 12, - 12, - 12, - 12, - 12, - 12, - 12, - 12, - 12, - 12, - 12, - 12, - 12, - 12, - 12, - 12, - 12, - 12, - 12, - 12, - 12, - 12, - 12, - 12, - 12, - 12, - 12, - 12, - 12, - 12, - 13, - 13, - 13, - 13, - 13, - 13, - 13, - 13, - 13, - 13, - 13, - 13, - 13, - 13, - 13, - 13, - 13, - 13, - 13, - 13, - 13, - 13, - 13, - 13, - 13, - 13, - 13, - 13, - 13, - 13, - 13, - 13, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 14, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 15, - 0, - 0, - 16, - 17, - 18, - 18, - 19, - 19, - 20, - 20, - 20, - 20, - 21, - 21, - 21, - 21, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 25, - 25, - 25, - 25, - 25, - 25, - 25, - 25, - 25, - 25, - 25, - 25, - 25, - 25, - 25, - 25, - 26, - 26, - 26, - 26, - 26, - 26, - 26, - 26, - 26, - 26, - 26, - 26, - 26, - 26, - 26, - 26, - 26, - 26, - 26, - 26, - 26, - 26, - 26, - 26, - 26, - 26, - 26, - 26, - 26, - 26, - 26, - 26, - 27, - 27, - 27, - 27, - 27, - 27, - 27, - 27, - 27, - 27, - 27, - 27, - 27, - 27, - 27, - 27, - 27, - 27, - 27, - 27, - 27, - 27, - 27, - 27, - 27, - 27, - 27, - 27, - 27, - 27, - 27, - 27, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 28, - 29, - 29, - 29, - 29, - 29, - 29, - 29, - 29, - 29, - 29, - 29, - 29, - 29, - 29, - 29, - 29, - 29, - 29, - 29, - 29, - 29, - 29, - 29, - 29, - 29, - 29, - 29, - 29, - 29, - 29, - 29, - 29, - 29, - 29, - 29, - 29, - 29, - 29, - 29, - 29, - 29, - 29, - 29, - 29, - 29, - 29, - 29, - 29, - 29, - 29, - 29, - 29, - 29, - 29, - 29, - 29, - 29, - 29, - 29, - 29, - 29, - 29, - 29, - 29 - }; - - internal static readonly sbyte[] LengthCode = - { - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 8, - 9, - 9, - 10, - 10, - 11, - 11, - 12, - 12, - 12, - 12, - 13, - 13, - 13, - 13, - 14, - 14, - 14, - 14, - 15, - 15, - 15, - 15, - 16, - 16, - 16, - 16, - 16, - 16, - 16, - 16, - 17, - 17, - 17, - 17, - 17, - 17, - 17, - 17, - 18, - 18, - 18, - 18, - 18, - 18, - 18, - 18, - 19, - 19, - 19, - 19, - 19, - 19, - 19, - 19, - 20, - 20, - 20, - 20, - 20, - 20, - 20, - 20, - 20, - 20, - 20, - 20, - 20, - 20, - 20, - 20, - 21, - 21, - 21, - 21, - 21, - 21, - 21, - 21, - 21, - 21, - 21, - 21, - 21, - 21, - 21, - 21, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 22, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 23, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 24, - 25, - 25, - 25, - 25, - 25, - 25, - 25, - 25, - 25, - 25, - 25, - 25, - 25, - 25, - 25, - 25, - 25, - 25, - 25, - 25, - 25, - 25, - 25, - 25, - 25, - 25, - 25, - 25, - 25, - 25, - 25, - 25, - 26, - 26, - 26, - 26, - 26, - 26, - 26, - 26, - 26, - 26, - 26, - 26, - 26, - 26, - 26, - 26, - 26, - 26, - 26, - 26, - 26, - 26, - 26, - 26, - 26, - 26, - 26, - 26, - 26, - 26, - 26, - 26, - 27, - 27, - 27, - 27, - 27, - 27, - 27, - 27, - 27, - 27, - 27, - 27, - 27, - 27, - 27, - 27, - 27, - 27, - 27, - 27, - 27, - 27, - 27, - 27, - 27, - 27, - 27, - 27, - 27, - 27, - 27, - 28 - }; - - internal static readonly int[] LengthBase = - { - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 10, - 12, - 14, - 16, - 20, - 24, - 28, - 32, - 40, - 48, - 56, - 64, - 80, - 96, - 112, - 128, - 160, - 192, - 224, - 0 - }; - - internal static readonly int[] DistanceBase = - { - 0, - 1, - 2, - 3, - 4, - 6, - 8, - 12, - 16, - 24, - 32, - 48, - 64, - 96, - 128, - 192, - 256, - 384, - 512, - 768, - 1024, - 1536, - 2048, - 3072, - 4096, - 6144, - 8192, - 12288, - 16384, - 24576 - }; - - internal short[] dyn_tree; // the dynamic tree - internal int max_code; // largest code with non zero frequency - internal StaticTree staticTree; // the corresponding static tree - - /// - /// Map from a distance to a distance code. - /// - /// - /// No side effects. _dist_code[256] and _dist_code[257] are never used. - /// - internal static int DistanceCode(int dist) - { - return (dist < 256) - ? _dist_code[dist] - : _dist_code[256 + SharedUtils.URShift(dist, 7)]; + s.bl_count[bits] = 0; } - // Compute the optimal bit lengths for a tree and update the total bit length - // for the current block. - // IN assertion: the fields freq and dad are set, heap[heap_max] and - // above are the tree nodes sorted by increasing frequency. - // OUT assertions: the field len is set to the optimal bit length, the - // array bl_count contains the frequencies for each bit length. - // The length opt_len is updated; static_len is also updated if stree is - // not null. - internal void gen_bitlen(DeflateManager s) + // In a first pass, compute the optimal bit lengths (which may + // overflow in the case of the bit length tree). + tree[(s.heap[s.heap_max] * 2) + 1] = 0; // root of the heap + + for (h = s.heap_max + 1; h < HEAP_SIZE; h++) { - short[] tree = dyn_tree; - short[] stree = staticTree.treeCodes; - int[] extra = staticTree.extraBits; - int base_Renamed = staticTree.extraBase; - int max_length = staticTree.maxLength; - int h; // heap index - int n, - m; // iterate over the tree elements - int bits; // bit length - int xbits; // extra bits - short f; // frequency - int overflow = 0; // number of elements with bit length too large - - for (bits = 0; bits <= InternalConstants.MAX_BITS; bits++) + n = s.heap[h]; + bits = tree[(tree[(n * 2) + 1] * 2) + 1] + 1; + if (bits > max_length) { - s.bl_count[bits] = 0; + bits = max_length; + overflow++; + } + tree[(n * 2) + 1] = (short)bits; + + // We overwrite tree[n*2+1] which is no longer needed + + if (n > max_code) + { + continue; // not a leaf node } - // In a first pass, compute the optimal bit lengths (which may - // overflow in the case of the bit length tree). - tree[s.heap[s.heap_max] * 2 + 1] = 0; // root of the heap - - for (h = s.heap_max + 1; h < HEAP_SIZE; h++) + s.bl_count[bits]++; + xbits = 0; + if (n >= base_Renamed) { - n = s.heap[h]; - bits = tree[tree[n * 2 + 1] * 2 + 1] + 1; - if (bits > max_length) - { - bits = max_length; - overflow++; - } - tree[n * 2 + 1] = (short)bits; - - // We overwrite tree[n*2+1] which is no longer needed - - if (n > max_code) - { - continue; // not a leaf node - } - - s.bl_count[bits]++; - xbits = 0; - if (n >= base_Renamed) - { - xbits = extra[n - base_Renamed]; - } - f = tree[n * 2]; - s.opt_len += f * (bits + xbits); - if (stree != null) - { - s.static_len += f * (stree[n * 2 + 1] + xbits); - } + xbits = extra[n - base_Renamed]; } - if (overflow == 0) + f = tree[n * 2]; + s.opt_len += f * (bits + xbits); + if (stree != null) { - return; - } - - // This happens for example on obj2 and pic of the Calgary corpus - // Find the first bit length which could increase: - do - { - bits = max_length - 1; - while (s.bl_count[bits] == 0) - { - bits--; - } - s.bl_count[bits]--; // move one leaf down the tree - s.bl_count[bits + 1] = (short)(s.bl_count[bits + 1] + 2); // move one overflow item as its brother - s.bl_count[max_length]--; - - // The brother of the overflow item also moves one step up, - // but this does not affect bl_count[max_length] - overflow -= 2; - } while (overflow > 0); - - for (bits = max_length; bits != 0; bits--) - { - n = s.bl_count[bits]; - while (n != 0) - { - m = s.heap[--h]; - if (m > max_code) - { - continue; - } - if (tree[m * 2 + 1] != bits) - { - s.opt_len = (int)( - s.opt_len + (bits - (long)tree[m * 2 + 1]) * tree[m * 2] - ); - tree[m * 2 + 1] = (short)bits; - } - n--; - } + s.static_len += f * (stree[(n * 2) + 1] + xbits); } } - - // Construct one Huffman tree and assigns the code bit strings and lengths. - // Update the total bit length for the current block. - // IN assertion: the field freq is set for all tree elements. - // OUT assertions: the fields len and code are set to the optimal bit length - // and corresponding code. The length opt_len is updated; static_len is - // also updated if stree is not null. The field max_code is set. - internal void build_tree(DeflateManager s) + if (overflow == 0) { - short[] tree = dyn_tree; - short[] stree = staticTree.treeCodes; - int elems = staticTree.elems; - int n, - m; // iterate over heap elements - int max_code = -1; // largest code with non zero frequency - int node; // new node being created - - // Construct the initial heap, with least frequent element in - // heap[1]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. - // heap[0] is not used. - s.heap_len = 0; - s.heap_max = HEAP_SIZE; - - for (n = 0; n < elems; n++) - { - if (tree[n * 2] != 0) - { - s.heap[++s.heap_len] = max_code = n; - s.depth[n] = 0; - } - else - { - tree[n * 2 + 1] = 0; - } - } - - // The pkzip format requires that at least one distance code exists, - // and that at least one bit should be sent even if there is only one - // possible code. So to avoid special checks later on we force at least - // two codes of non zero frequency. - while (s.heap_len < 2) - { - node = s.heap[++s.heap_len] = (max_code < 2 ? ++max_code : 0); - tree[node * 2] = 1; - s.depth[node] = 0; - s.opt_len--; - if (stree != null) - { - s.static_len -= stree[node * 2 + 1]; - } - - // node is 0 or 1 so it does not have extra bits - } - this.max_code = max_code; - - // The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, - // establish sub-heaps of increasing lengths: - - for (n = s.heap_len / 2; n >= 1; n--) - { - s.pqdownheap(tree, n); - } - - // Construct the Huffman tree by repeatedly combining the least two - // frequent nodes. - - node = elems; // next internal node of the tree - do - { - // n = node of least frequency - n = s.heap[1]; - s.heap[1] = s.heap[s.heap_len--]; - s.pqdownheap(tree, 1); - m = s.heap[1]; // m = node of next least frequency - - s.heap[--s.heap_max] = n; // keep the nodes sorted by frequency - s.heap[--s.heap_max] = m; - - // Create a new node father of n and m - tree[node * 2] = unchecked((short)(tree[n * 2] + tree[m * 2])); - s.depth[node] = (sbyte)(Math.Max((byte)s.depth[n], (byte)s.depth[m]) + 1); - tree[n * 2 + 1] = tree[m * 2 + 1] = (short)node; - - // and insert the new node in the heap - s.heap[1] = node++; - s.pqdownheap(tree, 1); - } while (s.heap_len >= 2); - - s.heap[--s.heap_max] = s.heap[1]; - - // At this point, the fields freq and dad are set. We can now - // generate the bit lengths. - - gen_bitlen(s); - - // The field len is now set, we can generate the bit codes - gen_codes(tree, max_code, s.bl_count); + return; } - // Generate the codes for a given tree and bit counts (which need not be - // optimal). - // IN assertion: the array bl_count contains the bit length statistics for - // the given tree and the field len is set for all tree elements. - // OUT assertion: the field code is set for all tree elements of non - // zero code length. - internal static void gen_codes(short[] tree, int max_code, short[] bl_count) + // This happens for example on obj2 and pic of the Calgary corpus + // Find the first bit length which could increase: + do { - var next_code = new short[InternalConstants.MAX_BITS + 1]; // next code value for each bit length - short code = 0; // running code value - int bits; // bit index - int n; // code index - - // The distribution counts are first used to generate the code values - // without bit reversal. - for (bits = 1; bits <= InternalConstants.MAX_BITS; bits++) + bits = max_length - 1; + while (s.bl_count[bits] == 0) { - unchecked - { - next_code[bits] = code = (short)((code + bl_count[bits - 1]) << 1); - } + bits--; } + s.bl_count[bits]--; // move one leaf down the tree + s.bl_count[bits + 1] = (short)(s.bl_count[bits + 1] + 2); // move one overflow item as its brother + s.bl_count[max_length]--; - // Check that the bit counts in bl_count are consistent. The last code - // must be all ones. - //Assert (code + bl_count[MAX_BITS]-1 == (1< 0); - for (n = 0; n <= max_code; n++) + for (bits = max_length; bits != 0; bits--) + { + n = s.bl_count[bits]; + while (n != 0) { - int len = tree[n * 2 + 1]; - if (len == 0) + m = s.heap[--h]; + if (m > max_code) { continue; } - - // Now reverse the bits - tree[n * 2] = unchecked((short)(bi_reverse(next_code[len]++, len))); + if (tree[(m * 2) + 1] != bits) + { + s.opt_len = (int)( + s.opt_len + ((bits - (long)tree[(m * 2) + 1]) * tree[m * 2]) + ); + tree[(m * 2) + 1] = (short)bits; + } + n--; } } - - // Reverse the first len bits of a code, using straightforward code (a faster - // method would use a table) - // IN assertion: 1 <= len <= 15 - internal static int bi_reverse(int code, int len) - { - int res = 0; - do - { - res |= code & 1; - code >>= 1; //SharedUtils.URShift(code, 1); - res <<= 1; - } while (--len > 0); - return res >> 1; - } } - #endregion + // Construct one Huffman tree and assigns the code bit strings and lengths. + // Update the total bit length for the current block. + // IN assertion: the field freq is set for all tree elements. + // OUT assertions: the fields len and code are set to the optimal bit length + // and corresponding code. The length opt_len is updated; static_len is + // also updated if stree is not null. The field max_code is set. + internal void build_tree(DeflateManager s) + { + var tree = dyn_tree; + var stree = staticTree.treeCodes; + var elems = staticTree.elems; + int n, + m; // iterate over heap elements + var max_code = -1; // largest code with non zero frequency + int node; // new node being created + + // Construct the initial heap, with least frequent element in + // heap[1]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. + // heap[0] is not used. + s.heap_len = 0; + s.heap_max = HEAP_SIZE; + + for (n = 0; n < elems; n++) + { + if (tree[n * 2] != 0) + { + s.heap[++s.heap_len] = max_code = n; + s.depth[n] = 0; + } + else + { + tree[(n * 2) + 1] = 0; + } + } + + // The pkzip format requires that at least one distance code exists, + // and that at least one bit should be sent even if there is only one + // possible code. So to avoid special checks later on we force at least + // two codes of non zero frequency. + while (s.heap_len < 2) + { + node = s.heap[++s.heap_len] = (max_code < 2 ? ++max_code : 0); + tree[node * 2] = 1; + s.depth[node] = 0; + s.opt_len--; + if (stree != null) + { + s.static_len -= stree[(node * 2) + 1]; + } + + // node is 0 or 1 so it does not have extra bits + } + this.max_code = max_code; + + // The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + // establish sub-heaps of increasing lengths: + + for (n = s.heap_len / 2; n >= 1; n--) + { + s.pqdownheap(tree, n); + } + + // Construct the Huffman tree by repeatedly combining the least two + // frequent nodes. + + node = elems; // next internal node of the tree + do + { + // n = node of least frequency + n = s.heap[1]; + s.heap[1] = s.heap[s.heap_len--]; + s.pqdownheap(tree, 1); + m = s.heap[1]; // m = node of next least frequency + + s.heap[--s.heap_max] = n; // keep the nodes sorted by frequency + s.heap[--s.heap_max] = m; + + // Create a new node father of n and m + tree[node * 2] = unchecked((short)(tree[n * 2] + tree[m * 2])); + s.depth[node] = (sbyte)(Math.Max((byte)s.depth[n], (byte)s.depth[m]) + 1); + tree[(n * 2) + 1] = tree[(m * 2) + 1] = (short)node; + + // and insert the new node in the heap + s.heap[1] = node++; + s.pqdownheap(tree, 1); + } while (s.heap_len >= 2); + + s.heap[--s.heap_max] = s.heap[1]; + + // At this point, the fields freq and dad are set. We can now + // generate the bit lengths. + + gen_bitlen(s); + + // The field len is now set, we can generate the bit codes + gen_codes(tree, max_code, s.bl_count); + } + + // Generate the codes for a given tree and bit counts (which need not be + // optimal). + // IN assertion: the array bl_count contains the bit length statistics for + // the given tree and the field len is set for all tree elements. + // OUT assertion: the field code is set for all tree elements of non + // zero code length. + internal static void gen_codes(short[] tree, int max_code, short[] bl_count) + { + var next_code = new short[InternalConstants.MAX_BITS + 1]; // next code value for each bit length + short code = 0; // running code value + int bits; // bit index + int n; // code index + + // The distribution counts are first used to generate the code values + // without bit reversal. + for (bits = 1; bits <= InternalConstants.MAX_BITS; bits++) + { + unchecked + { + next_code[bits] = code = (short)((code + bl_count[bits - 1]) << 1); + } + } + + // Check that the bit counts in bl_count are consistent. The last code + // must be all ones. + //Assert (code + bl_count[MAX_BITS]-1 == (1<>= 1; //SharedUtils.URShift(code, 1); + res <<= 1; + } while (--len > 0); + return res >> 1; + } } + + #endregion } diff --git a/src/SharpCompress/Compressors/Deflate/Zlib.cs b/src/SharpCompress/Compressors/Deflate/Zlib.cs index b8cab22c..0c5865fb 100644 --- a/src/SharpCompress/Compressors/Deflate/Zlib.cs +++ b/src/SharpCompress/Compressors/Deflate/Zlib.cs @@ -65,946 +65,945 @@ using System; using System.IO; -namespace SharpCompress.Compressors.Deflate +namespace SharpCompress.Compressors.Deflate; + +/// +/// The compression level to be used when using a DeflateStream or ZlibStream with CompressionMode.Compress. +/// +public enum CompressionLevel { /// - /// The compression level to be used when using a DeflateStream or ZlibStream with CompressionMode.Compress. + /// None means that the data will be simply stored, with no change at all. + /// If you are producing ZIPs for use on Mac OSX, be aware that archives produced with CompressionLevel.None + /// cannot be opened with the default zip reader. Use a different CompressionLevel. /// - public enum CompressionLevel - { - /// - /// None means that the data will be simply stored, with no change at all. - /// If you are producing ZIPs for use on Mac OSX, be aware that archives produced with CompressionLevel.None - /// cannot be opened with the default zip reader. Use a different CompressionLevel. - /// - None = 0, - - /// - /// Same as None. - /// - Level0 = None, - - /// - /// The fastest but least effective compression. - /// - BestSpeed = 1, - - /// - /// A synonym for BestSpeed. - /// - Level1 = BestSpeed, - - /// - /// A little slower, but better, than level 1. - /// - Level2 = 2, - - /// - /// A little slower, but better, than level 2. - /// - Level3 = 3, - - /// - /// A little slower, but better, than level 3. - /// - Level4 = 4, - - /// - /// A little slower than level 4, but with better compression. - /// - Level5 = 5, - - /// - /// The default compression level, with a good balance of speed and compression efficiency. - /// - Default = 6, - - /// - /// A synonym for Default. - /// - Level6 = Default, - - /// - /// Pretty good compression! - /// - Level7 = 7, - - /// - /// Better compression than Level7! - /// - Level8 = 8, - - /// - /// The "best" compression, where best means greatest reduction in size of the input data stream. - /// This is also the slowest compression. - /// - BestCompression = 9, - - /// - /// A synonym for BestCompression. - /// - Level9 = BestCompression - } + None = 0, /// - /// Describes options for how the compression algorithm is executed. Different strategies - /// work better on different sorts of data. The strategy parameter can affect the compression - /// ratio and the speed of compression but not the correctness of the compresssion. + /// Same as None. /// - public enum CompressionStrategy - { - /// - /// The default strategy is probably the best for normal data. - /// - Default = 0, - - /// - /// The Filtered strategy is intended to be used most effectively with data produced by a - /// filter or predictor. By this definition, filtered data consists mostly of small - /// values with a somewhat random distribution. In this case, the compression algorithm - /// is tuned to compress them better. The effect of Filtered is to force more Huffman - /// coding and less string matching; it is a half-step between Default and HuffmanOnly. - /// - Filtered = 1, - - /// - /// Using HuffmanOnly will force the compressor to do Huffman encoding only, with no - /// string matching. - /// - HuffmanOnly = 2 - } + Level0 = None, /// - /// A general purpose exception class for exceptions in the Zlib library. + /// The fastest but least effective compression. /// - public class ZlibException : Exception - { - /// - /// The ZlibException class captures exception information generated - /// by the Zlib library. - /// - public ZlibException() { } + BestSpeed = 1, - /// - /// This ctor collects a message attached to the exception. - /// - /// - public ZlibException(String s) : base(s) { } + /// + /// A synonym for BestSpeed. + /// + Level1 = BestSpeed, + + /// + /// A little slower, but better, than level 1. + /// + Level2 = 2, + + /// + /// A little slower, but better, than level 2. + /// + Level3 = 3, + + /// + /// A little slower, but better, than level 3. + /// + Level4 = 4, + + /// + /// A little slower than level 4, but with better compression. + /// + Level5 = 5, + + /// + /// The default compression level, with a good balance of speed and compression efficiency. + /// + Default = 6, + + /// + /// A synonym for Default. + /// + Level6 = Default, + + /// + /// Pretty good compression! + /// + Level7 = 7, + + /// + /// Better compression than Level7! + /// + Level8 = 8, + + /// + /// The "best" compression, where best means greatest reduction in size of the input data stream. + /// This is also the slowest compression. + /// + BestCompression = 9, + + /// + /// A synonym for BestCompression. + /// + Level9 = BestCompression +} + +/// +/// Describes options for how the compression algorithm is executed. Different strategies +/// work better on different sorts of data. The strategy parameter can affect the compression +/// ratio and the speed of compression but not the correctness of the compresssion. +/// +public enum CompressionStrategy +{ + /// + /// The default strategy is probably the best for normal data. + /// + Default = 0, + + /// + /// The Filtered strategy is intended to be used most effectively with data produced by a + /// filter or predictor. By this definition, filtered data consists mostly of small + /// values with a somewhat random distribution. In this case, the compression algorithm + /// is tuned to compress them better. The effect of Filtered is to force more Huffman + /// coding and less string matching; it is a half-step between Default and HuffmanOnly. + /// + Filtered = 1, + + /// + /// Using HuffmanOnly will force the compressor to do Huffman encoding only, with no + /// string matching. + /// + HuffmanOnly = 2 +} + +/// +/// A general purpose exception class for exceptions in the Zlib library. +/// +public class ZlibException : Exception +{ + /// + /// The ZlibException class captures exception information generated + /// by the Zlib library. + /// + public ZlibException() { } + + /// + /// This ctor collects a message attached to the exception. + /// + /// + public ZlibException(string s) : base(s) { } +} + +internal class SharedUtils +{ + /// + /// Performs an unsigned bitwise right shift with the specified number + /// + /// Number to operate on + /// Ammount of bits to shift + /// The resulting number from the shift operation + public static int URShift(int number, int bits) + { + return (int)((uint)number >> bits); } - internal class SharedUtils - { - /// - /// Performs an unsigned bitwise right shift with the specified number - /// - /// Number to operate on - /// Ammount of bits to shift - /// The resulting number from the shift operation - public static int URShift(int number, int bits) - { - return (int)((uint)number >> bits); - } - #if NOT - /// - /// Performs an unsigned bitwise right shift with the specified number - /// - /// Number to operate on - /// Ammount of bits to shift - /// The resulting number from the shift operation - public static long URShift(long number, int bits) - { - return (long)((UInt64)number >> bits); - } + /// + /// Performs an unsigned bitwise right shift with the specified number + /// + /// Number to operate on + /// Ammount of bits to shift + /// The resulting number from the shift operation + public static long URShift(long number, int bits) + { + return (long)((UInt64)number >> bits); + } #endif - /// - /// Reads a number of characters from the current source TextReader and writes - /// the data to the target array at the specified index. - /// - /// - /// The source TextReader to read from - /// Contains the array of characteres read from the source TextReader. - /// The starting index of the target array. - /// The maximum number of characters to read from the source TextReader. - /// - /// - /// The number of characters read. The number will be less than or equal to - /// count depending on the data available in the source TextReader. Returns -1 - /// if the end of the stream is reached. - /// - public static Int32 ReadInput( - TextReader sourceTextReader, - byte[] target, - int start, - int count - ) - { - // Returns 0 bytes if not enough space in target - if (target.Length == 0) - { - return 0; - } - - char[] charArray = new char[target.Length]; - int bytesRead = sourceTextReader.Read(charArray, start, count); - - // Returns -1 if EOF - if (bytesRead == 0) - { - return -1; - } - - for (int index = start; index < start + bytesRead; index++) - { - target[index] = (byte)charArray[index]; - } - - return bytesRead; - } - } - - internal static class InternalConstants + /// + /// Reads a number of characters from the current source TextReader and writes + /// the data to the target array at the specified index. + /// + /// + /// The source TextReader to read from + /// Contains the array of characteres read from the source TextReader. + /// The starting index of the target array. + /// The maximum number of characters to read from the source TextReader. + /// + /// + /// The number of characters read. The number will be less than or equal to + /// count depending on the data available in the source TextReader. Returns -1 + /// if the end of the stream is reached. + /// + public static int ReadInput( + TextReader sourceTextReader, + byte[] target, + int start, + int count + ) { - internal static readonly int MAX_BITS = 15; - internal static readonly int BL_CODES = 19; - internal static readonly int D_CODES = 30; - internal static readonly int LITERALS = 256; - internal static readonly int LENGTH_CODES = 29; - internal static readonly int L_CODES = (LITERALS + 1 + LENGTH_CODES); - - // Bit length codes must not exceed MAX_BL_BITS bits - internal static readonly int MAX_BL_BITS = 7; - - // repeat previous bit length 3-6 times (2 bits of repeat count) - internal static readonly int REP_3_6 = 16; - - // repeat a zero length 3-10 times (3 bits of repeat count) - internal static readonly int REPZ_3_10 = 17; - - // repeat a zero length 11-138 times (7 bits of repeat count) - internal static readonly int REPZ_11_138 = 18; - } - - internal sealed class StaticTree - { - internal static readonly short[] lengthAndLiteralsTreeCodes = + // Returns 0 bytes if not enough space in target + if (target.Length == 0) { - 12, - 8, - 140, - 8, - 76, - 8, - 204, - 8, - 44, - 8, - 172, - 8, - 108, - 8, - 236, - 8, - 28, - 8, - 156, - 8, - 92, - 8, - 220, - 8, - 60, - 8, - 188, - 8, - 124, - 8, - 252, - 8, - 2, - 8, - 130, - 8, - 66, - 8, - 194, - 8, - 34, - 8, - 162, - 8, - 98, - 8, - 226, - 8, - 18, - 8, - 146, - 8, - 82, - 8, - 210, - 8, - 50, - 8, - 178, - 8, - 114, - 8, - 242, - 8, - 10, - 8, - 138, - 8, - 74, - 8, - 202, - 8, - 42, - 8, - 170, - 8, - 106, - 8, - 234, - 8, - 26, - 8, - 154, - 8, - 90, - 8, - 218, - 8, - 58, - 8, - 186, - 8, - 122, - 8, - 250, - 8, - 6, - 8, - 134, - 8, - 70, - 8, - 198, - 8, - 38, - 8, - 166, - 8, - 102, - 8, - 230, - 8, - 22, - 8, - 150, - 8, - 86, - 8, - 214, - 8, - 54, - 8, - 182, - 8, - 118, - 8, - 246, - 8, - 14, - 8, - 142, - 8, - 78, - 8, - 206, - 8, - 46, - 8, - 174, - 8, - 110, - 8, - 238, - 8, - 30, - 8, - 158, - 8, - 94, - 8, - 222, - 8, - 62, - 8, - 190, - 8, - 126, - 8, - 254, - 8, - 1, - 8, - 129, - 8, - 65, - 8, - 193, - 8, - 33, - 8, - 161, - 8, - 97, - 8, - 225, - 8, - 17, - 8, - 145, - 8, - 81, - 8, - 209, - 8, - 49, - 8, - 177, - 8, - 113, - 8, - 241, - 8, - 9, - 8, - 137, - 8, - 73, - 8, - 201, - 8, - 41, - 8, - 169, - 8, - 105, - 8, - 233, - 8, - 25, - 8, - 153, - 8, - 89, - 8, - 217, - 8, - 57, - 8, - 185, - 8, - 121, - 8, - 249, - 8, - 5, - 8, - 133, - 8, - 69, - 8, - 197, - 8, - 37, - 8, - 165, - 8, - 101, - 8, - 229, - 8, - 21, - 8, - 149, - 8, - 85, - 8, - 213, - 8, - 53, - 8, - 181, - 8, - 117, - 8, - 245, - 8, - 13, - 8, - 141, - 8, - 77, - 8, - 205, - 8, - 45, - 8, - 173, - 8, - 109, - 8, - 237, - 8, - 29, - 8, - 157, - 8, - 93, - 8, - 221, - 8, - 61, - 8, - 189, - 8, - 125, - 8, - 253, - 8, - 19, - 9, - 275, - 9, - 147, - 9, - 403, - 9, - 83, - 9, - 339, - 9, - 211, - 9, - 467, - 9, - 51, - 9, - 307, - 9, - 179, - 9, - 435, - 9, - 115, - 9, - 371, - 9, - 243, - 9, - 499, - 9, - 11, - 9, - 267, - 9, - 139, - 9, - 395, - 9, - 75, - 9, - 331, - 9, - 203, - 9, - 459, - 9, - 43, - 9, - 299, - 9, - 171, - 9, - 427, - 9, - 107, - 9, - 363, - 9, - 235, - 9, - 491, - 9, - 27, - 9, - 283, - 9, - 155, - 9, - 411, - 9, - 91, - 9, - 347, - 9, - 219, - 9, - 475, - 9, - 59, - 9, - 315, - 9, - 187, - 9, - 443, - 9, - 123, - 9, - 379, - 9, - 251, - 9, - 507, - 9, - 7, - 9, - 263, - 9, - 135, - 9, - 391, - 9, - 71, - 9, - 327, - 9, - 199, - 9, - 455, - 9, - 39, - 9, - 295, - 9, - 167, - 9, - 423, - 9, - 103, - 9, - 359, - 9, - 231, - 9, - 487, - 9, - 23, - 9, - 279, - 9, - 151, - 9, - 407, - 9, - 87, - 9, - 343, - 9, - 215, - 9, - 471, - 9, - 55, - 9, - 311, - 9, - 183, - 9, - 439, - 9, - 119, - 9, - 375, - 9, - 247, - 9, - 503, - 9, - 15, - 9, - 271, - 9, - 143, - 9, - 399, - 9, - 79, - 9, - 335, - 9, - 207, - 9, - 463, - 9, - 47, - 9, - 303, - 9, - 175, - 9, - 431, - 9, - 111, - 9, - 367, - 9, - 239, - 9, - 495, - 9, - 31, - 9, - 287, - 9, - 159, - 9, - 415, - 9, - 95, - 9, - 351, - 9, - 223, - 9, - 479, - 9, - 63, - 9, - 319, - 9, - 191, - 9, - 447, - 9, - 127, - 9, - 383, - 9, - 255, - 9, - 511, - 9, - 0, - 7, - 64, - 7, - 32, - 7, - 96, - 7, - 16, - 7, - 80, - 7, - 48, - 7, - 112, - 7, - 8, - 7, - 72, - 7, - 40, - 7, - 104, - 7, - 24, - 7, - 88, - 7, - 56, - 7, - 120, - 7, - 4, - 7, - 68, - 7, - 36, - 7, - 100, - 7, - 20, - 7, - 84, - 7, - 52, - 7, - 116, - 7, - 3, - 8, - 131, - 8, - 67, - 8, - 195, - 8, - 35, - 8, - 163, - 8, - 99, - 8, - 227, - 8 - }; - - internal static readonly short[] distTreeCodes = - { - 0, - 5, - 16, - 5, - 8, - 5, - 24, - 5, - 4, - 5, - 20, - 5, - 12, - 5, - 28, - 5, - 2, - 5, - 18, - 5, - 10, - 5, - 26, - 5, - 6, - 5, - 22, - 5, - 14, - 5, - 30, - 5, - 1, - 5, - 17, - 5, - 9, - 5, - 25, - 5, - 5, - 5, - 21, - 5, - 13, - 5, - 29, - 5, - 3, - 5, - 19, - 5, - 11, - 5, - 27, - 5, - 7, - 5, - 23, - 5 - }; - - // extra bits for each bit length code - internal static readonly int[] extra_blbits = - { - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 3, - 7 - }; - - internal static readonly StaticTree Literals; - internal static readonly StaticTree Distances; - internal static readonly StaticTree BitLengths; - - internal short[]? treeCodes; // static tree or null - internal int[]? extraBits; // extra bits for each code or null - internal int extraBase; // base index for extra_bits - internal int elems; // max number of elements in the tree - internal int maxLength; // max bit length for the codes - - private StaticTree( - short[]? treeCodes, - int[]? extraBits, - int extraBase, - int elems, - int maxLength - ) - { - this.treeCodes = treeCodes; - this.extraBits = extraBits; - this.extraBase = extraBase; - this.elems = elems; - this.maxLength = maxLength; + return 0; } - static StaticTree() + var charArray = new char[target.Length]; + var bytesRead = sourceTextReader.Read(charArray, start, count); + + // Returns -1 if EOF + if (bytesRead == 0) { - Literals = new StaticTree( - lengthAndLiteralsTreeCodes, - DeflateManager.ExtraLengthBits, - InternalConstants.LITERALS + 1, - InternalConstants.L_CODES, - InternalConstants.MAX_BITS - ); - Distances = new StaticTree( - distTreeCodes, - DeflateManager.ExtraDistanceBits, - 0, - InternalConstants.D_CODES, - InternalConstants.MAX_BITS - ); - BitLengths = new StaticTree( - null, - extra_blbits, - 0, - InternalConstants.BL_CODES, - InternalConstants.MAX_BL_BITS - ); + return -1; } + + for (var index = start; index < start + bytesRead; index++) + { + target[index] = (byte)charArray[index]; + } + + return bytesRead; + } +} + +internal static class InternalConstants +{ + internal static readonly int MAX_BITS = 15; + internal static readonly int BL_CODES = 19; + internal static readonly int D_CODES = 30; + internal static readonly int LITERALS = 256; + internal static readonly int LENGTH_CODES = 29; + internal static readonly int L_CODES = (LITERALS + 1 + LENGTH_CODES); + + // Bit length codes must not exceed MAX_BL_BITS bits + internal static readonly int MAX_BL_BITS = 7; + + // repeat previous bit length 3-6 times (2 bits of repeat count) + internal static readonly int REP_3_6 = 16; + + // repeat a zero length 3-10 times (3 bits of repeat count) + internal static readonly int REPZ_3_10 = 17; + + // repeat a zero length 11-138 times (7 bits of repeat count) + internal static readonly int REPZ_11_138 = 18; +} + +internal sealed class StaticTree +{ + internal static readonly short[] lengthAndLiteralsTreeCodes = + { + 12, + 8, + 140, + 8, + 76, + 8, + 204, + 8, + 44, + 8, + 172, + 8, + 108, + 8, + 236, + 8, + 28, + 8, + 156, + 8, + 92, + 8, + 220, + 8, + 60, + 8, + 188, + 8, + 124, + 8, + 252, + 8, + 2, + 8, + 130, + 8, + 66, + 8, + 194, + 8, + 34, + 8, + 162, + 8, + 98, + 8, + 226, + 8, + 18, + 8, + 146, + 8, + 82, + 8, + 210, + 8, + 50, + 8, + 178, + 8, + 114, + 8, + 242, + 8, + 10, + 8, + 138, + 8, + 74, + 8, + 202, + 8, + 42, + 8, + 170, + 8, + 106, + 8, + 234, + 8, + 26, + 8, + 154, + 8, + 90, + 8, + 218, + 8, + 58, + 8, + 186, + 8, + 122, + 8, + 250, + 8, + 6, + 8, + 134, + 8, + 70, + 8, + 198, + 8, + 38, + 8, + 166, + 8, + 102, + 8, + 230, + 8, + 22, + 8, + 150, + 8, + 86, + 8, + 214, + 8, + 54, + 8, + 182, + 8, + 118, + 8, + 246, + 8, + 14, + 8, + 142, + 8, + 78, + 8, + 206, + 8, + 46, + 8, + 174, + 8, + 110, + 8, + 238, + 8, + 30, + 8, + 158, + 8, + 94, + 8, + 222, + 8, + 62, + 8, + 190, + 8, + 126, + 8, + 254, + 8, + 1, + 8, + 129, + 8, + 65, + 8, + 193, + 8, + 33, + 8, + 161, + 8, + 97, + 8, + 225, + 8, + 17, + 8, + 145, + 8, + 81, + 8, + 209, + 8, + 49, + 8, + 177, + 8, + 113, + 8, + 241, + 8, + 9, + 8, + 137, + 8, + 73, + 8, + 201, + 8, + 41, + 8, + 169, + 8, + 105, + 8, + 233, + 8, + 25, + 8, + 153, + 8, + 89, + 8, + 217, + 8, + 57, + 8, + 185, + 8, + 121, + 8, + 249, + 8, + 5, + 8, + 133, + 8, + 69, + 8, + 197, + 8, + 37, + 8, + 165, + 8, + 101, + 8, + 229, + 8, + 21, + 8, + 149, + 8, + 85, + 8, + 213, + 8, + 53, + 8, + 181, + 8, + 117, + 8, + 245, + 8, + 13, + 8, + 141, + 8, + 77, + 8, + 205, + 8, + 45, + 8, + 173, + 8, + 109, + 8, + 237, + 8, + 29, + 8, + 157, + 8, + 93, + 8, + 221, + 8, + 61, + 8, + 189, + 8, + 125, + 8, + 253, + 8, + 19, + 9, + 275, + 9, + 147, + 9, + 403, + 9, + 83, + 9, + 339, + 9, + 211, + 9, + 467, + 9, + 51, + 9, + 307, + 9, + 179, + 9, + 435, + 9, + 115, + 9, + 371, + 9, + 243, + 9, + 499, + 9, + 11, + 9, + 267, + 9, + 139, + 9, + 395, + 9, + 75, + 9, + 331, + 9, + 203, + 9, + 459, + 9, + 43, + 9, + 299, + 9, + 171, + 9, + 427, + 9, + 107, + 9, + 363, + 9, + 235, + 9, + 491, + 9, + 27, + 9, + 283, + 9, + 155, + 9, + 411, + 9, + 91, + 9, + 347, + 9, + 219, + 9, + 475, + 9, + 59, + 9, + 315, + 9, + 187, + 9, + 443, + 9, + 123, + 9, + 379, + 9, + 251, + 9, + 507, + 9, + 7, + 9, + 263, + 9, + 135, + 9, + 391, + 9, + 71, + 9, + 327, + 9, + 199, + 9, + 455, + 9, + 39, + 9, + 295, + 9, + 167, + 9, + 423, + 9, + 103, + 9, + 359, + 9, + 231, + 9, + 487, + 9, + 23, + 9, + 279, + 9, + 151, + 9, + 407, + 9, + 87, + 9, + 343, + 9, + 215, + 9, + 471, + 9, + 55, + 9, + 311, + 9, + 183, + 9, + 439, + 9, + 119, + 9, + 375, + 9, + 247, + 9, + 503, + 9, + 15, + 9, + 271, + 9, + 143, + 9, + 399, + 9, + 79, + 9, + 335, + 9, + 207, + 9, + 463, + 9, + 47, + 9, + 303, + 9, + 175, + 9, + 431, + 9, + 111, + 9, + 367, + 9, + 239, + 9, + 495, + 9, + 31, + 9, + 287, + 9, + 159, + 9, + 415, + 9, + 95, + 9, + 351, + 9, + 223, + 9, + 479, + 9, + 63, + 9, + 319, + 9, + 191, + 9, + 447, + 9, + 127, + 9, + 383, + 9, + 255, + 9, + 511, + 9, + 0, + 7, + 64, + 7, + 32, + 7, + 96, + 7, + 16, + 7, + 80, + 7, + 48, + 7, + 112, + 7, + 8, + 7, + 72, + 7, + 40, + 7, + 104, + 7, + 24, + 7, + 88, + 7, + 56, + 7, + 120, + 7, + 4, + 7, + 68, + 7, + 36, + 7, + 100, + 7, + 20, + 7, + 84, + 7, + 52, + 7, + 116, + 7, + 3, + 8, + 131, + 8, + 67, + 8, + 195, + 8, + 35, + 8, + 163, + 8, + 99, + 8, + 227, + 8 + }; + + internal static readonly short[] distTreeCodes = + { + 0, + 5, + 16, + 5, + 8, + 5, + 24, + 5, + 4, + 5, + 20, + 5, + 12, + 5, + 28, + 5, + 2, + 5, + 18, + 5, + 10, + 5, + 26, + 5, + 6, + 5, + 22, + 5, + 14, + 5, + 30, + 5, + 1, + 5, + 17, + 5, + 9, + 5, + 25, + 5, + 5, + 5, + 21, + 5, + 13, + 5, + 29, + 5, + 3, + 5, + 19, + 5, + 11, + 5, + 27, + 5, + 7, + 5, + 23, + 5 + }; + + // extra bits for each bit length code + internal static readonly int[] extra_blbits = + { + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 3, + 7 + }; + + internal static readonly StaticTree Literals; + internal static readonly StaticTree Distances; + internal static readonly StaticTree BitLengths; + + internal short[]? treeCodes; // static tree or null + internal int[]? extraBits; // extra bits for each code or null + internal int extraBase; // base index for extra_bits + internal int elems; // max number of elements in the tree + internal int maxLength; // max bit length for the codes + + private StaticTree( + short[]? treeCodes, + int[]? extraBits, + int extraBase, + int elems, + int maxLength + ) + { + this.treeCodes = treeCodes; + this.extraBits = extraBits; + this.extraBase = extraBase; + this.elems = elems; + this.maxLength = maxLength; + } + + static StaticTree() + { + Literals = new StaticTree( + lengthAndLiteralsTreeCodes, + DeflateManager.ExtraLengthBits, + InternalConstants.LITERALS + 1, + InternalConstants.L_CODES, + InternalConstants.MAX_BITS + ); + Distances = new StaticTree( + distTreeCodes, + DeflateManager.ExtraDistanceBits, + 0, + InternalConstants.D_CODES, + InternalConstants.MAX_BITS + ); + BitLengths = new StaticTree( + null, + extra_blbits, + 0, + InternalConstants.BL_CODES, + InternalConstants.MAX_BL_BITS + ); } } diff --git a/src/SharpCompress/Compressors/Deflate/ZlibCodec.cs b/src/SharpCompress/Compressors/Deflate/ZlibCodec.cs index 4c8e0b78..c6b68dad 100644 --- a/src/SharpCompress/Compressors/Deflate/ZlibCodec.cs +++ b/src/SharpCompress/Compressors/Deflate/ZlibCodec.cs @@ -67,691 +67,690 @@ using System; -namespace SharpCompress.Compressors.Deflate +namespace SharpCompress.Compressors.Deflate; + +/// +/// Encoder and Decoder for ZLIB and DEFLATE (IETF RFC1950 and RFC1951). +/// +/// +/// +/// This class compresses and decompresses data according to the Deflate algorithm +/// and optionally, the ZLIB format, as documented in RFC 1950 - ZLIB and RFC 1951 - DEFLATE. +/// +internal sealed class ZlibCodec { /// - /// Encoder and Decoder for ZLIB and DEFLATE (IETF RFC1950 and RFC1951). + /// The buffer from which data is taken. + /// + public byte[] InputBuffer; + + /// + /// An index into the InputBuffer array, indicating where to start reading. + /// + public int NextIn; + + /// + /// The number of bytes available in the InputBuffer, starting at NextIn. + /// + /// + /// Generally you should set this to InputBuffer.Length before the first Inflate() or Deflate() call. + /// The class will update this number as calls to Inflate/Deflate are made. + /// + public int AvailableBytesIn; + + /// + /// Total number of bytes read so far, through all calls to Inflate()/Deflate(). + /// + public long TotalBytesIn; + + /// + /// Buffer to store output data. + /// + public byte[] OutputBuffer; + + /// + /// An index into the OutputBuffer array, indicating where to start writing. + /// + public int NextOut; + + /// + /// The number of bytes available in the OutputBuffer, starting at NextOut. + /// + /// + /// Generally you should set this to OutputBuffer.Length before the first Inflate() or Deflate() call. + /// The class will update this number as calls to Inflate/Deflate are made. + /// + public int AvailableBytesOut; + + /// + /// Total number of bytes written to the output so far, through all calls to Inflate()/Deflate(). + /// + public long TotalBytesOut; + + /// + /// used for diagnostics, when something goes wrong! + /// + public string Message; + + internal DeflateManager dstate; + internal InflateManager istate; + + internal uint _adler32; + + /// + /// The compression level to use in this codec. Useful only in compression mode. + /// + public CompressionLevel CompressLevel = CompressionLevel.Default; + + /// + /// The number of Window Bits to use. + /// + /// + /// This gauges the size of the sliding window, and hence the + /// compression effectiveness as well as memory consumption. It's best to just leave this + /// setting alone if you don't know what it is. The maximum value is 15 bits, which implies + /// a 32k window. + /// + public int WindowBits = ZlibConstants.WindowBitsDefault; + + /// + /// The compression strategy to use. + /// + /// + /// This is only effective in compression. The theory offered by ZLIB is that different + /// strategies could potentially produce significant differences in compression behavior + /// for different data sets. Unfortunately I don't have any good recommendations for how + /// to set it differently. When I tested changing the strategy I got minimally different + /// compression performance. It's best to leave this property alone if you don't have a + /// good feel for it. Or, you may want to produce a test harness that runs through the + /// different strategy options and evaluates them on different file types. If you do that, + /// let me know your results. + /// + public CompressionStrategy Strategy = CompressionStrategy.Default; + + /// + /// The Adler32 checksum on the data transferred through the codec so far. You probably don't need to look at this. + /// + public int Adler32 => (int)_adler32; + + /// + /// Create a ZlibCodec. + /// + /// + /// If you use this default constructor, you will later have to explicitly call + /// InitializeInflate() or InitializeDeflate() before using the ZlibCodec to compress + /// or decompress. + /// + public ZlibCodec() { } + + /// + /// Create a ZlibCodec that either compresses or decompresses. + /// + /// + /// Indicates whether the codec should compress (deflate) or decompress (inflate). + /// + public ZlibCodec(CompressionMode mode) + { + if (mode == CompressionMode.Compress) + { + var rc = InitializeDeflate(); + if (rc != ZlibConstants.Z_OK) + { + throw new ZlibException("Cannot initialize for deflate."); + } + } + else if (mode == CompressionMode.Decompress) + { + var rc = InitializeInflate(); + if (rc != ZlibConstants.Z_OK) + { + throw new ZlibException("Cannot initialize for inflate."); + } + } + else + { + throw new ZlibException("Invalid ZlibStreamFlavor."); + } + } + + /// + /// Initialize the inflation state. + /// + /// + /// It is not necessary to call this before using the ZlibCodec to inflate data; + /// It is implicitly called when you call the constructor. + /// + /// Z_OK if everything goes well. + public int InitializeInflate() + { + return InitializeInflate(WindowBits); + } + + /// + /// Initialize the inflation state with an explicit flag to + /// govern the handling of RFC1950 header bytes. /// /// /// - /// This class compresses and decompresses data according to the Deflate algorithm - /// and optionally, the ZLIB format, as documented in RFC 1950 - ZLIB and RFC 1951 - DEFLATE. + /// By default, the ZLIB header defined in RFC 1950 is expected. If + /// you want to read a zlib stream you should specify true for + /// expectRfc1950Header. If you have a deflate stream, you will want to specify + /// false. It is only necessary to invoke this initializer explicitly if you + /// want to specify false. /// - internal sealed class ZlibCodec + /// + /// whether to expect an RFC1950 header byte + /// pair when reading the stream of data to be inflated. + /// + /// Z_OK if everything goes well. + public int InitializeInflate(bool expectRfc1950Header) { - /// - /// The buffer from which data is taken. - /// - public byte[] InputBuffer; + return InitializeInflate(WindowBits, expectRfc1950Header); + } - /// - /// An index into the InputBuffer array, indicating where to start reading. - /// - public int NextIn; + /// + /// Initialize the ZlibCodec for inflation, with the specified number of window bits. + /// + /// The number of window bits to use. If you need to ask what that is, + /// then you shouldn't be calling this initializer. + /// Z_OK if all goes well. + public int InitializeInflate(int windowBits) + { + WindowBits = windowBits; + return InitializeInflate(windowBits, true); + } - /// - /// The number of bytes available in the InputBuffer, starting at NextIn. - /// - /// - /// Generally you should set this to InputBuffer.Length before the first Inflate() or Deflate() call. - /// The class will update this number as calls to Inflate/Deflate are made. - /// - public int AvailableBytesIn; - - /// - /// Total number of bytes read so far, through all calls to Inflate()/Deflate(). - /// - public long TotalBytesIn; - - /// - /// Buffer to store output data. - /// - public byte[] OutputBuffer; - - /// - /// An index into the OutputBuffer array, indicating where to start writing. - /// - public int NextOut; - - /// - /// The number of bytes available in the OutputBuffer, starting at NextOut. - /// - /// - /// Generally you should set this to OutputBuffer.Length before the first Inflate() or Deflate() call. - /// The class will update this number as calls to Inflate/Deflate are made. - /// - public int AvailableBytesOut; - - /// - /// Total number of bytes written to the output so far, through all calls to Inflate()/Deflate(). - /// - public long TotalBytesOut; - - /// - /// used for diagnostics, when something goes wrong! - /// - public string Message; - - internal DeflateManager dstate; - internal InflateManager istate; - - internal uint _adler32; - - /// - /// The compression level to use in this codec. Useful only in compression mode. - /// - public CompressionLevel CompressLevel = CompressionLevel.Default; - - /// - /// The number of Window Bits to use. - /// - /// - /// This gauges the size of the sliding window, and hence the - /// compression effectiveness as well as memory consumption. It's best to just leave this - /// setting alone if you don't know what it is. The maximum value is 15 bits, which implies - /// a 32k window. - /// - public int WindowBits = ZlibConstants.WindowBitsDefault; - - /// - /// The compression strategy to use. - /// - /// - /// This is only effective in compression. The theory offered by ZLIB is that different - /// strategies could potentially produce significant differences in compression behavior - /// for different data sets. Unfortunately I don't have any good recommendations for how - /// to set it differently. When I tested changing the strategy I got minimally different - /// compression performance. It's best to leave this property alone if you don't have a - /// good feel for it. Or, you may want to produce a test harness that runs through the - /// different strategy options and evaluates them on different file types. If you do that, - /// let me know your results. - /// - public CompressionStrategy Strategy = CompressionStrategy.Default; - - /// - /// The Adler32 checksum on the data transferred through the codec so far. You probably don't need to look at this. - /// - public int Adler32 => (int)_adler32; - - /// - /// Create a ZlibCodec. - /// - /// - /// If you use this default constructor, you will later have to explicitly call - /// InitializeInflate() or InitializeDeflate() before using the ZlibCodec to compress - /// or decompress. - /// - public ZlibCodec() { } - - /// - /// Create a ZlibCodec that either compresses or decompresses. - /// - /// - /// Indicates whether the codec should compress (deflate) or decompress (inflate). - /// - public ZlibCodec(CompressionMode mode) + /// + /// Initialize the inflation state with an explicit flag to govern the handling of + /// RFC1950 header bytes. + /// + /// + /// + /// If you want to read a zlib stream you should specify true for + /// expectRfc1950Header. In this case, the library will expect to find a ZLIB + /// header, as defined in RFC + /// 1950, in the compressed stream. If you will be reading a DEFLATE or + /// GZIP stream, which does not have such a header, you will want to specify + /// false. + /// + /// + /// whether to expect an RFC1950 header byte pair when reading + /// the stream of data to be inflated. + /// The number of window bits to use. If you need to ask what that is, + /// then you shouldn't be calling this initializer. + /// Z_OK if everything goes well. + public int InitializeInflate(int windowBits, bool expectRfc1950Header) + { + WindowBits = windowBits; + if (dstate != null) { - if (mode == CompressionMode.Compress) - { - int rc = InitializeDeflate(); - if (rc != ZlibConstants.Z_OK) - { - throw new ZlibException("Cannot initialize for deflate."); - } - } - else if (mode == CompressionMode.Decompress) - { - int rc = InitializeInflate(); - if (rc != ZlibConstants.Z_OK) - { - throw new ZlibException("Cannot initialize for inflate."); - } - } - else - { - throw new ZlibException("Invalid ZlibStreamFlavor."); - } + throw new ZlibException( + "You may not call InitializeInflate() after calling InitializeDeflate()." + ); + } + istate = new InflateManager(expectRfc1950Header); + return istate.Initialize(this, windowBits); + } + + /// + /// Inflate the data in the InputBuffer, placing the result in the OutputBuffer. + /// + /// + /// You must have set InputBuffer and OutputBuffer, NextIn and NextOut, and AvailableBytesIn and + /// AvailableBytesOut before calling this method. + /// + /// + /// + /// private void InflateBuffer() + /// { + /// int bufferSize = 1024; + /// byte[] buffer = new byte[bufferSize]; + /// ZlibCodec decompressor = new ZlibCodec(); + /// + /// Console.WriteLine("\n============================================"); + /// Console.WriteLine("Size of Buffer to Inflate: {0} bytes.", CompressedBytes.Length); + /// MemoryStream ms = new MemoryStream(DecompressedBytes); + /// + /// int rc = decompressor.InitializeInflate(); + /// + /// decompressor.InputBuffer = CompressedBytes; + /// decompressor.NextIn = 0; + /// decompressor.AvailableBytesIn = CompressedBytes.Length; + /// + /// decompressor.OutputBuffer = buffer; + /// + /// // pass 1: inflate + /// do + /// { + /// decompressor.NextOut = 0; + /// decompressor.AvailableBytesOut = buffer.Length; + /// rc = decompressor.Inflate(FlushType.None); + /// + /// if (rc != ZlibConstants.Z_OK && rc != ZlibConstants.Z_STREAM_END) + /// throw new Exception("inflating: " + decompressor.Message); + /// + /// ms.Write(decompressor.OutputBuffer, 0, buffer.Length - decompressor.AvailableBytesOut); + /// } + /// while (decompressor.AvailableBytesIn > 0 || decompressor.AvailableBytesOut == 0); + /// + /// // pass 2: finish and flush + /// do + /// { + /// decompressor.NextOut = 0; + /// decompressor.AvailableBytesOut = buffer.Length; + /// rc = decompressor.Inflate(FlushType.Finish); + /// + /// if (rc != ZlibConstants.Z_STREAM_END && rc != ZlibConstants.Z_OK) + /// throw new Exception("inflating: " + decompressor.Message); + /// + /// if (buffer.Length - decompressor.AvailableBytesOut > 0) + /// ms.Write(buffer, 0, buffer.Length - decompressor.AvailableBytesOut); + /// } + /// while (decompressor.AvailableBytesIn > 0 || decompressor.AvailableBytesOut == 0); + /// + /// decompressor.EndInflate(); + /// } + /// + /// + /// + /// The flush to use when inflating. + /// Z_OK if everything goes well. + public int Inflate(FlushType flush) + { + if (istate is null) + { + throw new ZlibException("No Inflate State!"); + } + return istate.Inflate(flush); + } + + /// + /// Ends an inflation session. + /// + /// + /// Call this after successively calling Inflate(). This will cause all buffers to be flushed. + /// After calling this you cannot call Inflate() without a intervening call to one of the + /// InitializeInflate() overloads. + /// + /// Z_OK if everything goes well. + public int EndInflate() + { + if (istate is null) + { + throw new ZlibException("No Inflate State!"); + } + var ret = istate.End(); + istate = null; + return ret; + } + + /// + /// I don't know what this does! + /// + /// Z_OK if everything goes well. + public int SyncInflate() + { + if (istate is null) + { + throw new ZlibException("No Inflate State!"); + } + return istate.Sync(); + } + + /// + /// Initialize the ZlibCodec for deflation operation. + /// + /// + /// The codec will use the MAX window bits and the default level of compression. + /// + /// + /// + /// int bufferSize = 40000; + /// byte[] CompressedBytes = new byte[bufferSize]; + /// byte[] DecompressedBytes = new byte[bufferSize]; + /// + /// ZlibCodec compressor = new ZlibCodec(); + /// + /// compressor.InitializeDeflate(CompressionLevel.Default); + /// + /// compressor.InputBuffer = System.Text.ASCIIEncoding.ASCII.GetBytes(TextToCompress); + /// compressor.NextIn = 0; + /// compressor.AvailableBytesIn = compressor.InputBuffer.Length; + /// + /// compressor.OutputBuffer = CompressedBytes; + /// compressor.NextOut = 0; + /// compressor.AvailableBytesOut = CompressedBytes.Length; + /// + /// while (compressor.TotalBytesIn != TextToCompress.Length && compressor.TotalBytesOut < bufferSize) + /// { + /// compressor.Deflate(FlushType.None); + /// } + /// + /// while (true) + /// { + /// int rc= compressor.Deflate(FlushType.Finish); + /// if (rc == ZlibConstants.Z_STREAM_END) break; + /// } + /// + /// compressor.EndDeflate(); + /// + /// + /// + /// Z_OK if all goes well. You generally don't need to check the return code. + public int InitializeDeflate() + { + return _InternalInitializeDeflate(true); + } + + /// + /// Initialize the ZlibCodec for deflation operation, using the specified CompressionLevel. + /// + /// + /// The codec will use the maximum window bits (15) and the specified + /// CompressionLevel. It will emit a ZLIB stream as it compresses. + /// + /// The compression level for the codec. + /// Z_OK if all goes well. + public int InitializeDeflate(CompressionLevel level) + { + CompressLevel = level; + return _InternalInitializeDeflate(true); + } + + /// + /// Initialize the ZlibCodec for deflation operation, using the specified CompressionLevel, + /// and the explicit flag governing whether to emit an RFC1950 header byte pair. + /// + /// + /// The codec will use the maximum window bits (15) and the specified CompressionLevel. + /// If you want to generate a zlib stream, you should specify true for + /// wantRfc1950Header. In this case, the library will emit a ZLIB + /// header, as defined in RFC + /// 1950, in the compressed stream. + /// + /// The compression level for the codec. + /// whether to emit an initial RFC1950 byte pair in the compressed stream. + /// Z_OK if all goes well. + public int InitializeDeflate(CompressionLevel level, bool wantRfc1950Header) + { + CompressLevel = level; + return _InternalInitializeDeflate(wantRfc1950Header); + } + + /// + /// Initialize the ZlibCodec for deflation operation, using the specified CompressionLevel, + /// and the specified number of window bits. + /// + /// + /// The codec will use the specified number of window bits and the specified CompressionLevel. + /// + /// The compression level for the codec. + /// the number of window bits to use. If you don't know what this means, don't use this method. + /// Z_OK if all goes well. + public int InitializeDeflate(CompressionLevel level, int bits) + { + CompressLevel = level; + WindowBits = bits; + return _InternalInitializeDeflate(true); + } + + /// + /// Initialize the ZlibCodec for deflation operation, using the specified + /// CompressionLevel, the specified number of window bits, and the explicit flag + /// governing whether to emit an RFC1950 header byte pair. + /// + /// + /// The compression level for the codec. + /// whether to emit an initial RFC1950 byte pair in the compressed stream. + /// the number of window bits to use. If you don't know what this means, don't use this method. + /// Z_OK if all goes well. + public int InitializeDeflate(CompressionLevel level, int bits, bool wantRfc1950Header) + { + CompressLevel = level; + WindowBits = bits; + return _InternalInitializeDeflate(wantRfc1950Header); + } + + private int _InternalInitializeDeflate(bool wantRfc1950Header) + { + if (istate != null) + { + throw new ZlibException( + "You may not call InitializeDeflate() after calling InitializeInflate()." + ); + } + dstate = new DeflateManager(); + dstate.WantRfc1950HeaderBytes = wantRfc1950Header; + + return dstate.Initialize(this, CompressLevel, WindowBits, Strategy); + } + + /// + /// Deflate one batch of data. + /// + /// + /// You must have set InputBuffer and OutputBuffer before calling this method. + /// + /// + /// + /// private void DeflateBuffer(CompressionLevel level) + /// { + /// int bufferSize = 1024; + /// byte[] buffer = new byte[bufferSize]; + /// ZlibCodec compressor = new ZlibCodec(); + /// + /// Console.WriteLine("\n============================================"); + /// Console.WriteLine("Size of Buffer to Deflate: {0} bytes.", UncompressedBytes.Length); + /// MemoryStream ms = new MemoryStream(); + /// + /// int rc = compressor.InitializeDeflate(level); + /// + /// compressor.InputBuffer = UncompressedBytes; + /// compressor.NextIn = 0; + /// compressor.AvailableBytesIn = UncompressedBytes.Length; + /// + /// compressor.OutputBuffer = buffer; + /// + /// // pass 1: deflate + /// do + /// { + /// compressor.NextOut = 0; + /// compressor.AvailableBytesOut = buffer.Length; + /// rc = compressor.Deflate(FlushType.None); + /// + /// if (rc != ZlibConstants.Z_OK && rc != ZlibConstants.Z_STREAM_END) + /// throw new Exception("deflating: " + compressor.Message); + /// + /// ms.Write(compressor.OutputBuffer, 0, buffer.Length - compressor.AvailableBytesOut); + /// } + /// while (compressor.AvailableBytesIn > 0 || compressor.AvailableBytesOut == 0); + /// + /// // pass 2: finish and flush + /// do + /// { + /// compressor.NextOut = 0; + /// compressor.AvailableBytesOut = buffer.Length; + /// rc = compressor.Deflate(FlushType.Finish); + /// + /// if (rc != ZlibConstants.Z_STREAM_END && rc != ZlibConstants.Z_OK) + /// throw new Exception("deflating: " + compressor.Message); + /// + /// if (buffer.Length - compressor.AvailableBytesOut > 0) + /// ms.Write(buffer, 0, buffer.Length - compressor.AvailableBytesOut); + /// } + /// while (compressor.AvailableBytesIn > 0 || compressor.AvailableBytesOut == 0); + /// + /// compressor.EndDeflate(); + /// + /// ms.Seek(0, SeekOrigin.Begin); + /// CompressedBytes = new byte[compressor.TotalBytesOut]; + /// ms.Read(CompressedBytes, 0, CompressedBytes.Length); + /// } + /// + /// + /// whether to flush all data as you deflate. Generally you will want to + /// use Z_NO_FLUSH here, in a series of calls to Deflate(), and then call EndDeflate() to + /// flush everything. + /// + /// Z_OK if all goes well. + public int Deflate(FlushType flush) + { + if (dstate is null) + { + throw new ZlibException("No Deflate State!"); + } + return dstate.Deflate(flush); + } + + /// + /// End a deflation session. + /// + /// + /// Call this after making a series of one or more calls to Deflate(). All buffers are flushed. + /// + /// Z_OK if all goes well. + public int EndDeflate() + { + if (dstate is null) + { + throw new ZlibException("No Deflate State!"); } - /// - /// Initialize the inflation state. - /// - /// - /// It is not necessary to call this before using the ZlibCodec to inflate data; - /// It is implicitly called when you call the constructor. - /// - /// Z_OK if everything goes well. - public int InitializeInflate() + // TODO: dinoch Tue, 03 Nov 2009 15:39 (test this) + //int ret = dstate.End(); + dstate = null; + return ZlibConstants.Z_OK; //ret; + } + + /// + /// Reset a codec for another deflation session. + /// + /// + /// Call this to reset the deflation state. For example if a thread is deflating + /// non-consecutive blocks, you can call Reset() after the Deflate(Sync) of the first + /// block and before the next Deflate(None) of the second block. + /// + /// Z_OK if all goes well. + public void ResetDeflate() + { + if (dstate is null) { - return InitializeInflate(WindowBits); + throw new ZlibException("No Deflate State!"); + } + dstate.Reset(); + } + + /// + /// Set the CompressionStrategy and CompressionLevel for a deflation session. + /// + /// the level of compression to use. + /// the strategy to use for compression. + /// Z_OK if all goes well. + public int SetDeflateParams(CompressionLevel level, CompressionStrategy strategy) + { + if (dstate is null) + { + throw new ZlibException("No Deflate State!"); + } + return dstate.SetParams(level, strategy); + } + + /// + /// Set the dictionary to be used for either Inflation or Deflation. + /// + /// The dictionary bytes to use. + /// Z_OK if all goes well. + public int SetDictionary(byte[] dictionary) + { + if (istate != null) + { + return istate.SetDictionary(dictionary); } - /// - /// Initialize the inflation state with an explicit flag to - /// govern the handling of RFC1950 header bytes. - /// - /// - /// - /// By default, the ZLIB header defined in RFC 1950 is expected. If - /// you want to read a zlib stream you should specify true for - /// expectRfc1950Header. If you have a deflate stream, you will want to specify - /// false. It is only necessary to invoke this initializer explicitly if you - /// want to specify false. - /// - /// - /// whether to expect an RFC1950 header byte - /// pair when reading the stream of data to be inflated. - /// - /// Z_OK if everything goes well. - public int InitializeInflate(bool expectRfc1950Header) + if (dstate != null) { - return InitializeInflate(WindowBits, expectRfc1950Header); + return dstate.SetDictionary(dictionary); } - /// - /// Initialize the ZlibCodec for inflation, with the specified number of window bits. - /// - /// The number of window bits to use. If you need to ask what that is, - /// then you shouldn't be calling this initializer. - /// Z_OK if all goes well. - public int InitializeInflate(int windowBits) + throw new ZlibException("No Inflate or Deflate state!"); + } + + // Flush as much pending output as possible. All deflate() output goes + // through this function so some applications may wish to modify it + // to avoid allocating a large strm->next_out buffer and copying into it. + // (See also read_buf()). + internal void flush_pending() + { + var len = dstate.pendingCount; + + if (len > AvailableBytesOut) { - WindowBits = windowBits; - return InitializeInflate(windowBits, true); + len = AvailableBytesOut; + } + if (len == 0) + { + return; } - /// - /// Initialize the inflation state with an explicit flag to govern the handling of - /// RFC1950 header bytes. - /// - /// - /// - /// If you want to read a zlib stream you should specify true for - /// expectRfc1950Header. In this case, the library will expect to find a ZLIB - /// header, as defined in RFC - /// 1950, in the compressed stream. If you will be reading a DEFLATE or - /// GZIP stream, which does not have such a header, you will want to specify - /// false. - /// - /// - /// whether to expect an RFC1950 header byte pair when reading - /// the stream of data to be inflated. - /// The number of window bits to use. If you need to ask what that is, - /// then you shouldn't be calling this initializer. - /// Z_OK if everything goes well. - public int InitializeInflate(int windowBits, bool expectRfc1950Header) + if ( + dstate.pending.Length <= dstate.nextPending + || OutputBuffer.Length <= NextOut + || dstate.pending.Length < (dstate.nextPending + len) + || OutputBuffer.Length < (NextOut + len) + ) { - WindowBits = windowBits; - if (dstate != null) - { - throw new ZlibException( - "You may not call InitializeInflate() after calling InitializeDeflate()." - ); - } - istate = new InflateManager(expectRfc1950Header); - return istate.Initialize(this, windowBits); + throw new ZlibException( + string.Format( + "Invalid State. (pending.Length={0}, pendingCount={1})", + dstate.pending.Length, + dstate.pendingCount + ) + ); } - /// - /// Inflate the data in the InputBuffer, placing the result in the OutputBuffer. - /// - /// - /// You must have set InputBuffer and OutputBuffer, NextIn and NextOut, and AvailableBytesIn and - /// AvailableBytesOut before calling this method. - /// - /// - /// - /// private void InflateBuffer() - /// { - /// int bufferSize = 1024; - /// byte[] buffer = new byte[bufferSize]; - /// ZlibCodec decompressor = new ZlibCodec(); - /// - /// Console.WriteLine("\n============================================"); - /// Console.WriteLine("Size of Buffer to Inflate: {0} bytes.", CompressedBytes.Length); - /// MemoryStream ms = new MemoryStream(DecompressedBytes); - /// - /// int rc = decompressor.InitializeInflate(); - /// - /// decompressor.InputBuffer = CompressedBytes; - /// decompressor.NextIn = 0; - /// decompressor.AvailableBytesIn = CompressedBytes.Length; - /// - /// decompressor.OutputBuffer = buffer; - /// - /// // pass 1: inflate - /// do - /// { - /// decompressor.NextOut = 0; - /// decompressor.AvailableBytesOut = buffer.Length; - /// rc = decompressor.Inflate(FlushType.None); - /// - /// if (rc != ZlibConstants.Z_OK && rc != ZlibConstants.Z_STREAM_END) - /// throw new Exception("inflating: " + decompressor.Message); - /// - /// ms.Write(decompressor.OutputBuffer, 0, buffer.Length - decompressor.AvailableBytesOut); - /// } - /// while (decompressor.AvailableBytesIn > 0 || decompressor.AvailableBytesOut == 0); - /// - /// // pass 2: finish and flush - /// do - /// { - /// decompressor.NextOut = 0; - /// decompressor.AvailableBytesOut = buffer.Length; - /// rc = decompressor.Inflate(FlushType.Finish); - /// - /// if (rc != ZlibConstants.Z_STREAM_END && rc != ZlibConstants.Z_OK) - /// throw new Exception("inflating: " + decompressor.Message); - /// - /// if (buffer.Length - decompressor.AvailableBytesOut > 0) - /// ms.Write(buffer, 0, buffer.Length - decompressor.AvailableBytesOut); - /// } - /// while (decompressor.AvailableBytesIn > 0 || decompressor.AvailableBytesOut == 0); - /// - /// decompressor.EndInflate(); - /// } - /// - /// - /// - /// The flush to use when inflating. - /// Z_OK if everything goes well. - public int Inflate(FlushType flush) + Array.Copy(dstate.pending, dstate.nextPending, OutputBuffer, NextOut, len); + + NextOut += len; + dstate.nextPending += len; + TotalBytesOut += len; + AvailableBytesOut -= len; + dstate.pendingCount -= len; + if (dstate.pendingCount == 0) { - if (istate is null) - { - throw new ZlibException("No Inflate State!"); - } - return istate.Inflate(flush); - } - - /// - /// Ends an inflation session. - /// - /// - /// Call this after successively calling Inflate(). This will cause all buffers to be flushed. - /// After calling this you cannot call Inflate() without a intervening call to one of the - /// InitializeInflate() overloads. - /// - /// Z_OK if everything goes well. - public int EndInflate() - { - if (istate is null) - { - throw new ZlibException("No Inflate State!"); - } - int ret = istate.End(); - istate = null; - return ret; - } - - /// - /// I don't know what this does! - /// - /// Z_OK if everything goes well. - public int SyncInflate() - { - if (istate is null) - { - throw new ZlibException("No Inflate State!"); - } - return istate.Sync(); - } - - /// - /// Initialize the ZlibCodec for deflation operation. - /// - /// - /// The codec will use the MAX window bits and the default level of compression. - /// - /// - /// - /// int bufferSize = 40000; - /// byte[] CompressedBytes = new byte[bufferSize]; - /// byte[] DecompressedBytes = new byte[bufferSize]; - /// - /// ZlibCodec compressor = new ZlibCodec(); - /// - /// compressor.InitializeDeflate(CompressionLevel.Default); - /// - /// compressor.InputBuffer = System.Text.ASCIIEncoding.ASCII.GetBytes(TextToCompress); - /// compressor.NextIn = 0; - /// compressor.AvailableBytesIn = compressor.InputBuffer.Length; - /// - /// compressor.OutputBuffer = CompressedBytes; - /// compressor.NextOut = 0; - /// compressor.AvailableBytesOut = CompressedBytes.Length; - /// - /// while (compressor.TotalBytesIn != TextToCompress.Length && compressor.TotalBytesOut < bufferSize) - /// { - /// compressor.Deflate(FlushType.None); - /// } - /// - /// while (true) - /// { - /// int rc= compressor.Deflate(FlushType.Finish); - /// if (rc == ZlibConstants.Z_STREAM_END) break; - /// } - /// - /// compressor.EndDeflate(); - /// - /// - /// - /// Z_OK if all goes well. You generally don't need to check the return code. - public int InitializeDeflate() - { - return _InternalInitializeDeflate(true); - } - - /// - /// Initialize the ZlibCodec for deflation operation, using the specified CompressionLevel. - /// - /// - /// The codec will use the maximum window bits (15) and the specified - /// CompressionLevel. It will emit a ZLIB stream as it compresses. - /// - /// The compression level for the codec. - /// Z_OK if all goes well. - public int InitializeDeflate(CompressionLevel level) - { - CompressLevel = level; - return _InternalInitializeDeflate(true); - } - - /// - /// Initialize the ZlibCodec for deflation operation, using the specified CompressionLevel, - /// and the explicit flag governing whether to emit an RFC1950 header byte pair. - /// - /// - /// The codec will use the maximum window bits (15) and the specified CompressionLevel. - /// If you want to generate a zlib stream, you should specify true for - /// wantRfc1950Header. In this case, the library will emit a ZLIB - /// header, as defined in RFC - /// 1950, in the compressed stream. - /// - /// The compression level for the codec. - /// whether to emit an initial RFC1950 byte pair in the compressed stream. - /// Z_OK if all goes well. - public int InitializeDeflate(CompressionLevel level, bool wantRfc1950Header) - { - CompressLevel = level; - return _InternalInitializeDeflate(wantRfc1950Header); - } - - /// - /// Initialize the ZlibCodec for deflation operation, using the specified CompressionLevel, - /// and the specified number of window bits. - /// - /// - /// The codec will use the specified number of window bits and the specified CompressionLevel. - /// - /// The compression level for the codec. - /// the number of window bits to use. If you don't know what this means, don't use this method. - /// Z_OK if all goes well. - public int InitializeDeflate(CompressionLevel level, int bits) - { - CompressLevel = level; - WindowBits = bits; - return _InternalInitializeDeflate(true); - } - - /// - /// Initialize the ZlibCodec for deflation operation, using the specified - /// CompressionLevel, the specified number of window bits, and the explicit flag - /// governing whether to emit an RFC1950 header byte pair. - /// - /// - /// The compression level for the codec. - /// whether to emit an initial RFC1950 byte pair in the compressed stream. - /// the number of window bits to use. If you don't know what this means, don't use this method. - /// Z_OK if all goes well. - public int InitializeDeflate(CompressionLevel level, int bits, bool wantRfc1950Header) - { - CompressLevel = level; - WindowBits = bits; - return _InternalInitializeDeflate(wantRfc1950Header); - } - - private int _InternalInitializeDeflate(bool wantRfc1950Header) - { - if (istate != null) - { - throw new ZlibException( - "You may not call InitializeDeflate() after calling InitializeInflate()." - ); - } - dstate = new DeflateManager(); - dstate.WantRfc1950HeaderBytes = wantRfc1950Header; - - return dstate.Initialize(this, CompressLevel, WindowBits, Strategy); - } - - /// - /// Deflate one batch of data. - /// - /// - /// You must have set InputBuffer and OutputBuffer before calling this method. - /// - /// - /// - /// private void DeflateBuffer(CompressionLevel level) - /// { - /// int bufferSize = 1024; - /// byte[] buffer = new byte[bufferSize]; - /// ZlibCodec compressor = new ZlibCodec(); - /// - /// Console.WriteLine("\n============================================"); - /// Console.WriteLine("Size of Buffer to Deflate: {0} bytes.", UncompressedBytes.Length); - /// MemoryStream ms = new MemoryStream(); - /// - /// int rc = compressor.InitializeDeflate(level); - /// - /// compressor.InputBuffer = UncompressedBytes; - /// compressor.NextIn = 0; - /// compressor.AvailableBytesIn = UncompressedBytes.Length; - /// - /// compressor.OutputBuffer = buffer; - /// - /// // pass 1: deflate - /// do - /// { - /// compressor.NextOut = 0; - /// compressor.AvailableBytesOut = buffer.Length; - /// rc = compressor.Deflate(FlushType.None); - /// - /// if (rc != ZlibConstants.Z_OK && rc != ZlibConstants.Z_STREAM_END) - /// throw new Exception("deflating: " + compressor.Message); - /// - /// ms.Write(compressor.OutputBuffer, 0, buffer.Length - compressor.AvailableBytesOut); - /// } - /// while (compressor.AvailableBytesIn > 0 || compressor.AvailableBytesOut == 0); - /// - /// // pass 2: finish and flush - /// do - /// { - /// compressor.NextOut = 0; - /// compressor.AvailableBytesOut = buffer.Length; - /// rc = compressor.Deflate(FlushType.Finish); - /// - /// if (rc != ZlibConstants.Z_STREAM_END && rc != ZlibConstants.Z_OK) - /// throw new Exception("deflating: " + compressor.Message); - /// - /// if (buffer.Length - compressor.AvailableBytesOut > 0) - /// ms.Write(buffer, 0, buffer.Length - compressor.AvailableBytesOut); - /// } - /// while (compressor.AvailableBytesIn > 0 || compressor.AvailableBytesOut == 0); - /// - /// compressor.EndDeflate(); - /// - /// ms.Seek(0, SeekOrigin.Begin); - /// CompressedBytes = new byte[compressor.TotalBytesOut]; - /// ms.Read(CompressedBytes, 0, CompressedBytes.Length); - /// } - /// - /// - /// whether to flush all data as you deflate. Generally you will want to - /// use Z_NO_FLUSH here, in a series of calls to Deflate(), and then call EndDeflate() to - /// flush everything. - /// - /// Z_OK if all goes well. - public int Deflate(FlushType flush) - { - if (dstate is null) - { - throw new ZlibException("No Deflate State!"); - } - return dstate.Deflate(flush); - } - - /// - /// End a deflation session. - /// - /// - /// Call this after making a series of one or more calls to Deflate(). All buffers are flushed. - /// - /// Z_OK if all goes well. - public int EndDeflate() - { - if (dstate is null) - { - throw new ZlibException("No Deflate State!"); - } - - // TODO: dinoch Tue, 03 Nov 2009 15:39 (test this) - //int ret = dstate.End(); - dstate = null; - return ZlibConstants.Z_OK; //ret; - } - - /// - /// Reset a codec for another deflation session. - /// - /// - /// Call this to reset the deflation state. For example if a thread is deflating - /// non-consecutive blocks, you can call Reset() after the Deflate(Sync) of the first - /// block and before the next Deflate(None) of the second block. - /// - /// Z_OK if all goes well. - public void ResetDeflate() - { - if (dstate is null) - { - throw new ZlibException("No Deflate State!"); - } - dstate.Reset(); - } - - /// - /// Set the CompressionStrategy and CompressionLevel for a deflation session. - /// - /// the level of compression to use. - /// the strategy to use for compression. - /// Z_OK if all goes well. - public int SetDeflateParams(CompressionLevel level, CompressionStrategy strategy) - { - if (dstate is null) - { - throw new ZlibException("No Deflate State!"); - } - return dstate.SetParams(level, strategy); - } - - /// - /// Set the dictionary to be used for either Inflation or Deflation. - /// - /// The dictionary bytes to use. - /// Z_OK if all goes well. - public int SetDictionary(byte[] dictionary) - { - if (istate != null) - { - return istate.SetDictionary(dictionary); - } - - if (dstate != null) - { - return dstate.SetDictionary(dictionary); - } - - throw new ZlibException("No Inflate or Deflate state!"); - } - - // Flush as much pending output as possible. All deflate() output goes - // through this function so some applications may wish to modify it - // to avoid allocating a large strm->next_out buffer and copying into it. - // (See also read_buf()). - internal void flush_pending() - { - int len = dstate.pendingCount; - - if (len > AvailableBytesOut) - { - len = AvailableBytesOut; - } - if (len == 0) - { - return; - } - - if ( - dstate.pending.Length <= dstate.nextPending - || OutputBuffer.Length <= NextOut - || dstate.pending.Length < (dstate.nextPending + len) - || OutputBuffer.Length < (NextOut + len) - ) - { - throw new ZlibException( - String.Format( - "Invalid State. (pending.Length={0}, pendingCount={1})", - dstate.pending.Length, - dstate.pendingCount - ) - ); - } - - Array.Copy(dstate.pending, dstate.nextPending, OutputBuffer, NextOut, len); - - NextOut += len; - dstate.nextPending += len; - TotalBytesOut += len; - AvailableBytesOut -= len; - dstate.pendingCount -= len; - if (dstate.pendingCount == 0) - { - dstate.nextPending = 0; - } - } - - // Read a new buffer from the current input stream, update the adler32 - // and total number of bytes read. All deflate() input goes through - // this function so some applications may wish to modify it to avoid - // allocating a large strm->next_in buffer and copying from it. - // (See also flush_pending()). - internal int read_buf(byte[] buf, int start, int size) - { - int len = AvailableBytesIn; - - if (len > size) - { - len = size; - } - if (len == 0) - { - return 0; - } - - AvailableBytesIn -= len; - - if (dstate.WantRfc1950HeaderBytes) - { - _adler32 = Algorithms.Adler32.Calculate(_adler32, InputBuffer.AsSpan(NextIn, len)); - } - Array.Copy(InputBuffer, NextIn, buf, start, len); - NextIn += len; - TotalBytesIn += len; - return len; + dstate.nextPending = 0; } } + + // Read a new buffer from the current input stream, update the adler32 + // and total number of bytes read. All deflate() input goes through + // this function so some applications may wish to modify it to avoid + // allocating a large strm->next_in buffer and copying from it. + // (See also flush_pending()). + internal int read_buf(byte[] buf, int start, int size) + { + var len = AvailableBytesIn; + + if (len > size) + { + len = size; + } + if (len == 0) + { + return 0; + } + + AvailableBytesIn -= len; + + if (dstate.WantRfc1950HeaderBytes) + { + _adler32 = Algorithms.Adler32.Calculate(_adler32, InputBuffer.AsSpan(NextIn, len)); + } + Array.Copy(InputBuffer, NextIn, buf, start, len); + NextIn += len; + TotalBytesIn += len; + return len; + } } diff --git a/src/SharpCompress/Compressors/Deflate/ZlibConstants.cs b/src/SharpCompress/Compressors/Deflate/ZlibConstants.cs index 48d6c170..1a372a31 100644 --- a/src/SharpCompress/Compressors/Deflate/ZlibConstants.cs +++ b/src/SharpCompress/Compressors/Deflate/ZlibConstants.cs @@ -61,65 +61,64 @@ // ----------------------------------------------------------------------- -namespace SharpCompress.Compressors.Deflate +namespace SharpCompress.Compressors.Deflate; + +/// +/// A bunch of constants used in the Zlib interface. +/// +internal static class ZlibConstants { /// - /// A bunch of constants used in the Zlib interface. + /// The maximum number of window bits for the Deflate algorithm. /// - internal static class ZlibConstants - { - /// - /// The maximum number of window bits for the Deflate algorithm. - /// - public const int WindowBitsMax = 15; // 32K LZ77 window + public const int WindowBitsMax = 15; // 32K LZ77 window - /// - /// The default number of window bits for the Deflate algorithm. - /// - public const int WindowBitsDefault = WindowBitsMax; + /// + /// The default number of window bits for the Deflate algorithm. + /// + public const int WindowBitsDefault = WindowBitsMax; - /// - /// indicates everything is A-OK - /// - public const int Z_OK = 0; + /// + /// indicates everything is A-OK + /// + public const int Z_OK = 0; - /// - /// Indicates that the last operation reached the end of the stream. - /// - public const int Z_STREAM_END = 1; + /// + /// Indicates that the last operation reached the end of the stream. + /// + public const int Z_STREAM_END = 1; - /// - /// The operation ended in need of a dictionary. - /// - public const int Z_NEED_DICT = 2; + /// + /// The operation ended in need of a dictionary. + /// + public const int Z_NEED_DICT = 2; - /// - /// There was an error with the stream - not enough data, not open and readable, etc. - /// - public const int Z_STREAM_ERROR = -2; + /// + /// There was an error with the stream - not enough data, not open and readable, etc. + /// + public const int Z_STREAM_ERROR = -2; - /// - /// There was an error with the data - not enough data, bad data, etc. - /// - public const int Z_DATA_ERROR = -3; + /// + /// There was an error with the data - not enough data, bad data, etc. + /// + public const int Z_DATA_ERROR = -3; - /// - /// There was an error with the working buffer. - /// - public const int Z_BUF_ERROR = -5; + /// + /// There was an error with the working buffer. + /// + public const int Z_BUF_ERROR = -5; - /// - /// The size of the working buffer used in the ZlibCodec class. Defaults to 8192 bytes. - /// + /// + /// The size of the working buffer used in the ZlibCodec class. Defaults to 8192 bytes. + /// #if NETCF - public const int WorkingBufferSizeDefault = 8192; + public const int WorkingBufferSizeDefault = 8192; #else - public const int WorkingBufferSizeDefault = 16384; + public const int WorkingBufferSizeDefault = 16384; #endif - /// - /// The minimum size of the working buffer used in the ZlibCodec class. Currently it is 128 bytes. - /// - public const int WorkingBufferSizeMin = 1024; - } + /// + /// The minimum size of the working buffer used in the ZlibCodec class. Currently it is 128 bytes. + /// + public const int WorkingBufferSizeMin = 1024; } diff --git a/src/SharpCompress/Compressors/Deflate/ZlibStream.cs b/src/SharpCompress/Compressors/Deflate/ZlibStream.cs index 8d8be7ae..22ccfdd8 100644 --- a/src/SharpCompress/Compressors/Deflate/ZlibStream.cs +++ b/src/SharpCompress/Compressors/Deflate/ZlibStream.cs @@ -29,320 +29,319 @@ using System; using System.IO; using System.Text; -namespace SharpCompress.Compressors.Deflate +namespace SharpCompress.Compressors.Deflate; + +public class ZlibStream : Stream { - public class ZlibStream : Stream + private readonly ZlibBaseStream _baseStream; + private bool _disposed; + + public ZlibStream(Stream stream, CompressionMode mode) + : this(stream, mode, CompressionLevel.Default, Encoding.UTF8) { } + + public ZlibStream(Stream stream, CompressionMode mode, CompressionLevel level) + : this(stream, mode, level, Encoding.UTF8) { } + + public ZlibStream( + Stream stream, + CompressionMode mode, + CompressionLevel level, + Encoding encoding + ) { - private readonly ZlibBaseStream _baseStream; - private bool _disposed; - - public ZlibStream(Stream stream, CompressionMode mode) - : this(stream, mode, CompressionLevel.Default, Encoding.UTF8) { } - - public ZlibStream(Stream stream, CompressionMode mode, CompressionLevel level) - : this(stream, mode, level, Encoding.UTF8) { } - - public ZlibStream( - Stream stream, - CompressionMode mode, - CompressionLevel level, - Encoding encoding - ) - { - _baseStream = new ZlibBaseStream(stream, mode, level, ZlibStreamFlavor.ZLIB, encoding); - } - - #region Zlib properties - - /// - /// This property sets the flush behavior on the stream. - /// Sorry, though, not sure exactly how to describe all the various settings. - /// - public virtual FlushType FlushMode - { - get => (_baseStream._flushMode); - set - { - if (_disposed) - { - throw new ObjectDisposedException("ZlibStream"); - } - _baseStream._flushMode = value; - } - } - - /// - /// The size of the working buffer for the compression codec. - /// - /// - /// - /// - /// The working buffer is used for all stream operations. The default size is - /// 1024 bytes. The minimum size is 128 bytes. You may get better performance - /// with a larger buffer. Then again, you might not. You would have to test - /// it. - /// - /// - /// - /// Set this before the first call to Read() or Write() on the - /// stream. If you try to set it afterwards, it will throw. - /// - /// - public int BufferSize - { - get => _baseStream._bufferSize; - set - { - if (_disposed) - { - throw new ObjectDisposedException("ZlibStream"); - } - if (_baseStream._workingBuffer != null) - { - throw new ZlibException("The working buffer is already set."); - } - if (value < ZlibConstants.WorkingBufferSizeMin) - { - throw new ZlibException( - String.Format( - "Don't be silly. {0} bytes?? Use a bigger buffer, at least {1}.", - value, - ZlibConstants.WorkingBufferSizeMin - ) - ); - } - _baseStream._bufferSize = value; - } - } - - /// Returns the total number of bytes input so far. - public virtual long TotalIn => _baseStream._z.TotalBytesIn; - - /// Returns the total number of bytes output so far. - public virtual long TotalOut => _baseStream._z.TotalBytesOut; - - #endregion - - #region System.IO.Stream methods - - /// - /// Indicates whether the stream can be read. - /// - /// - /// The return value depends on whether the captive stream supports reading. - /// - public override bool CanRead - { - get - { - if (_disposed) - { - throw new ObjectDisposedException("ZlibStream"); - } - return _baseStream._stream.CanRead; - } - } - - /// - /// Indicates whether the stream supports Seek operations. - /// - /// - /// Always returns false. - /// - public override bool CanSeek => false; - - /// - /// Indicates whether the stream can be written. - /// - /// - /// The return value depends on whether the captive stream supports writing. - /// - public override bool CanWrite - { - get - { - if (_disposed) - { - throw new ObjectDisposedException("ZlibStream"); - } - return _baseStream._stream.CanWrite; - } - } - - /// - /// Reading this property always throws a . - /// - public override long Length => throw new NotSupportedException(); - - /// - /// The position of the stream pointer. - /// - /// - /// - /// Setting this property always throws a . Reading will return the total bytes - /// written out, if used in writing, or the total bytes read in, if used in - /// reading. The count may refer to compressed bytes or uncompressed bytes, - /// depending on how you've used the stream. - /// - public override long Position - { - get - { - if (_baseStream._streamMode == ZlibBaseStream.StreamMode.Writer) - { - return _baseStream._z.TotalBytesOut; - } - if (_baseStream._streamMode == ZlibBaseStream.StreamMode.Reader) - { - return _baseStream._z.TotalBytesIn; - } - return 0; - } - set => throw new NotSupportedException(); - } - - /// - /// Dispose the stream. - /// - /// - /// This may or may not result in a Close() call on the captive stream. - /// - protected override void Dispose(bool disposing) - { - try - { - if (!_disposed) - { - if (disposing) - { - _baseStream?.Dispose(); - } - _disposed = true; - } - } - finally - { - base.Dispose(disposing); - } - } - - /// - /// Flush the stream. - /// - public override void Flush() - { - if (_disposed) - { - throw new ObjectDisposedException("ZlibStream"); - } - _baseStream.Flush(); - } - - /// - /// Read data from the stream. - /// - /// - /// - /// - /// - /// If you wish to use the ZlibStream to compress data while reading, - /// you can create a ZlibStream with CompressionMode.Compress, - /// providing an uncompressed data stream. Then call Read() on that - /// ZlibStream, and the data read will be compressed. If you wish to - /// use the ZlibStream to decompress data while reading, you can create - /// a ZlibStream with CompressionMode.Decompress, providing a - /// readable compressed data stream. Then call Read() on that - /// ZlibStream, and the data will be decompressed as it is read. - /// - /// - /// - /// A ZlibStream can be used for Read() or Write(), but - /// not both. - /// - /// - /// - /// The buffer into which the read data should be placed. - /// the offset within that data array to put the first byte read. - /// the number of bytes to read. - public override int Read(byte[] buffer, int offset, int count) - { - if (_disposed) - { - throw new ObjectDisposedException("ZlibStream"); - } - return _baseStream.Read(buffer, offset, count); - } - - public override int ReadByte() - { - if (_disposed) - { - throw new ObjectDisposedException("ZlibStream"); - } - return _baseStream.ReadByte(); - } - - /// - /// Calling this method always throws a . - /// - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } - - /// - /// Calling this method always throws a . - /// - public override void SetLength(long value) - { - throw new NotSupportedException(); - } - - /// - /// Write data to the stream. - /// - /// - /// - /// - /// - /// If you wish to use the ZlibStream to compress data while writing, - /// you can create a ZlibStream with CompressionMode.Compress, - /// and a writable output stream. Then call Write() on that - /// ZlibStream, providing uncompressed data as input. The data sent to - /// the output stream will be the compressed form of the data written. If you - /// wish to use the ZlibStream to decompress data while writing, you - /// can create a ZlibStream with CompressionMode.Decompress, and a - /// writable output stream. Then call Write() on that stream, - /// providing previously compressed data. The data sent to the output stream - /// will be the decompressed form of the data written. - /// - /// - /// - /// A ZlibStream can be used for Read() or Write(), but not both. - /// - /// - /// The buffer holding data to write to the stream. - /// the offset within that data array to find the first byte to write. - /// the number of bytes to write. - public override void Write(byte[] buffer, int offset, int count) - { - if (_disposed) - { - throw new ObjectDisposedException("ZlibStream"); - } - _baseStream.Write(buffer, offset, count); - } - - public override void WriteByte(byte value) - { - if (_disposed) - { - throw new ObjectDisposedException("ZlibStream"); - } - _baseStream.WriteByte(value); - } - - #endregion System.IO.Stream methods + _baseStream = new ZlibBaseStream(stream, mode, level, ZlibStreamFlavor.ZLIB, encoding); } + + #region Zlib properties + + /// + /// This property sets the flush behavior on the stream. + /// Sorry, though, not sure exactly how to describe all the various settings. + /// + public virtual FlushType FlushMode + { + get => (_baseStream._flushMode); + set + { + if (_disposed) + { + throw new ObjectDisposedException("ZlibStream"); + } + _baseStream._flushMode = value; + } + } + + /// + /// The size of the working buffer for the compression codec. + /// + /// + /// + /// + /// The working buffer is used for all stream operations. The default size is + /// 1024 bytes. The minimum size is 128 bytes. You may get better performance + /// with a larger buffer. Then again, you might not. You would have to test + /// it. + /// + /// + /// + /// Set this before the first call to Read() or Write() on the + /// stream. If you try to set it afterwards, it will throw. + /// + /// + public int BufferSize + { + get => _baseStream._bufferSize; + set + { + if (_disposed) + { + throw new ObjectDisposedException("ZlibStream"); + } + if (_baseStream._workingBuffer != null) + { + throw new ZlibException("The working buffer is already set."); + } + if (value < ZlibConstants.WorkingBufferSizeMin) + { + throw new ZlibException( + string.Format( + "Don't be silly. {0} bytes?? Use a bigger buffer, at least {1}.", + value, + ZlibConstants.WorkingBufferSizeMin + ) + ); + } + _baseStream._bufferSize = value; + } + } + + /// Returns the total number of bytes input so far. + public virtual long TotalIn => _baseStream._z.TotalBytesIn; + + /// Returns the total number of bytes output so far. + public virtual long TotalOut => _baseStream._z.TotalBytesOut; + + #endregion + + #region System.IO.Stream methods + + /// + /// Indicates whether the stream can be read. + /// + /// + /// The return value depends on whether the captive stream supports reading. + /// + public override bool CanRead + { + get + { + if (_disposed) + { + throw new ObjectDisposedException("ZlibStream"); + } + return _baseStream._stream.CanRead; + } + } + + /// + /// Indicates whether the stream supports Seek operations. + /// + /// + /// Always returns false. + /// + public override bool CanSeek => false; + + /// + /// Indicates whether the stream can be written. + /// + /// + /// The return value depends on whether the captive stream supports writing. + /// + public override bool CanWrite + { + get + { + if (_disposed) + { + throw new ObjectDisposedException("ZlibStream"); + } + return _baseStream._stream.CanWrite; + } + } + + /// + /// Reading this property always throws a . + /// + public override long Length => throw new NotSupportedException(); + + /// + /// The position of the stream pointer. + /// + /// + /// + /// Setting this property always throws a . Reading will return the total bytes + /// written out, if used in writing, or the total bytes read in, if used in + /// reading. The count may refer to compressed bytes or uncompressed bytes, + /// depending on how you've used the stream. + /// + public override long Position + { + get + { + if (_baseStream._streamMode == ZlibBaseStream.StreamMode.Writer) + { + return _baseStream._z.TotalBytesOut; + } + if (_baseStream._streamMode == ZlibBaseStream.StreamMode.Reader) + { + return _baseStream._z.TotalBytesIn; + } + return 0; + } + set => throw new NotSupportedException(); + } + + /// + /// Dispose the stream. + /// + /// + /// This may or may not result in a Close() call on the captive stream. + /// + protected override void Dispose(bool disposing) + { + try + { + if (!_disposed) + { + if (disposing) + { + _baseStream?.Dispose(); + } + _disposed = true; + } + } + finally + { + base.Dispose(disposing); + } + } + + /// + /// Flush the stream. + /// + public override void Flush() + { + if (_disposed) + { + throw new ObjectDisposedException("ZlibStream"); + } + _baseStream.Flush(); + } + + /// + /// Read data from the stream. + /// + /// + /// + /// + /// + /// If you wish to use the ZlibStream to compress data while reading, + /// you can create a ZlibStream with CompressionMode.Compress, + /// providing an uncompressed data stream. Then call Read() on that + /// ZlibStream, and the data read will be compressed. If you wish to + /// use the ZlibStream to decompress data while reading, you can create + /// a ZlibStream with CompressionMode.Decompress, providing a + /// readable compressed data stream. Then call Read() on that + /// ZlibStream, and the data will be decompressed as it is read. + /// + /// + /// + /// A ZlibStream can be used for Read() or Write(), but + /// not both. + /// + /// + /// + /// The buffer into which the read data should be placed. + /// the offset within that data array to put the first byte read. + /// the number of bytes to read. + public override int Read(byte[] buffer, int offset, int count) + { + if (_disposed) + { + throw new ObjectDisposedException("ZlibStream"); + } + return _baseStream.Read(buffer, offset, count); + } + + public override int ReadByte() + { + if (_disposed) + { + throw new ObjectDisposedException("ZlibStream"); + } + return _baseStream.ReadByte(); + } + + /// + /// Calling this method always throws a . + /// + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } + + /// + /// Calling this method always throws a . + /// + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + /// + /// Write data to the stream. + /// + /// + /// + /// + /// + /// If you wish to use the ZlibStream to compress data while writing, + /// you can create a ZlibStream with CompressionMode.Compress, + /// and a writable output stream. Then call Write() on that + /// ZlibStream, providing uncompressed data as input. The data sent to + /// the output stream will be the compressed form of the data written. If you + /// wish to use the ZlibStream to decompress data while writing, you + /// can create a ZlibStream with CompressionMode.Decompress, and a + /// writable output stream. Then call Write() on that stream, + /// providing previously compressed data. The data sent to the output stream + /// will be the decompressed form of the data written. + /// + /// + /// + /// A ZlibStream can be used for Read() or Write(), but not both. + /// + /// + /// The buffer holding data to write to the stream. + /// the offset within that data array to find the first byte to write. + /// the number of bytes to write. + public override void Write(byte[] buffer, int offset, int count) + { + if (_disposed) + { + throw new ObjectDisposedException("ZlibStream"); + } + _baseStream.Write(buffer, offset, count); + } + + public override void WriteByte(byte value) + { + if (_disposed) + { + throw new ObjectDisposedException("ZlibStream"); + } + _baseStream.WriteByte(value); + } + + #endregion System.IO.Stream methods } diff --git a/src/SharpCompress/Compressors/Deflate64/BlockType.cs b/src/SharpCompress/Compressors/Deflate64/BlockType.cs index c8938079..5bd9eb83 100644 --- a/src/SharpCompress/Compressors/Deflate64/BlockType.cs +++ b/src/SharpCompress/Compressors/Deflate64/BlockType.cs @@ -2,12 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -namespace SharpCompress.Compressors.Deflate64 +namespace SharpCompress.Compressors.Deflate64; + +internal enum BlockType { - internal enum BlockType - { - Uncompressed = 0, - Static = 1, - Dynamic = 2 - } + Uncompressed = 0, + Static = 1, + Dynamic = 2 } diff --git a/src/SharpCompress/Compressors/Deflate64/DeflateInput.cs b/src/SharpCompress/Compressors/Deflate64/DeflateInput.cs index 2305d241..f539e3bb 100644 --- a/src/SharpCompress/Compressors/Deflate64/DeflateInput.cs +++ b/src/SharpCompress/Compressors/Deflate64/DeflateInput.cs @@ -4,46 +4,45 @@ using System.Diagnostics; -namespace SharpCompress.Compressors.Deflate64 +namespace SharpCompress.Compressors.Deflate64; + +internal sealed class DeflateInput { - internal sealed class DeflateInput + public DeflateInput(byte[] buffer) { - public DeflateInput(byte[] buffer) + Buffer = buffer; + } + + public byte[] Buffer { get; } + public int Count { get; set; } + public int StartIndex { get; set; } + + internal void ConsumeBytes(int n) + { + Debug.Assert(n <= Count, "Should use more bytes than what we have in the buffer"); + StartIndex += n; + Count -= n; + Debug.Assert(StartIndex + Count <= Buffer.Length, "Input buffer is in invalid state!"); + } + + internal InputState DumpState() => new InputState(Count, StartIndex); + + internal void RestoreState(InputState state) + { + Count = state._count; + StartIndex = state._startIndex; + } + + internal /*readonly */ +readonly struct InputState + { + internal readonly int _count; + internal readonly int _startIndex; + + internal InputState(int count, int startIndex) { - Buffer = buffer; - } - - public byte[] Buffer { get; } - public int Count { get; set; } - public int StartIndex { get; set; } - - internal void ConsumeBytes(int n) - { - Debug.Assert(n <= Count, "Should use more bytes than what we have in the buffer"); - StartIndex += n; - Count -= n; - Debug.Assert(StartIndex + Count <= Buffer.Length, "Input buffer is in invalid state!"); - } - - internal InputState DumpState() => new InputState(Count, StartIndex); - - internal void RestoreState(InputState state) - { - Count = state._count; - StartIndex = state._startIndex; - } - - internal /*readonly */ - struct InputState - { - internal readonly int _count; - internal readonly int _startIndex; - - internal InputState(int count, int startIndex) - { - _count = count; - _startIndex = startIndex; - } + _count = count; + _startIndex = startIndex; } } } diff --git a/src/SharpCompress/Compressors/Deflate64/FastEncoderStatus.cs b/src/SharpCompress/Compressors/Deflate64/FastEncoderStatus.cs index 8b0992da..71e3f680 100644 --- a/src/SharpCompress/Compressors/Deflate64/FastEncoderStatus.cs +++ b/src/SharpCompress/Compressors/Deflate64/FastEncoderStatus.cs @@ -5,975 +5,974 @@ using System; using System.Diagnostics; -namespace SharpCompress.Compressors.Deflate64 +namespace SharpCompress.Compressors.Deflate64; + +internal static class FastEncoderStatics { - internal static class FastEncoderStatics + // static information for encoding, DO NOT MODIFY + + internal static ReadOnlySpan FAST_ENCODER_TREE_STRUCTURE_DATA => + new byte[] + { + 0xec, + 0xbd, + 0x07, + 0x60, + 0x1c, + 0x49, + 0x96, + 0x25, + 0x26, + 0x2f, + 0x6d, + 0xca, + 0x7b, + 0x7f, + 0x4a, + 0xf5, + 0x4a, + 0xd7, + 0xe0, + 0x74, + 0xa1, + 0x08, + 0x80, + 0x60, + 0x13, + 0x24, + 0xd8, + 0x90, + 0x40, + 0x10, + 0xec, + 0xc1, + 0x88, + 0xcd, + 0xe6, + 0x92, + 0xec, + 0x1d, + 0x69, + 0x47, + 0x23, + 0x29, + 0xab, + 0x2a, + 0x81, + 0xca, + 0x65, + 0x56, + 0x65, + 0x5d, + 0x66, + 0x16, + 0x40, + 0xcc, + 0xed, + 0x9d, + 0xbc, + 0xf7, + 0xde, + 0x7b, + 0xef, + 0xbd, + 0xf7, + 0xde, + 0x7b, + 0xef, + 0xbd, + 0xf7, + 0xba, + 0x3b, + 0x9d, + 0x4e, + 0x27, + 0xf7, + 0xdf, + 0xff, + 0x3f, + 0x5c, + 0x66, + 0x64, + 0x01, + 0x6c, + 0xf6, + 0xce, + 0x4a, + 0xda, + 0xc9, + 0x9e, + 0x21, + 0x80, + 0xaa, + 0xc8, + 0x1f, + 0x3f, + 0x7e, + 0x7c, + 0x1f, + 0x3f + }; + + internal static ReadOnlySpan B_FINAL_FAST_ENCODER_TREE_STRUCTURE_DATA => + new byte[] + { + 0xed, + 0xbd, + 0x07, + 0x60, + 0x1c, + 0x49, + 0x96, + 0x25, + 0x26, + 0x2f, + 0x6d, + 0xca, + 0x7b, + 0x7f, + 0x4a, + 0xf5, + 0x4a, + 0xd7, + 0xe0, + 0x74, + 0xa1, + 0x08, + 0x80, + 0x60, + 0x13, + 0x24, + 0xd8, + 0x90, + 0x40, + 0x10, + 0xec, + 0xc1, + 0x88, + 0xcd, + 0xe6, + 0x92, + 0xec, + 0x1d, + 0x69, + 0x47, + 0x23, + 0x29, + 0xab, + 0x2a, + 0x81, + 0xca, + 0x65, + 0x56, + 0x65, + 0x5d, + 0x66, + 0x16, + 0x40, + 0xcc, + 0xed, + 0x9d, + 0xbc, + 0xf7, + 0xde, + 0x7b, + 0xef, + 0xbd, + 0xf7, + 0xde, + 0x7b, + 0xef, + 0xbd, + 0xf7, + 0xba, + 0x3b, + 0x9d, + 0x4e, + 0x27, + 0xf7, + 0xdf, + 0xff, + 0x3f, + 0x5c, + 0x66, + 0x64, + 0x01, + 0x6c, + 0xf6, + 0xce, + 0x4a, + 0xda, + 0xc9, + 0x9e, + 0x21, + 0x80, + 0xaa, + 0xc8, + 0x1f, + 0x3f, + 0x7e, + 0x7c, + 0x1f, + 0x3f + }; + + // Output a currentMatch with length matchLen (>= MIN_MATCH) and displacement matchPos + // + // Optimisation: unlike the other encoders, here we have an array of codes for each currentMatch + // length (not just each currentMatch length slot), complete with all the extra bits filled in, in + // a single array element. + // + // There are many advantages to doing this: + // + // 1. A single array lookup on g_FastEncoderLiteralCodeInfo, instead of separate array lookups + // on g_LengthLookup (to get the length slot), g_FastEncoderLiteralTreeLength, + // g_FastEncoderLiteralTreeCode, g_ExtraLengthBits, and g_BitMask + // + // 2. The array is an array of ULONGs, so no access penalty, unlike for accessing those USHORT + // code arrays in the other encoders (although they could be made into ULONGs with some + // modifications to the source). + // + // Note, if we could guarantee that codeLen <= 16 always, then we could skip an if statement here. + // + // A completely different optimisation is used for the distance codes since, obviously, a table for + // all 8192 distances combining their extra bits is not feasible. The distance codeinfo table is + // made up of code[], len[] and # extraBits for this code. + // + // The advantages are similar to the above; a ULONG array instead of a USHORT and BYTE array, better + // cache locality, fewer memory operations. + // + + + // Encoding information for literal and Length. + // The least 5 significant bits are the length + // and the rest is the code bits. + + internal static readonly uint[] FAST_ENCODER_LITERAL_CODE_INFO = { - // static information for encoding, DO NOT MODIFY + 0x0000d7ee, + 0x0004d7ee, + 0x0002d7ee, + 0x0006d7ee, + 0x0001d7ee, + 0x0005d7ee, + 0x0003d7ee, + 0x0007d7ee, + 0x000037ee, + 0x0000c7ec, + 0x00000126, + 0x000437ee, + 0x000237ee, + 0x000637ee, + 0x000137ee, + 0x000537ee, + 0x000337ee, + 0x000737ee, + 0x0000b7ee, + 0x0004b7ee, + 0x0002b7ee, + 0x0006b7ee, + 0x0001b7ee, + 0x0005b7ee, + 0x0003b7ee, + 0x0007b7ee, + 0x000077ee, + 0x000477ee, + 0x000277ee, + 0x000677ee, + 0x000017ed, + 0x000177ee, + 0x00000526, + 0x000577ee, + 0x000023ea, + 0x0001c7ec, + 0x000377ee, + 0x000777ee, + 0x000217ed, + 0x000063ea, + 0x00000b68, + 0x00000ee9, + 0x00005beb, + 0x000013ea, + 0x00000467, + 0x00001b68, + 0x00000c67, + 0x00002ee9, + 0x00000768, + 0x00001768, + 0x00000f68, + 0x00001ee9, + 0x00001f68, + 0x00003ee9, + 0x000053ea, + 0x000001e9, + 0x000000e8, + 0x000021e9, + 0x000011e9, + 0x000010e8, + 0x000031e9, + 0x000033ea, + 0x000008e8, + 0x0000f7ee, + 0x0004f7ee, + 0x000018e8, + 0x000009e9, + 0x000004e8, + 0x000029e9, + 0x000014e8, + 0x000019e9, + 0x000073ea, + 0x0000dbeb, + 0x00000ce8, + 0x00003beb, + 0x0002f7ee, + 0x000039e9, + 0x00000bea, + 0x000005e9, + 0x00004bea, + 0x000025e9, + 0x000027ec, + 0x000015e9, + 0x000035e9, + 0x00000de9, + 0x00002bea, + 0x000127ec, + 0x0000bbeb, + 0x0006f7ee, + 0x0001f7ee, + 0x0000a7ec, + 0x00007beb, + 0x0005f7ee, + 0x0000fbeb, + 0x0003f7ee, + 0x0007f7ee, + 0x00000fee, + 0x00000326, + 0x00000267, + 0x00000a67, + 0x00000667, + 0x00000726, + 0x00001ce8, + 0x000002e8, + 0x00000e67, + 0x000000a6, + 0x0001a7ec, + 0x00002de9, + 0x000004a6, + 0x00000167, + 0x00000967, + 0x000002a6, + 0x00000567, + 0x000117ed, + 0x000006a6, + 0x000001a6, + 0x000005a6, + 0x00000d67, + 0x000012e8, + 0x00000ae8, + 0x00001de9, + 0x00001ae8, + 0x000007eb, + 0x000317ed, + 0x000067ec, + 0x000097ed, + 0x000297ed, + 0x00040fee, + 0x00020fee, + 0x00060fee, + 0x00010fee, + 0x00050fee, + 0x00030fee, + 0x00070fee, + 0x00008fee, + 0x00048fee, + 0x00028fee, + 0x00068fee, + 0x00018fee, + 0x00058fee, + 0x00038fee, + 0x00078fee, + 0x00004fee, + 0x00044fee, + 0x00024fee, + 0x00064fee, + 0x00014fee, + 0x00054fee, + 0x00034fee, + 0x00074fee, + 0x0000cfee, + 0x0004cfee, + 0x0002cfee, + 0x0006cfee, + 0x0001cfee, + 0x0005cfee, + 0x0003cfee, + 0x0007cfee, + 0x00002fee, + 0x00042fee, + 0x00022fee, + 0x00062fee, + 0x00012fee, + 0x00052fee, + 0x00032fee, + 0x00072fee, + 0x0000afee, + 0x0004afee, + 0x0002afee, + 0x0006afee, + 0x0001afee, + 0x0005afee, + 0x0003afee, + 0x0007afee, + 0x00006fee, + 0x00046fee, + 0x00026fee, + 0x00066fee, + 0x00016fee, + 0x00056fee, + 0x00036fee, + 0x00076fee, + 0x0000efee, + 0x0004efee, + 0x0002efee, + 0x0006efee, + 0x0001efee, + 0x0005efee, + 0x0003efee, + 0x0007efee, + 0x00001fee, + 0x00041fee, + 0x00021fee, + 0x00061fee, + 0x00011fee, + 0x00051fee, + 0x00031fee, + 0x00071fee, + 0x00009fee, + 0x00049fee, + 0x00029fee, + 0x00069fee, + 0x00019fee, + 0x00059fee, + 0x00039fee, + 0x00079fee, + 0x00005fee, + 0x00045fee, + 0x00025fee, + 0x00065fee, + 0x00015fee, + 0x00055fee, + 0x00035fee, + 0x00075fee, + 0x0000dfee, + 0x0004dfee, + 0x0002dfee, + 0x0006dfee, + 0x0001dfee, + 0x0005dfee, + 0x0003dfee, + 0x0007dfee, + 0x00003fee, + 0x00043fee, + 0x00023fee, + 0x00063fee, + 0x00013fee, + 0x00053fee, + 0x00033fee, + 0x00073fee, + 0x0000bfee, + 0x0004bfee, + 0x0002bfee, + 0x0006bfee, + 0x0001bfee, + 0x0005bfee, + 0x0003bfee, + 0x0007bfee, + 0x00007fee, + 0x00047fee, + 0x00027fee, + 0x00067fee, + 0x00017fee, + 0x000197ed, + 0x000397ed, + 0x000057ed, + 0x00057fee, + 0x000257ed, + 0x00037fee, + 0x000157ed, + 0x00077fee, + 0x000357ed, + 0x0000ffee, + 0x0004ffee, + 0x0002ffee, + 0x0006ffee, + 0x0001ffee, + 0x00000084, + 0x00000003, + 0x00000184, + 0x00000044, + 0x00000144, + 0x000000c5, + 0x000002c5, + 0x000001c5, + 0x000003c6, + 0x000007c6, + 0x00000026, + 0x00000426, + 0x000003a7, + 0x00000ba7, + 0x000007a7, + 0x00000fa7, + 0x00000227, + 0x00000627, + 0x00000a27, + 0x00000e27, + 0x00000068, + 0x00000868, + 0x00001068, + 0x00001868, + 0x00000369, + 0x00001369, + 0x00002369, + 0x00003369, + 0x000006ea, + 0x000026ea, + 0x000046ea, + 0x000066ea, + 0x000016eb, + 0x000036eb, + 0x000056eb, + 0x000076eb, + 0x000096eb, + 0x0000b6eb, + 0x0000d6eb, + 0x0000f6eb, + 0x00003dec, + 0x00007dec, + 0x0000bdec, + 0x0000fdec, + 0x00013dec, + 0x00017dec, + 0x0001bdec, + 0x0001fdec, + 0x00006bed, + 0x0000ebed, + 0x00016bed, + 0x0001ebed, + 0x00026bed, + 0x0002ebed, + 0x00036bed, + 0x0003ebed, + 0x000003ec, + 0x000043ec, + 0x000083ec, + 0x0000c3ec, + 0x000103ec, + 0x000143ec, + 0x000183ec, + 0x0001c3ec, + 0x00001bee, + 0x00009bee, + 0x00011bee, + 0x00019bee, + 0x00021bee, + 0x00029bee, + 0x00031bee, + 0x00039bee, + 0x00041bee, + 0x00049bee, + 0x00051bee, + 0x00059bee, + 0x00061bee, + 0x00069bee, + 0x00071bee, + 0x00079bee, + 0x000167f0, + 0x000367f0, + 0x000567f0, + 0x000767f0, + 0x000967f0, + 0x000b67f0, + 0x000d67f0, + 0x000f67f0, + 0x001167f0, + 0x001367f0, + 0x001567f0, + 0x001767f0, + 0x001967f0, + 0x001b67f0, + 0x001d67f0, + 0x001f67f0, + 0x000087ef, + 0x000187ef, + 0x000287ef, + 0x000387ef, + 0x000487ef, + 0x000587ef, + 0x000687ef, + 0x000787ef, + 0x000887ef, + 0x000987ef, + 0x000a87ef, + 0x000b87ef, + 0x000c87ef, + 0x000d87ef, + 0x000e87ef, + 0x000f87ef, + 0x0000e7f0, + 0x0002e7f0, + 0x0004e7f0, + 0x0006e7f0, + 0x0008e7f0, + 0x000ae7f0, + 0x000ce7f0, + 0x000ee7f0, + 0x0010e7f0, + 0x0012e7f0, + 0x0014e7f0, + 0x0016e7f0, + 0x0018e7f0, + 0x001ae7f0, + 0x001ce7f0, + 0x001ee7f0, + 0x0005fff3, + 0x000dfff3, + 0x0015fff3, + 0x001dfff3, + 0x0025fff3, + 0x002dfff3, + 0x0035fff3, + 0x003dfff3, + 0x0045fff3, + 0x004dfff3, + 0x0055fff3, + 0x005dfff3, + 0x0065fff3, + 0x006dfff3, + 0x0075fff3, + 0x007dfff3, + 0x0085fff3, + 0x008dfff3, + 0x0095fff3, + 0x009dfff3, + 0x00a5fff3, + 0x00adfff3, + 0x00b5fff3, + 0x00bdfff3, + 0x00c5fff3, + 0x00cdfff3, + 0x00d5fff3, + 0x00ddfff3, + 0x00e5fff3, + 0x00edfff3, + 0x00f5fff3, + 0x00fdfff3, + 0x0003fff3, + 0x000bfff3, + 0x0013fff3, + 0x001bfff3, + 0x0023fff3, + 0x002bfff3, + 0x0033fff3, + 0x003bfff3, + 0x0043fff3, + 0x004bfff3, + 0x0053fff3, + 0x005bfff3, + 0x0063fff3, + 0x006bfff3, + 0x0073fff3, + 0x007bfff3, + 0x0083fff3, + 0x008bfff3, + 0x0093fff3, + 0x009bfff3, + 0x00a3fff3, + 0x00abfff3, + 0x00b3fff3, + 0x00bbfff3, + 0x00c3fff3, + 0x00cbfff3, + 0x00d3fff3, + 0x00dbfff3, + 0x00e3fff3, + 0x00ebfff3, + 0x00f3fff3, + 0x00fbfff3, + 0x0007fff3, + 0x000ffff3, + 0x0017fff3, + 0x001ffff3, + 0x0027fff3, + 0x002ffff3, + 0x0037fff3, + 0x003ffff3, + 0x0047fff3, + 0x004ffff3, + 0x0057fff3, + 0x005ffff3, + 0x0067fff3, + 0x006ffff3, + 0x0077fff3, + 0x007ffff3, + 0x0087fff3, + 0x008ffff3, + 0x0097fff3, + 0x009ffff3, + 0x00a7fff3, + 0x00affff3, + 0x00b7fff3, + 0x00bffff3, + 0x00c7fff3, + 0x00cffff3, + 0x00d7fff3, + 0x00dffff3, + 0x00e7fff3, + 0x00effff3, + 0x00f7fff3, + 0x00fffff3, + 0x0001e7f1, + 0x0003e7f1, + 0x0005e7f1, + 0x0007e7f1, + 0x0009e7f1, + 0x000be7f1, + 0x000de7f1, + 0x000fe7f1, + 0x0011e7f1, + 0x0013e7f1, + 0x0015e7f1, + 0x0017e7f1, + 0x0019e7f1, + 0x001be7f1, + 0x001de7f1, + 0x001fe7f1, + 0x0021e7f1, + 0x0023e7f1, + 0x0025e7f1, + 0x0027e7f1, + 0x0029e7f1, + 0x002be7f1, + 0x002de7f1, + 0x002fe7f1, + 0x0031e7f1, + 0x0033e7f1, + 0x0035e7f1, + 0x0037e7f1, + 0x0039e7f1, + 0x003be7f1, + 0x003de7f1, + 0x000047eb + }; - internal static ReadOnlySpan FAST_ENCODER_TREE_STRUCTURE_DATA => - new byte[] + internal static readonly uint[] FAST_ENCODER_DISTANCE_CODE_INFO = + { + 0x00000f06, + 0x0001ff0a, + 0x0003ff0b, + 0x0007ff0b, + 0x0000ff19, + 0x00003f18, + 0x0000bf28, + 0x00007f28, + 0x00001f37, + 0x00005f37, + 0x00000d45, + 0x00002f46, + 0x00000054, + 0x00001d55, + 0x00000864, + 0x00000365, + 0x00000474, + 0x00001375, + 0x00000c84, + 0x00000284, + 0x00000a94, + 0x00000694, + 0x00000ea4, + 0x000001a4, + 0x000009b4, + 0x00000bb5, + 0x000005c4, + 0x00001bc5, + 0x000007d5, + 0x000017d5, + 0x00000000, + 0x00000100 + }; + + internal static readonly uint[] BIT_MASK = + { + 0, + 1, + 3, + 7, + 15, + 31, + 63, + 127, + 255, + 511, + 1023, + 2047, + 4095, + 8191, + 16383, + 32767 + }; + internal static readonly byte[] EXTRA_LENGTH_BITS = + { + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 4, + 4, + 4, + 4, + 5, + 5, + 5, + 5, + 0 + }; + internal static readonly byte[] EXTRA_DISTANCE_BITS = + { + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 2, + 3, + 3, + 4, + 4, + 5, + 5, + 6, + 6, + 7, + 7, + 8, + 8, + 9, + 9, + 10, + 10, + 11, + 11, + 12, + 12, + 13, + 13, + 0, + 0 + }; + internal const int NUM_CHARS = 256; + internal const int NUM_LENGTH_BASE_CODES = 29; + internal const int NUM_DIST_BASE_CODES = 30; + + internal const uint FAST_ENCODER_POST_TREE_BIT_BUF = 0x0022; + internal const int FAST_ENCODER_POST_TREE_BIT_COUNT = 9; + + internal const uint NO_COMPRESSION_HEADER = 0x0; + internal const int NO_COMPRESSION_HEADER_BIT_COUNT = 3; + internal const uint B_FINAL_NO_COMPRESSION_HEADER = 0x1; + internal const int B_FINAL_NO_COMPRESSION_HEADER_BIT_COUNT = 3; + internal const int MAX_CODE_LEN = 16; + + private static readonly byte[] S_DIST_LOOKUP = CreateDistanceLookup(); + + private static byte[] CreateDistanceLookup() + { + var result = new byte[512]; + + // Generate the global slot tables which allow us to convert a distance + // (0..32K) to a distance slot (0..29) + // + // Distance table + // Extra Extra Extra + // Code Bits Dist Code Bits Dist Code Bits Distance + // ---- ---- ---- ---- ---- ------ ---- ---- -------- + // 0 0 1 10 4 33-48 20 9 1025-1536 + // 1 0 2 11 4 49-64 21 9 1537-2048 + // 2 0 3 12 5 65-96 22 10 2049-3072 + // 3 0 4 13 5 97-128 23 10 3073-4096 + // 4 1 5,6 14 6 129-192 24 11 4097-6144 + // 5 1 7,8 15 6 193-256 25 11 6145-8192 + // 6 2 9-12 16 7 257-384 26 12 8193-12288 + // 7 2 13-16 17 7 385-512 27 12 12289-16384 + // 8 3 17-24 18 8 513-768 28 13 16385-24576 + // 9 3 25-32 19 8 769-1024 29 13 24577-32768 + + // Initialize the mapping length (0..255) -> length code (0..28) + //int length = 0; + //for (code = 0; code < FastEncoderStatics.NumLengthBaseCodes-1; code++) { + // for (int n = 0; n < (1 << FastEncoderStatics.ExtraLengthBits[code]); n++) + // lengthLookup[length++] = (byte) code; + //} + //lengthLookup[length-1] = (byte) code; + + // Initialize the mapping dist (0..32K) -> dist code (0..29) + var dist = 0; + int code; + for (code = 0; code < 16; code++) + { + for (var n = 0; n < (1 << EXTRA_DISTANCE_BITS[code]); n++) { - 0xec, - 0xbd, - 0x07, - 0x60, - 0x1c, - 0x49, - 0x96, - 0x25, - 0x26, - 0x2f, - 0x6d, - 0xca, - 0x7b, - 0x7f, - 0x4a, - 0xf5, - 0x4a, - 0xd7, - 0xe0, - 0x74, - 0xa1, - 0x08, - 0x80, - 0x60, - 0x13, - 0x24, - 0xd8, - 0x90, - 0x40, - 0x10, - 0xec, - 0xc1, - 0x88, - 0xcd, - 0xe6, - 0x92, - 0xec, - 0x1d, - 0x69, - 0x47, - 0x23, - 0x29, - 0xab, - 0x2a, - 0x81, - 0xca, - 0x65, - 0x56, - 0x65, - 0x5d, - 0x66, - 0x16, - 0x40, - 0xcc, - 0xed, - 0x9d, - 0xbc, - 0xf7, - 0xde, - 0x7b, - 0xef, - 0xbd, - 0xf7, - 0xde, - 0x7b, - 0xef, - 0xbd, - 0xf7, - 0xba, - 0x3b, - 0x9d, - 0x4e, - 0x27, - 0xf7, - 0xdf, - 0xff, - 0x3f, - 0x5c, - 0x66, - 0x64, - 0x01, - 0x6c, - 0xf6, - 0xce, - 0x4a, - 0xda, - 0xc9, - 0x9e, - 0x21, - 0x80, - 0xaa, - 0xc8, - 0x1f, - 0x3f, - 0x7e, - 0x7c, - 0x1f, - 0x3f - }; - - internal static ReadOnlySpan B_FINAL_FAST_ENCODER_TREE_STRUCTURE_DATA => - new byte[] - { - 0xed, - 0xbd, - 0x07, - 0x60, - 0x1c, - 0x49, - 0x96, - 0x25, - 0x26, - 0x2f, - 0x6d, - 0xca, - 0x7b, - 0x7f, - 0x4a, - 0xf5, - 0x4a, - 0xd7, - 0xe0, - 0x74, - 0xa1, - 0x08, - 0x80, - 0x60, - 0x13, - 0x24, - 0xd8, - 0x90, - 0x40, - 0x10, - 0xec, - 0xc1, - 0x88, - 0xcd, - 0xe6, - 0x92, - 0xec, - 0x1d, - 0x69, - 0x47, - 0x23, - 0x29, - 0xab, - 0x2a, - 0x81, - 0xca, - 0x65, - 0x56, - 0x65, - 0x5d, - 0x66, - 0x16, - 0x40, - 0xcc, - 0xed, - 0x9d, - 0xbc, - 0xf7, - 0xde, - 0x7b, - 0xef, - 0xbd, - 0xf7, - 0xde, - 0x7b, - 0xef, - 0xbd, - 0xf7, - 0xba, - 0x3b, - 0x9d, - 0x4e, - 0x27, - 0xf7, - 0xdf, - 0xff, - 0x3f, - 0x5c, - 0x66, - 0x64, - 0x01, - 0x6c, - 0xf6, - 0xce, - 0x4a, - 0xda, - 0xc9, - 0x9e, - 0x21, - 0x80, - 0xaa, - 0xc8, - 0x1f, - 0x3f, - 0x7e, - 0x7c, - 0x1f, - 0x3f - }; - - // Output a currentMatch with length matchLen (>= MIN_MATCH) and displacement matchPos - // - // Optimisation: unlike the other encoders, here we have an array of codes for each currentMatch - // length (not just each currentMatch length slot), complete with all the extra bits filled in, in - // a single array element. - // - // There are many advantages to doing this: - // - // 1. A single array lookup on g_FastEncoderLiteralCodeInfo, instead of separate array lookups - // on g_LengthLookup (to get the length slot), g_FastEncoderLiteralTreeLength, - // g_FastEncoderLiteralTreeCode, g_ExtraLengthBits, and g_BitMask - // - // 2. The array is an array of ULONGs, so no access penalty, unlike for accessing those USHORT - // code arrays in the other encoders (although they could be made into ULONGs with some - // modifications to the source). - // - // Note, if we could guarantee that codeLen <= 16 always, then we could skip an if statement here. - // - // A completely different optimisation is used for the distance codes since, obviously, a table for - // all 8192 distances combining their extra bits is not feasible. The distance codeinfo table is - // made up of code[], len[] and # extraBits for this code. - // - // The advantages are similar to the above; a ULONG array instead of a USHORT and BYTE array, better - // cache locality, fewer memory operations. - // - - - // Encoding information for literal and Length. - // The least 5 significant bits are the length - // and the rest is the code bits. - - internal static readonly uint[] FAST_ENCODER_LITERAL_CODE_INFO = - { - 0x0000d7ee, - 0x0004d7ee, - 0x0002d7ee, - 0x0006d7ee, - 0x0001d7ee, - 0x0005d7ee, - 0x0003d7ee, - 0x0007d7ee, - 0x000037ee, - 0x0000c7ec, - 0x00000126, - 0x000437ee, - 0x000237ee, - 0x000637ee, - 0x000137ee, - 0x000537ee, - 0x000337ee, - 0x000737ee, - 0x0000b7ee, - 0x0004b7ee, - 0x0002b7ee, - 0x0006b7ee, - 0x0001b7ee, - 0x0005b7ee, - 0x0003b7ee, - 0x0007b7ee, - 0x000077ee, - 0x000477ee, - 0x000277ee, - 0x000677ee, - 0x000017ed, - 0x000177ee, - 0x00000526, - 0x000577ee, - 0x000023ea, - 0x0001c7ec, - 0x000377ee, - 0x000777ee, - 0x000217ed, - 0x000063ea, - 0x00000b68, - 0x00000ee9, - 0x00005beb, - 0x000013ea, - 0x00000467, - 0x00001b68, - 0x00000c67, - 0x00002ee9, - 0x00000768, - 0x00001768, - 0x00000f68, - 0x00001ee9, - 0x00001f68, - 0x00003ee9, - 0x000053ea, - 0x000001e9, - 0x000000e8, - 0x000021e9, - 0x000011e9, - 0x000010e8, - 0x000031e9, - 0x000033ea, - 0x000008e8, - 0x0000f7ee, - 0x0004f7ee, - 0x000018e8, - 0x000009e9, - 0x000004e8, - 0x000029e9, - 0x000014e8, - 0x000019e9, - 0x000073ea, - 0x0000dbeb, - 0x00000ce8, - 0x00003beb, - 0x0002f7ee, - 0x000039e9, - 0x00000bea, - 0x000005e9, - 0x00004bea, - 0x000025e9, - 0x000027ec, - 0x000015e9, - 0x000035e9, - 0x00000de9, - 0x00002bea, - 0x000127ec, - 0x0000bbeb, - 0x0006f7ee, - 0x0001f7ee, - 0x0000a7ec, - 0x00007beb, - 0x0005f7ee, - 0x0000fbeb, - 0x0003f7ee, - 0x0007f7ee, - 0x00000fee, - 0x00000326, - 0x00000267, - 0x00000a67, - 0x00000667, - 0x00000726, - 0x00001ce8, - 0x000002e8, - 0x00000e67, - 0x000000a6, - 0x0001a7ec, - 0x00002de9, - 0x000004a6, - 0x00000167, - 0x00000967, - 0x000002a6, - 0x00000567, - 0x000117ed, - 0x000006a6, - 0x000001a6, - 0x000005a6, - 0x00000d67, - 0x000012e8, - 0x00000ae8, - 0x00001de9, - 0x00001ae8, - 0x000007eb, - 0x000317ed, - 0x000067ec, - 0x000097ed, - 0x000297ed, - 0x00040fee, - 0x00020fee, - 0x00060fee, - 0x00010fee, - 0x00050fee, - 0x00030fee, - 0x00070fee, - 0x00008fee, - 0x00048fee, - 0x00028fee, - 0x00068fee, - 0x00018fee, - 0x00058fee, - 0x00038fee, - 0x00078fee, - 0x00004fee, - 0x00044fee, - 0x00024fee, - 0x00064fee, - 0x00014fee, - 0x00054fee, - 0x00034fee, - 0x00074fee, - 0x0000cfee, - 0x0004cfee, - 0x0002cfee, - 0x0006cfee, - 0x0001cfee, - 0x0005cfee, - 0x0003cfee, - 0x0007cfee, - 0x00002fee, - 0x00042fee, - 0x00022fee, - 0x00062fee, - 0x00012fee, - 0x00052fee, - 0x00032fee, - 0x00072fee, - 0x0000afee, - 0x0004afee, - 0x0002afee, - 0x0006afee, - 0x0001afee, - 0x0005afee, - 0x0003afee, - 0x0007afee, - 0x00006fee, - 0x00046fee, - 0x00026fee, - 0x00066fee, - 0x00016fee, - 0x00056fee, - 0x00036fee, - 0x00076fee, - 0x0000efee, - 0x0004efee, - 0x0002efee, - 0x0006efee, - 0x0001efee, - 0x0005efee, - 0x0003efee, - 0x0007efee, - 0x00001fee, - 0x00041fee, - 0x00021fee, - 0x00061fee, - 0x00011fee, - 0x00051fee, - 0x00031fee, - 0x00071fee, - 0x00009fee, - 0x00049fee, - 0x00029fee, - 0x00069fee, - 0x00019fee, - 0x00059fee, - 0x00039fee, - 0x00079fee, - 0x00005fee, - 0x00045fee, - 0x00025fee, - 0x00065fee, - 0x00015fee, - 0x00055fee, - 0x00035fee, - 0x00075fee, - 0x0000dfee, - 0x0004dfee, - 0x0002dfee, - 0x0006dfee, - 0x0001dfee, - 0x0005dfee, - 0x0003dfee, - 0x0007dfee, - 0x00003fee, - 0x00043fee, - 0x00023fee, - 0x00063fee, - 0x00013fee, - 0x00053fee, - 0x00033fee, - 0x00073fee, - 0x0000bfee, - 0x0004bfee, - 0x0002bfee, - 0x0006bfee, - 0x0001bfee, - 0x0005bfee, - 0x0003bfee, - 0x0007bfee, - 0x00007fee, - 0x00047fee, - 0x00027fee, - 0x00067fee, - 0x00017fee, - 0x000197ed, - 0x000397ed, - 0x000057ed, - 0x00057fee, - 0x000257ed, - 0x00037fee, - 0x000157ed, - 0x00077fee, - 0x000357ed, - 0x0000ffee, - 0x0004ffee, - 0x0002ffee, - 0x0006ffee, - 0x0001ffee, - 0x00000084, - 0x00000003, - 0x00000184, - 0x00000044, - 0x00000144, - 0x000000c5, - 0x000002c5, - 0x000001c5, - 0x000003c6, - 0x000007c6, - 0x00000026, - 0x00000426, - 0x000003a7, - 0x00000ba7, - 0x000007a7, - 0x00000fa7, - 0x00000227, - 0x00000627, - 0x00000a27, - 0x00000e27, - 0x00000068, - 0x00000868, - 0x00001068, - 0x00001868, - 0x00000369, - 0x00001369, - 0x00002369, - 0x00003369, - 0x000006ea, - 0x000026ea, - 0x000046ea, - 0x000066ea, - 0x000016eb, - 0x000036eb, - 0x000056eb, - 0x000076eb, - 0x000096eb, - 0x0000b6eb, - 0x0000d6eb, - 0x0000f6eb, - 0x00003dec, - 0x00007dec, - 0x0000bdec, - 0x0000fdec, - 0x00013dec, - 0x00017dec, - 0x0001bdec, - 0x0001fdec, - 0x00006bed, - 0x0000ebed, - 0x00016bed, - 0x0001ebed, - 0x00026bed, - 0x0002ebed, - 0x00036bed, - 0x0003ebed, - 0x000003ec, - 0x000043ec, - 0x000083ec, - 0x0000c3ec, - 0x000103ec, - 0x000143ec, - 0x000183ec, - 0x0001c3ec, - 0x00001bee, - 0x00009bee, - 0x00011bee, - 0x00019bee, - 0x00021bee, - 0x00029bee, - 0x00031bee, - 0x00039bee, - 0x00041bee, - 0x00049bee, - 0x00051bee, - 0x00059bee, - 0x00061bee, - 0x00069bee, - 0x00071bee, - 0x00079bee, - 0x000167f0, - 0x000367f0, - 0x000567f0, - 0x000767f0, - 0x000967f0, - 0x000b67f0, - 0x000d67f0, - 0x000f67f0, - 0x001167f0, - 0x001367f0, - 0x001567f0, - 0x001767f0, - 0x001967f0, - 0x001b67f0, - 0x001d67f0, - 0x001f67f0, - 0x000087ef, - 0x000187ef, - 0x000287ef, - 0x000387ef, - 0x000487ef, - 0x000587ef, - 0x000687ef, - 0x000787ef, - 0x000887ef, - 0x000987ef, - 0x000a87ef, - 0x000b87ef, - 0x000c87ef, - 0x000d87ef, - 0x000e87ef, - 0x000f87ef, - 0x0000e7f0, - 0x0002e7f0, - 0x0004e7f0, - 0x0006e7f0, - 0x0008e7f0, - 0x000ae7f0, - 0x000ce7f0, - 0x000ee7f0, - 0x0010e7f0, - 0x0012e7f0, - 0x0014e7f0, - 0x0016e7f0, - 0x0018e7f0, - 0x001ae7f0, - 0x001ce7f0, - 0x001ee7f0, - 0x0005fff3, - 0x000dfff3, - 0x0015fff3, - 0x001dfff3, - 0x0025fff3, - 0x002dfff3, - 0x0035fff3, - 0x003dfff3, - 0x0045fff3, - 0x004dfff3, - 0x0055fff3, - 0x005dfff3, - 0x0065fff3, - 0x006dfff3, - 0x0075fff3, - 0x007dfff3, - 0x0085fff3, - 0x008dfff3, - 0x0095fff3, - 0x009dfff3, - 0x00a5fff3, - 0x00adfff3, - 0x00b5fff3, - 0x00bdfff3, - 0x00c5fff3, - 0x00cdfff3, - 0x00d5fff3, - 0x00ddfff3, - 0x00e5fff3, - 0x00edfff3, - 0x00f5fff3, - 0x00fdfff3, - 0x0003fff3, - 0x000bfff3, - 0x0013fff3, - 0x001bfff3, - 0x0023fff3, - 0x002bfff3, - 0x0033fff3, - 0x003bfff3, - 0x0043fff3, - 0x004bfff3, - 0x0053fff3, - 0x005bfff3, - 0x0063fff3, - 0x006bfff3, - 0x0073fff3, - 0x007bfff3, - 0x0083fff3, - 0x008bfff3, - 0x0093fff3, - 0x009bfff3, - 0x00a3fff3, - 0x00abfff3, - 0x00b3fff3, - 0x00bbfff3, - 0x00c3fff3, - 0x00cbfff3, - 0x00d3fff3, - 0x00dbfff3, - 0x00e3fff3, - 0x00ebfff3, - 0x00f3fff3, - 0x00fbfff3, - 0x0007fff3, - 0x000ffff3, - 0x0017fff3, - 0x001ffff3, - 0x0027fff3, - 0x002ffff3, - 0x0037fff3, - 0x003ffff3, - 0x0047fff3, - 0x004ffff3, - 0x0057fff3, - 0x005ffff3, - 0x0067fff3, - 0x006ffff3, - 0x0077fff3, - 0x007ffff3, - 0x0087fff3, - 0x008ffff3, - 0x0097fff3, - 0x009ffff3, - 0x00a7fff3, - 0x00affff3, - 0x00b7fff3, - 0x00bffff3, - 0x00c7fff3, - 0x00cffff3, - 0x00d7fff3, - 0x00dffff3, - 0x00e7fff3, - 0x00effff3, - 0x00f7fff3, - 0x00fffff3, - 0x0001e7f1, - 0x0003e7f1, - 0x0005e7f1, - 0x0007e7f1, - 0x0009e7f1, - 0x000be7f1, - 0x000de7f1, - 0x000fe7f1, - 0x0011e7f1, - 0x0013e7f1, - 0x0015e7f1, - 0x0017e7f1, - 0x0019e7f1, - 0x001be7f1, - 0x001de7f1, - 0x001fe7f1, - 0x0021e7f1, - 0x0023e7f1, - 0x0025e7f1, - 0x0027e7f1, - 0x0029e7f1, - 0x002be7f1, - 0x002de7f1, - 0x002fe7f1, - 0x0031e7f1, - 0x0033e7f1, - 0x0035e7f1, - 0x0037e7f1, - 0x0039e7f1, - 0x003be7f1, - 0x003de7f1, - 0x000047eb - }; - - internal static readonly uint[] FAST_ENCODER_DISTANCE_CODE_INFO = - { - 0x00000f06, - 0x0001ff0a, - 0x0003ff0b, - 0x0007ff0b, - 0x0000ff19, - 0x00003f18, - 0x0000bf28, - 0x00007f28, - 0x00001f37, - 0x00005f37, - 0x00000d45, - 0x00002f46, - 0x00000054, - 0x00001d55, - 0x00000864, - 0x00000365, - 0x00000474, - 0x00001375, - 0x00000c84, - 0x00000284, - 0x00000a94, - 0x00000694, - 0x00000ea4, - 0x000001a4, - 0x000009b4, - 0x00000bb5, - 0x000005c4, - 0x00001bc5, - 0x000007d5, - 0x000017d5, - 0x00000000, - 0x00000100 - }; - - internal static readonly uint[] BIT_MASK = - { - 0, - 1, - 3, - 7, - 15, - 31, - 63, - 127, - 255, - 511, - 1023, - 2047, - 4095, - 8191, - 16383, - 32767 - }; - internal static readonly byte[] EXTRA_LENGTH_BITS = - { - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1, - 1, - 1, - 1, - 2, - 2, - 2, - 2, - 3, - 3, - 3, - 3, - 4, - 4, - 4, - 4, - 5, - 5, - 5, - 5, - 0 - }; - internal static readonly byte[] EXTRA_DISTANCE_BITS = - { - 0, - 0, - 0, - 0, - 1, - 1, - 2, - 2, - 3, - 3, - 4, - 4, - 5, - 5, - 6, - 6, - 7, - 7, - 8, - 8, - 9, - 9, - 10, - 10, - 11, - 11, - 12, - 12, - 13, - 13, - 0, - 0 - }; - internal const int NUM_CHARS = 256; - internal const int NUM_LENGTH_BASE_CODES = 29; - internal const int NUM_DIST_BASE_CODES = 30; - - internal const uint FAST_ENCODER_POST_TREE_BIT_BUF = 0x0022; - internal const int FAST_ENCODER_POST_TREE_BIT_COUNT = 9; - - internal const uint NO_COMPRESSION_HEADER = 0x0; - internal const int NO_COMPRESSION_HEADER_BIT_COUNT = 3; - internal const uint B_FINAL_NO_COMPRESSION_HEADER = 0x1; - internal const int B_FINAL_NO_COMPRESSION_HEADER_BIT_COUNT = 3; - internal const int MAX_CODE_LEN = 16; - - private static readonly byte[] S_DIST_LOOKUP = CreateDistanceLookup(); - - private static byte[] CreateDistanceLookup() - { - byte[] result = new byte[512]; - - // Generate the global slot tables which allow us to convert a distance - // (0..32K) to a distance slot (0..29) - // - // Distance table - // Extra Extra Extra - // Code Bits Dist Code Bits Dist Code Bits Distance - // ---- ---- ---- ---- ---- ------ ---- ---- -------- - // 0 0 1 10 4 33-48 20 9 1025-1536 - // 1 0 2 11 4 49-64 21 9 1537-2048 - // 2 0 3 12 5 65-96 22 10 2049-3072 - // 3 0 4 13 5 97-128 23 10 3073-4096 - // 4 1 5,6 14 6 129-192 24 11 4097-6144 - // 5 1 7,8 15 6 193-256 25 11 6145-8192 - // 6 2 9-12 16 7 257-384 26 12 8193-12288 - // 7 2 13-16 17 7 385-512 27 12 12289-16384 - // 8 3 17-24 18 8 513-768 28 13 16385-24576 - // 9 3 25-32 19 8 769-1024 29 13 24577-32768 - - // Initialize the mapping length (0..255) -> length code (0..28) - //int length = 0; - //for (code = 0; code < FastEncoderStatics.NumLengthBaseCodes-1; code++) { - // for (int n = 0; n < (1 << FastEncoderStatics.ExtraLengthBits[code]); n++) - // lengthLookup[length++] = (byte) code; - //} - //lengthLookup[length-1] = (byte) code; - - // Initialize the mapping dist (0..32K) -> dist code (0..29) - int dist = 0; - int code; - for (code = 0; code < 16; code++) - { - for (int n = 0; n < (1 << EXTRA_DISTANCE_BITS[code]); n++) - { - result[dist++] = (byte)code; - } + result[dist++] = (byte)code; } - - dist >>= 7; // from now on, all distances are divided by 128 - - for (; code < NUM_DIST_BASE_CODES; code++) - { - for (int n = 0; n < (1 << (EXTRA_DISTANCE_BITS[code] - 7)); n++) - { - result[256 + dist++] = (byte)code; - } - } - - return result; } - // Return the position slot (0...29) of a match offset (0...32767) - internal static int GetSlot(int pos) => - S_DIST_LOOKUP[((pos) < 256) ? (pos) : (256 + ((pos) >> 7))]; + dist >>= 7; // from now on, all distances are divided by 128 - // Reverse 'length' of the bits in code - public static uint BitReverse(uint code, int length) + for (; code < NUM_DIST_BASE_CODES; code++) { - uint newCode = 0; - - Debug.Assert(length > 0 && length <= 16, "Invalid len"); - do + for (var n = 0; n < (1 << (EXTRA_DISTANCE_BITS[code] - 7)); n++) { - newCode |= (code & 1); - newCode <<= 1; - code >>= 1; - } while (--length > 0); - - return newCode >> 1; + result[256 + dist++] = (byte)code; + } } + + return result; + } + + // Return the position slot (0...29) of a match offset (0...32767) + internal static int GetSlot(int pos) => + S_DIST_LOOKUP[((pos) < 256) ? (pos) : (256 + ((pos) >> 7))]; + + // Reverse 'length' of the bits in code + public static uint BitReverse(uint code, int length) + { + uint newCode = 0; + + Debug.Assert(length > 0 && length <= 16, "Invalid len"); + do + { + newCode |= (code & 1); + newCode <<= 1; + code >>= 1; + } while (--length > 0); + + return newCode >> 1; } } diff --git a/src/SharpCompress/Compressors/Deflate64/HuffmanTree.cs b/src/SharpCompress/Compressors/Deflate64/HuffmanTree.cs index eac0ff5f..051b613e 100644 --- a/src/SharpCompress/Compressors/Deflate64/HuffmanTree.cs +++ b/src/SharpCompress/Compressors/Deflate64/HuffmanTree.cs @@ -6,326 +6,325 @@ using System; using System.Diagnostics; using System.IO; -namespace SharpCompress.Compressors.Deflate64 +namespace SharpCompress.Compressors.Deflate64; + +// Strictly speaking this class is not a HuffmanTree, this class is +// a lookup table combined with a HuffmanTree. The idea is to speed up +// the lookup for short symbols (they should appear more frequently ideally.) +// However we don't want to create a huge table since it might take longer to +// build the table than decoding (Deflate usually generates new tables frequently.) +// +// Jean-loup Gailly and Mark Adler gave a very good explanation about this. +// The full text (algorithm.txt) can be found inside +// ftp://ftp.uu.net/pub/archiving/zip/zlib/zlib.zip. +// +// Following paper explains decoding in details: +// Hirschberg and Lelewer, "Efficient decoding of prefix codes," +// Comm. ACM, 33,4, April 1990, pp. 449-459. +// + +internal sealed class HuffmanTree { - // Strictly speaking this class is not a HuffmanTree, this class is - // a lookup table combined with a HuffmanTree. The idea is to speed up - // the lookup for short symbols (they should appear more frequently ideally.) - // However we don't want to create a huge table since it might take longer to - // build the table than decoding (Deflate usually generates new tables frequently.) - // - // Jean-loup Gailly and Mark Adler gave a very good explanation about this. - // The full text (algorithm.txt) can be found inside - // ftp://ftp.uu.net/pub/archiving/zip/zlib/zlib.zip. - // - // Following paper explains decoding in details: - // Hirschberg and Lelewer, "Efficient decoding of prefix codes," - // Comm. ACM, 33,4, April 1990, pp. 449-459. - // + internal const int MAX_LITERAL_TREE_ELEMENTS = 288; + internal const int MAX_DIST_TREE_ELEMENTS = 32; + internal const int END_OF_BLOCK_CODE = 256; + internal const int NUMBER_OF_CODE_LENGTH_TREE_ELEMENTS = 19; - internal sealed class HuffmanTree + private readonly int _tableBits; + private readonly short[] _table; + private readonly short[] _left; + private readonly short[] _right; + private readonly byte[] _codeLengthArray; +#if DEBUG + private uint[]? _codeArrayDebug; +#endif + + private readonly int _tableMask; + + // huffman tree for static block + public static HuffmanTree StaticLiteralLengthTree { get; } = + new HuffmanTree(GetStaticLiteralTreeLength()); + + public static HuffmanTree StaticDistanceTree { get; } = + new HuffmanTree(GetStaticDistanceTreeLength()); + + public HuffmanTree(byte[] codeLengths) { - internal const int MAX_LITERAL_TREE_ELEMENTS = 288; - internal const int MAX_DIST_TREE_ELEMENTS = 32; - internal const int END_OF_BLOCK_CODE = 256; - internal const int NUMBER_OF_CODE_LENGTH_TREE_ELEMENTS = 19; + Debug.Assert( + codeLengths.Length == MAX_LITERAL_TREE_ELEMENTS + || codeLengths.Length == MAX_DIST_TREE_ELEMENTS + || codeLengths.Length == NUMBER_OF_CODE_LENGTH_TREE_ELEMENTS, + "we only expect three kinds of Length here" + ); + _codeLengthArray = codeLengths; - private readonly int _tableBits; - private readonly short[] _table; - private readonly short[] _left; - private readonly short[] _right; - private readonly byte[] _codeLengthArray; + if (_codeLengthArray.Length == MAX_LITERAL_TREE_ELEMENTS) + { + // bits for Literal/Length tree table + _tableBits = 9; + } + else + { + // bits for distance tree table and code length tree table + _tableBits = 7; + } + _tableMask = (1 << _tableBits) - 1; + + _table = new short[1 << _tableBits]; + + // I need to find proof that left and right array will always be + // enough. I think they are. + _left = new short[2 * _codeLengthArray.Length]; + _right = new short[2 * _codeLengthArray.Length]; + + CreateTable(); + } + + // Generate the array contains huffman codes lengths for static huffman tree. + // The data is in RFC 1951. + private static byte[] GetStaticLiteralTreeLength() + { + var literalTreeLength = new byte[MAX_LITERAL_TREE_ELEMENTS]; + for (var i = 0; i <= 143; i++) + { + literalTreeLength[i] = 8; + } + + for (var i = 144; i <= 255; i++) + { + literalTreeLength[i] = 9; + } + + for (var i = 256; i <= 279; i++) + { + literalTreeLength[i] = 7; + } + + for (var i = 280; i <= 287; i++) + { + literalTreeLength[i] = 8; + } + + return literalTreeLength; + } + + private static byte[] GetStaticDistanceTreeLength() + { + var staticDistanceTreeLength = new byte[MAX_DIST_TREE_ELEMENTS]; + for (var i = 0; i < MAX_DIST_TREE_ELEMENTS; i++) + { + staticDistanceTreeLength[i] = 5; + } + return staticDistanceTreeLength; + } + + // Calculate the huffman code for each character based on the code length for each character. + // This algorithm is described in standard RFC 1951 + private uint[] CalculateHuffmanCode() + { + Span bitLengthCount = stackalloc uint[17]; + foreach (int codeLength in _codeLengthArray) + { + bitLengthCount[codeLength]++; + } + bitLengthCount[0] = 0; // clear count for length 0 + + Span nextCode = stackalloc uint[17]; + uint tempCode = 0; + for (var bits = 1; bits <= 16; bits++) + { + tempCode = (tempCode + bitLengthCount[bits - 1]) << 1; + nextCode[bits] = tempCode; + } + + var code = new uint[MAX_LITERAL_TREE_ELEMENTS]; + for (var i = 0; i < _codeLengthArray.Length; i++) + { + int len = _codeLengthArray[i]; + + if (len > 0) + { + code[i] = FastEncoderStatics.BitReverse(nextCode[len], len); + nextCode[len]++; + } + } + return code; + } + + private void CreateTable() + { + var codeArray = CalculateHuffmanCode(); #if DEBUG - private uint[]? _codeArrayDebug; + _codeArrayDebug = codeArray; #endif - private readonly int _tableMask; + var avail = (short)_codeLengthArray.Length; - // huffman tree for static block - public static HuffmanTree StaticLiteralLengthTree { get; } = - new HuffmanTree(GetStaticLiteralTreeLength()); - - public static HuffmanTree StaticDistanceTree { get; } = - new HuffmanTree(GetStaticDistanceTreeLength()); - - public HuffmanTree(byte[] codeLengths) + for (var ch = 0; ch < _codeLengthArray.Length; ch++) { - Debug.Assert( - codeLengths.Length == MAX_LITERAL_TREE_ELEMENTS - || codeLengths.Length == MAX_DIST_TREE_ELEMENTS - || codeLengths.Length == NUMBER_OF_CODE_LENGTH_TREE_ELEMENTS, - "we only expect three kinds of Length here" - ); - _codeLengthArray = codeLengths; - - if (_codeLengthArray.Length == MAX_LITERAL_TREE_ELEMENTS) + // length of this code + int len = _codeLengthArray[ch]; + if (len > 0) { - // bits for Literal/Length tree table - _tableBits = 9; - } - else - { - // bits for distance tree table and code length tree table - _tableBits = 7; - } - _tableMask = (1 << _tableBits) - 1; + // start value (bit reversed) + var start = (int)codeArray[ch]; - _table = new short[1 << _tableBits]; - - // I need to find proof that left and right array will always be - // enough. I think they are. - _left = new short[2 * _codeLengthArray.Length]; - _right = new short[2 * _codeLengthArray.Length]; - - CreateTable(); - } - - // Generate the array contains huffman codes lengths for static huffman tree. - // The data is in RFC 1951. - private static byte[] GetStaticLiteralTreeLength() - { - byte[] literalTreeLength = new byte[MAX_LITERAL_TREE_ELEMENTS]; - for (int i = 0; i <= 143; i++) - { - literalTreeLength[i] = 8; - } - - for (int i = 144; i <= 255; i++) - { - literalTreeLength[i] = 9; - } - - for (int i = 256; i <= 279; i++) - { - literalTreeLength[i] = 7; - } - - for (int i = 280; i <= 287; i++) - { - literalTreeLength[i] = 8; - } - - return literalTreeLength; - } - - private static byte[] GetStaticDistanceTreeLength() - { - byte[] staticDistanceTreeLength = new byte[MAX_DIST_TREE_ELEMENTS]; - for (int i = 0; i < MAX_DIST_TREE_ELEMENTS; i++) - { - staticDistanceTreeLength[i] = 5; - } - return staticDistanceTreeLength; - } - - // Calculate the huffman code for each character based on the code length for each character. - // This algorithm is described in standard RFC 1951 - private uint[] CalculateHuffmanCode() - { - Span bitLengthCount = stackalloc uint[17]; - foreach (int codeLength in _codeLengthArray) - { - bitLengthCount[codeLength]++; - } - bitLengthCount[0] = 0; // clear count for length 0 - - Span nextCode = stackalloc uint[17]; - uint tempCode = 0; - for (int bits = 1; bits <= 16; bits++) - { - tempCode = (tempCode + bitLengthCount[bits - 1]) << 1; - nextCode[bits] = tempCode; - } - - uint[] code = new uint[MAX_LITERAL_TREE_ELEMENTS]; - for (int i = 0; i < _codeLengthArray.Length; i++) - { - int len = _codeLengthArray[i]; - - if (len > 0) + if (len <= _tableBits) { - code[i] = FastEncoderStatics.BitReverse(nextCode[len], len); - nextCode[len]++; - } - } - return code; - } - - private void CreateTable() - { - uint[] codeArray = CalculateHuffmanCode(); -#if DEBUG - _codeArrayDebug = codeArray; -#endif - - short avail = (short)_codeLengthArray.Length; - - for (int ch = 0; ch < _codeLengthArray.Length; ch++) - { - // length of this code - int len = _codeLengthArray[ch]; - if (len > 0) - { - // start value (bit reversed) - int start = (int)codeArray[ch]; - - if (len <= _tableBits) + // If a particular symbol is shorter than nine bits, + // then that symbol's translation is duplicated + // in all those entries that start with that symbol's bits. + // For example, if the symbol is four bits, then it's duplicated + // 32 times in a nine-bit table. If a symbol is nine bits long, + // it appears in the table once. + // + // Make sure that in the loop below, code is always + // less than table_size. + // + // On last iteration we store at array index: + // initial_start_at + (locs-1)*increment + // = initial_start_at + locs*increment - increment + // = initial_start_at + (1 << tableBits) - increment + // = initial_start_at + table_size - increment + // + // Therefore we must ensure: + // initial_start_at + table_size - increment < table_size + // or: initial_start_at < increment + // + var increment = 1 << len; + if (start >= increment) { - // If a particular symbol is shorter than nine bits, - // then that symbol's translation is duplicated - // in all those entries that start with that symbol's bits. - // For example, if the symbol is four bits, then it's duplicated - // 32 times in a nine-bit table. If a symbol is nine bits long, - // it appears in the table once. - // - // Make sure that in the loop below, code is always - // less than table_size. - // - // On last iteration we store at array index: - // initial_start_at + (locs-1)*increment - // = initial_start_at + locs*increment - increment - // = initial_start_at + (1 << tableBits) - increment - // = initial_start_at + table_size - increment - // - // Therefore we must ensure: - // initial_start_at + table_size - increment < table_size - // or: initial_start_at < increment - // - int increment = 1 << len; - if (start >= increment) + throw new InvalidDataException("Deflate64: invalid Huffman data"); + } + + // Note the bits in the table are reverted. + var locs = 1 << (_tableBits - len); + for (var j = 0; j < locs; j++) + { + _table[start] = (short)ch; + start += increment; + } + } + else + { + // For any code which has length longer than num_elements, + // build a binary tree. + + var overflowBits = len - _tableBits; // the nodes we need to respent the data. + var codeBitMask = 1 << _tableBits; // mask to get current bit (the bits can't fit in the table) + + // the left, right table is used to repesent the + // the rest bits. When we got the first part (number bits.) and look at + // tbe table, we will need to follow the tree to find the real character. + // This is in place to avoid bloating the table if there are + // a few ones with long code. + var index = start & ((1 << _tableBits) - 1); + var array = _table; + + do + { + var value = array[index]; + + if (value == 0) { + // set up next pointer if this node is not used before. + array[index] = (short)-avail; // use next available slot. + value = (short)-avail; + avail++; + } + + if (value > 0) + { + // prevent an IndexOutOfRangeException from array[index] throw new InvalidDataException("Deflate64: invalid Huffman data"); } - // Note the bits in the table are reverted. - int locs = 1 << (_tableBits - len); - for (int j = 0; j < locs; j++) + Debug.Assert( + value < 0, + "CreateTable: Only negative numbers are used for tree pointers!" + ); + + if ((start & codeBitMask) == 0) { - _table[start] = (short)ch; - start += increment; + // if current bit is 0, go change the left array + array = _left; } - } - else - { - // For any code which has length longer than num_elements, - // build a binary tree. - - int overflowBits = len - _tableBits; // the nodes we need to respent the data. - int codeBitMask = 1 << _tableBits; // mask to get current bit (the bits can't fit in the table) - - // the left, right table is used to repesent the - // the rest bits. When we got the first part (number bits.) and look at - // tbe table, we will need to follow the tree to find the real character. - // This is in place to avoid bloating the table if there are - // a few ones with long code. - int index = start & ((1 << _tableBits) - 1); - short[] array = _table; - - do + else { - short value = array[index]; + // if current bit is 1, set value in the right array + array = _right; + } + index = -value; // go to next node - if (value == 0) - { - // set up next pointer if this node is not used before. - array[index] = (short)-avail; // use next available slot. - value = (short)-avail; - avail++; - } + codeBitMask <<= 1; + overflowBits--; + } while (overflowBits != 0); - if (value > 0) - { - // prevent an IndexOutOfRangeException from array[index] - throw new InvalidDataException("Deflate64: invalid Huffman data"); - } - - Debug.Assert( - value < 0, - "CreateTable: Only negative numbers are used for tree pointers!" - ); - - if ((start & codeBitMask) == 0) - { - // if current bit is 0, go change the left array - array = _left; - } - else - { - // if current bit is 1, set value in the right array - array = _right; - } - index = -value; // go to next node - - codeBitMask <<= 1; - overflowBits--; - } while (overflowBits != 0); - - array[index] = (short)ch; - } + array[index] = (short)ch; } } } + } - // - // This function will try to get enough bits from input and - // try to decode the bits. - // If there are no enought bits in the input, this function will return -1. - // - public int GetNextSymbol(InputBuffer input) - { - // Try to load 16 bits into input buffer if possible and get the bitBuffer value. - // If there aren't 16 bits available we will return all we have in the - // input buffer. - uint bitBuffer = input.TryLoad16Bits(); - if (input.AvailableBits == 0) - { // running out of input. - return -1; - } - - // decode an element - int symbol = _table[bitBuffer & _tableMask]; - if (symbol < 0) - { // this will be the start of the binary tree - // navigate the tree - uint mask = (uint)1 << _tableBits; - do - { - symbol = -symbol; - if ((bitBuffer & mask) == 0) - { - symbol = _left[symbol]; - } - else - { - symbol = _right[symbol]; - } - - mask <<= 1; - } while (symbol < 0); - } - - int codeLength = _codeLengthArray[symbol]; - - // huffman code lengths must be at least 1 bit long - if (codeLength <= 0) - { - throw new InvalidDataException("Deflate64: invalid Huffman data"); - } - - // - // If this code is longer than the # bits we had in the bit buffer (i.e. - // we read only part of the code), we can hit the entry in the table or the tree - // for another symbol. However the length of another symbol will not match the - // available bits count. - if (codeLength > input.AvailableBits) - { - // We already tried to load 16 bits and maximum length is 15, - // so this means we are running out of input. - return -1; - } - - input.SkipBits(codeLength); - return symbol; + // + // This function will try to get enough bits from input and + // try to decode the bits. + // If there are no enought bits in the input, this function will return -1. + // + public int GetNextSymbol(InputBuffer input) + { + // Try to load 16 bits into input buffer if possible and get the bitBuffer value. + // If there aren't 16 bits available we will return all we have in the + // input buffer. + var bitBuffer = input.TryLoad16Bits(); + if (input.AvailableBits == 0) + { // running out of input. + return -1; } + + // decode an element + int symbol = _table[bitBuffer & _tableMask]; + if (symbol < 0) + { // this will be the start of the binary tree + // navigate the tree + var mask = (uint)1 << _tableBits; + do + { + symbol = -symbol; + if ((bitBuffer & mask) == 0) + { + symbol = _left[symbol]; + } + else + { + symbol = _right[symbol]; + } + + mask <<= 1; + } while (symbol < 0); + } + + int codeLength = _codeLengthArray[symbol]; + + // huffman code lengths must be at least 1 bit long + if (codeLength <= 0) + { + throw new InvalidDataException("Deflate64: invalid Huffman data"); + } + + // + // If this code is longer than the # bits we had in the bit buffer (i.e. + // we read only part of the code), we can hit the entry in the table or the tree + // for another symbol. However the length of another symbol will not match the + // available bits count. + if (codeLength > input.AvailableBits) + { + // We already tried to load 16 bits and maximum length is 15, + // so this means we are running out of input. + return -1; + } + + input.SkipBits(codeLength); + return symbol; } } diff --git a/src/SharpCompress/Compressors/Deflate64/InflaterManaged.cs b/src/SharpCompress/Compressors/Deflate64/InflaterManaged.cs index 3864ff44..a4890899 100644 --- a/src/SharpCompress/Compressors/Deflate64/InflaterManaged.cs +++ b/src/SharpCompress/Compressors/Deflate64/InflaterManaged.cs @@ -32,818 +32,621 @@ using System; using System.Diagnostics; using System.IO; -namespace SharpCompress.Compressors.Deflate64 +namespace SharpCompress.Compressors.Deflate64; + +internal sealed class InflaterManaged { - internal sealed class InflaterManaged - { - // const tables used in decoding: + // const tables used in decoding: - // Extra bits for length code 257 - 285. - private static ReadOnlySpan S_EXTRA_LENGTH_BITS => - new byte[] - { - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1, - 1, - 1, - 1, - 2, - 2, - 2, - 2, - 3, - 3, - 3, - 3, - 4, - 4, - 4, - 4, - 5, - 5, - 5, - 5, - 16 - }; - - // The base length for length code 257 - 285. - // The formula to get the real length for a length code is lengthBase[code - 257] + (value stored in extraBits) - private static readonly int[] S_LENGTH_BASE = - { - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 13, - 15, - 17, - 19, - 23, - 27, - 31, - 35, - 43, - 51, - 59, - 67, - 83, - 99, - 115, - 131, - 163, - 195, - 227, - 3 - }; - - // The base distance for distance code 0 - 31 - // The real distance for a distance code is distanceBasePosition[code] + (value stored in extraBits) - private static readonly int[] S_DISTANCE_BASE_POSITION = + // Extra bits for length code 257 - 285. + private static ReadOnlySpan S_EXTRA_LENGTH_BITS => + new byte[] { + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, 1, 2, + 2, + 2, + 2, + 3, + 3, + 3, 3, 4, + 4, + 4, + 4, 5, - 7, - 9, - 13, - 17, - 25, - 33, - 49, - 65, - 97, - 129, - 193, - 257, - 385, - 513, - 769, - 1025, - 1537, - 2049, - 3073, - 4097, - 6145, - 8193, - 12289, - 16385, - 24577, - 32769, - 49153 + 5, + 5, + 5, + 16 }; - // code lengths for code length alphabet is stored in following order - private static ReadOnlySpan S_CODE_ORDER => - new byte[] { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; + // The base length for length code 257 - 285. + // The formula to get the real length for a length code is lengthBase[code - 257] + (value stored in extraBits) + private static readonly int[] S_LENGTH_BASE = + { + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 13, + 15, + 17, + 19, + 23, + 27, + 31, + 35, + 43, + 51, + 59, + 67, + 83, + 99, + 115, + 131, + 163, + 195, + 227, + 3 + }; - private static ReadOnlySpan S_STATIC_DISTANCE_TREE_TABLE => - new byte[] + // The base distance for distance code 0 - 31 + // The real distance for a distance code is distanceBasePosition[code] + (value stored in extraBits) + private static readonly int[] S_DISTANCE_BASE_POSITION = + { + 1, + 2, + 3, + 4, + 5, + 7, + 9, + 13, + 17, + 25, + 33, + 49, + 65, + 97, + 129, + 193, + 257, + 385, + 513, + 769, + 1025, + 1537, + 2049, + 3073, + 4097, + 6145, + 8193, + 12289, + 16385, + 24577, + 32769, + 49153 + }; + + // code lengths for code length alphabet is stored in following order + private static ReadOnlySpan S_CODE_ORDER => + new byte[] { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; + + private static ReadOnlySpan S_STATIC_DISTANCE_TREE_TABLE => + new byte[] + { + 0x00, + 0x10, + 0x08, + 0x18, + 0x04, + 0x14, + 0x0c, + 0x1c, + 0x02, + 0x12, + 0x0a, + 0x1a, + 0x06, + 0x16, + 0x0e, + 0x1e, + 0x01, + 0x11, + 0x09, + 0x19, + 0x05, + 0x15, + 0x0d, + 0x1d, + 0x03, + 0x13, + 0x0b, + 0x1b, + 0x07, + 0x17, + 0x0f, + 0x1f + }; + + private readonly OutputWindow _output; + private readonly InputBuffer _input; + private HuffmanTree _literalLengthTree; + private HuffmanTree _distanceTree; + + private InflaterState _state; + + //private bool _hasFormatReader; + private int _bfinal; + private BlockType _blockType; + + // uncompressed block + private readonly byte[] _blockLengthBuffer = new byte[4]; + private int _blockLength; + + // compressed block + private int _length; + private int _distanceCode; + private int _extraBits; + + private int _loopCounter; + private int _literalLengthCodeCount; + private int _distanceCodeCount; + private int _codeLengthCodeCount; + private int _codeArraySize; + private int _lengthCode; + + private readonly byte[] _codeList; // temporary array to store the code length for literal/Length and distance + private readonly byte[] _codeLengthTreeCodeLength; + private readonly bool _deflate64; + private HuffmanTree _codeLengthTree; + + //private IFileFormatReader _formatReader; // class to decode header and footer (e.g. gzip) + + internal InflaterManaged( /*IFileFormatReader reader, */ + bool deflate64 + ) + { + _output = new OutputWindow(); + _input = new InputBuffer(); + + _codeList = new byte[ + HuffmanTree.MAX_LITERAL_TREE_ELEMENTS + HuffmanTree.MAX_DIST_TREE_ELEMENTS + ]; + _codeLengthTreeCodeLength = new byte[HuffmanTree.NUMBER_OF_CODE_LENGTH_TREE_ELEMENTS]; + _deflate64 = deflate64; + //if (reader != null) + //{ + // _formatReader = reader; + // _hasFormatReader = true; + //} + Reset(); + } + + private void Reset() + { + _state = //_hasFormatReader ? + //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 + + public bool Finished() => + _state == InflaterState.Done || _state == InflaterState.VerifyingFooter; + + public int AvailableOutput => _output.AvailableBytes; + + public int Inflate(byte[] bytes, int offset, int length) + { + // copy bytes from output to outputbytes if we have available bytes + // if buffer is not filled up. keep decoding until no input are available + // if decodeBlock returns false. Throw an exception. + var count = 0; + do + { + var copied = _output.CopyTo(bytes, offset, length); + if (copied > 0) { - 0x00, - 0x10, - 0x08, - 0x18, - 0x04, - 0x14, - 0x0c, - 0x1c, - 0x02, - 0x12, - 0x0a, - 0x1a, - 0x06, - 0x16, - 0x0e, - 0x1e, - 0x01, - 0x11, - 0x09, - 0x19, - 0x05, - 0x15, - 0x0d, - 0x1d, - 0x03, - 0x13, - 0x0b, - 0x1b, - 0x07, - 0x17, - 0x0f, - 0x1f - }; + //if (_hasFormatReader) + //{ + // _formatReader.UpdateWithBytesRead(bytes, offset, copied); + //} - private readonly OutputWindow _output; - private readonly InputBuffer _input; - private HuffmanTree _literalLengthTree; - private HuffmanTree _distanceTree; - - private InflaterState _state; - - //private bool _hasFormatReader; - private int _bfinal; - private BlockType _blockType; - - // uncompressed block - private readonly byte[] _blockLengthBuffer = new byte[4]; - private int _blockLength; - - // compressed block - private int _length; - private int _distanceCode; - private int _extraBits; - - private int _loopCounter; - private int _literalLengthCodeCount; - private int _distanceCodeCount; - private int _codeLengthCodeCount; - private int _codeArraySize; - private int _lengthCode; - - private readonly byte[] _codeList; // temporary array to store the code length for literal/Length and distance - private readonly byte[] _codeLengthTreeCodeLength; - private readonly bool _deflate64; - private HuffmanTree _codeLengthTree; - - //private IFileFormatReader _formatReader; // class to decode header and footer (e.g. gzip) - - internal InflaterManaged( /*IFileFormatReader reader, */ - bool deflate64 - ) - { - _output = new OutputWindow(); - _input = new InputBuffer(); - - _codeList = new byte[ - HuffmanTree.MAX_LITERAL_TREE_ELEMENTS + HuffmanTree.MAX_DIST_TREE_ELEMENTS - ]; - _codeLengthTreeCodeLength = new byte[HuffmanTree.NUMBER_OF_CODE_LENGTH_TREE_ELEMENTS]; - _deflate64 = deflate64; - //if (reader != null) - //{ - // _formatReader = reader; - // _hasFormatReader = true; - //} - Reset(); - } - - private void Reset() - { - _state = //_hasFormatReader ? - //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 - - public bool Finished() => - _state == InflaterState.Done || _state == InflaterState.VerifyingFooter; - - public int AvailableOutput => _output.AvailableBytes; - - public int Inflate(byte[] bytes, int offset, int length) - { - // copy bytes from output to outputbytes if we have available bytes - // if buffer is not filled up. keep decoding until no input are available - // if decodeBlock returns false. Throw an exception. - int count = 0; - do - { - int copied = _output.CopyTo(bytes, offset, length); - if (copied > 0) - { - //if (_hasFormatReader) - //{ - // _formatReader.UpdateWithBytesRead(bytes, offset, copied); - //} - - offset += copied; - count += copied; - length -= copied; - } - - if (length == 0) - { // filled in the bytes array - break; - } - // Decode will return false when more input is needed - } while (!Finished() && Decode()); - - if (_state == InflaterState.VerifyingFooter) - { // finished reading CRC - // In this case finished is true and output window has all the data. - // But some data in output window might not be copied out. - if (_output.AvailableBytes == 0) - { - //_formatReader.Validate(); - } + offset += copied; + count += copied; + length -= copied; } - return count; + if (length == 0) + { // filled in the bytes array + break; + } + // Decode will return false when more input is needed + } while (!Finished() && Decode()); + + if (_state == InflaterState.VerifyingFooter) + { // finished reading CRC + // In this case finished is true and output window has all the data. + // But some data in output window might not be copied out. + if (_output.AvailableBytes == 0) + { + //_formatReader.Validate(); + } } - //Each block of compressed data begins with 3 header bits - // containing the following data: - // first bit BFINAL - // next 2 bits BTYPE - // Note that the header bits do not necessarily begin on a byte - // boundary, since a block does not necessarily occupy an integral - // number of bytes. - // BFINAL is set if and only if this is the last block of the data - // set. - // BTYPE specifies how the data are compressed, as follows: - // 00 - no compression - // 01 - compressed with fixed Huffman codes - // 10 - compressed with dynamic Huffman codes - // 11 - reserved (error) - // The only difference between the two compressed cases is how the - // Huffman codes for the literal/length and distance alphabets are - // defined. - // - // This function returns true for success (end of block or output window is full,) - // false if we are short of input - // - private bool Decode() - { - bool eob = false; - bool result = false; + return count; + } - if (Finished()) + //Each block of compressed data begins with 3 header bits + // containing the following data: + // first bit BFINAL + // next 2 bits BTYPE + // Note that the header bits do not necessarily begin on a byte + // boundary, since a block does not necessarily occupy an integral + // number of bytes. + // BFINAL is set if and only if this is the last block of the data + // set. + // BTYPE specifies how the data are compressed, as follows: + // 00 - no compression + // 01 - compressed with fixed Huffman codes + // 10 - compressed with dynamic Huffman codes + // 11 - reserved (error) + // The only difference between the two compressed cases is how the + // Huffman codes for the literal/length and distance alphabets are + // defined. + // + // This function returns true for success (end of block or output window is full,) + // false if we are short of input + // + private bool Decode() + { + var eob = false; + var result = false; + + if (Finished()) + { + return true; + } + + //if (_hasFormatReader) + //{ + // if (_state == InflaterState.ReadingHeader) + // { + // if (!_formatReader.ReadHeader(_input)) + // { + // return false; + // } + // _state = InflaterState.ReadingBFinal; + // } + // else if (_state == InflaterState.StartReadingFooter || _state == InflaterState.ReadingFooter) + // { + // if (!_formatReader.ReadFooter(_input)) + // return false; + + // _state = InflaterState.VerifyingFooter; + // return true; + // } + //} + + if (_state == InflaterState.ReadingBFinal) + { + // reading bfinal bit + // Need 1 bit + if (!_input.EnsureBitsAvailable(1)) { - return true; + return false; } - //if (_hasFormatReader) - //{ - // if (_state == InflaterState.ReadingHeader) - // { - // if (!_formatReader.ReadHeader(_input)) - // { - // return false; - // } - // _state = InflaterState.ReadingBFinal; - // } - // else if (_state == InflaterState.StartReadingFooter || _state == InflaterState.ReadingFooter) - // { - // if (!_formatReader.ReadFooter(_input)) - // return false; + _bfinal = _input.GetBits(1); + _state = InflaterState.ReadingBType; + } - // _state = InflaterState.VerifyingFooter; - // return true; - // } - //} - - if (_state == InflaterState.ReadingBFinal) + if (_state == InflaterState.ReadingBType) + { + // Need 2 bits + if (!_input.EnsureBitsAvailable(2)) { - // reading bfinal bit - // Need 1 bit - if (!_input.EnsureBitsAvailable(1)) - { - return false; - } - - _bfinal = _input.GetBits(1); _state = InflaterState.ReadingBType; + return false; } - if (_state == InflaterState.ReadingBType) - { - // Need 2 bits - if (!_input.EnsureBitsAvailable(2)) - { - _state = InflaterState.ReadingBType; - return false; - } - - _blockType = (BlockType)_input.GetBits(2); - if (_blockType == BlockType.Dynamic) - { - _state = InflaterState.ReadingNumLitCodes; - } - else if (_blockType == BlockType.Static) - { - _literalLengthTree = HuffmanTree.StaticLiteralLengthTree; - _distanceTree = HuffmanTree.StaticDistanceTree; - _state = InflaterState.DecodeTop; - } - else if (_blockType == BlockType.Uncompressed) - { - _state = InflaterState.UncompressedAligning; - } - else - { - throw new InvalidDataException("Deflate64: unknown block type"); - } - } - + _blockType = (BlockType)_input.GetBits(2); if (_blockType == BlockType.Dynamic) { - if (_state < InflaterState.DecodeTop) - { - // we are reading the header - result = DecodeDynamicBlockHeader(); - } - else - { - result = DecodeBlock(out eob); // this can returns true when output is full - } + _state = InflaterState.ReadingNumLitCodes; } else if (_blockType == BlockType.Static) { - result = DecodeBlock(out eob); + _literalLengthTree = HuffmanTree.StaticLiteralLengthTree; + _distanceTree = HuffmanTree.StaticDistanceTree; + _state = InflaterState.DecodeTop; } else if (_blockType == BlockType.Uncompressed) { - result = DecodeUncompressedBlock(out eob); + _state = InflaterState.UncompressedAligning; } else { throw new InvalidDataException("Deflate64: unknown block type"); } - - // - // If we reached the end of the block and the block we were decoding had - // bfinal=1 (final block) - // - if (eob && (_bfinal != 0)) - { - //if (_hasFormatReader) - // _state = InflaterState.StartReadingFooter; - //else - _state = InflaterState.Done; - } - return result; } - // Format of Non-compressed blocks (BTYPE=00): - // - // Any bits of input up to the next byte boundary are ignored. - // The rest of the block consists of the following information: - // - // 0 1 2 3 4... - // +---+---+---+---+================================+ - // | LEN | NLEN |... LEN bytes of literal data...| - // +---+---+---+---+================================+ - // - // LEN is the number of data bytes in the block. NLEN is the - // one's complement of LEN. - private bool DecodeUncompressedBlock(out bool endOfBlock) + if (_blockType == BlockType.Dynamic) { - endOfBlock = false; - while (true) + if (_state < InflaterState.DecodeTop) { - switch (_state) - { - case InflaterState.UncompressedAligning: // initial state when calling this function - // we must skip to a byte boundary - _input.SkipToByteBoundary(); - _state = InflaterState.UncompressedByte1; - goto case InflaterState.UncompressedByte1; - - case InflaterState.UncompressedByte1: // decoding block length - case InflaterState.UncompressedByte2: - case InflaterState.UncompressedByte3: - case InflaterState.UncompressedByte4: - int bits = _input.GetBits(8); - if (bits < 0) - { - return false; - } - - _blockLengthBuffer[_state - InflaterState.UncompressedByte1] = (byte)bits; - if (_state == InflaterState.UncompressedByte4) - { - _blockLength = - _blockLengthBuffer[0] + ((int)_blockLengthBuffer[1]) * 256; - int blockLengthComplement = - _blockLengthBuffer[2] + ((int)_blockLengthBuffer[3]) * 256; - - // make sure complement matches - if ((ushort)_blockLength != (ushort)(~blockLengthComplement)) - { - throw new InvalidDataException("Deflate64: invalid block length"); - } - } - - _state += 1; - break; - - case InflaterState.DecodingUncompressed: // copying block data - - // Directly copy bytes from input to output. - int bytesCopied = _output.CopyFrom(_input, _blockLength); - _blockLength -= bytesCopied; - - if (_blockLength == 0) - { - // Done with this block, need to re-init bit buffer for next block - _state = InflaterState.ReadingBFinal; - endOfBlock = true; - return true; - } - - // We can fail to copy all bytes for two reasons: - // Running out of Input - // running out of free space in output window - if (_output.FreeBytes == 0) - { - return true; - } - - return false; - - default: - Debug. /*Fail*/ - Assert(false, "check why we are here!"); - throw new InvalidDataException("Deflate64: unknown state"); - } + // we are reading the header + result = DecodeDynamicBlockHeader(); + } + else + { + result = DecodeBlock(out eob); // this can returns true when output is full } } - - private bool DecodeBlock(out bool endOfBlockCodeSeen) + else if (_blockType == BlockType.Static) { - endOfBlockCodeSeen = false; - - int freeBytes = _output.FreeBytes; // it is a little bit faster than frequently accessing the property - while (freeBytes > 65536) - { - // With Deflate64 we can have up to a 64kb length, so we ensure at least that much space is available - // in the OutputWindow to avoid overwriting previous unflushed output data. - - int symbol; - switch (_state) - { - case InflaterState.DecodeTop: - // decode an element from the literal tree - - // TODO: optimize this!!! - symbol = _literalLengthTree.GetNextSymbol(_input); - if (symbol < 0) - { - // running out of input - return false; - } - - if (symbol < 256) - { - // literal - _output.Write((byte)symbol); - --freeBytes; - } - else if (symbol == 256) - { - // end of block - endOfBlockCodeSeen = true; - // Reset state - _state = InflaterState.ReadingBFinal; - return true; - } - else - { - // length/distance pair - symbol -= 257; // length code started at 257 - if (symbol < 8) - { - symbol += 3; // match length = 3,4,5,6,7,8,9,10 - _extraBits = 0; - } - else if (!_deflate64 && symbol == 28) - { - // extra bits for code 285 is 0 - symbol = 258; // code 285 means length 258 - _extraBits = 0; - } - else - { - if (symbol < 0 || symbol >= S_EXTRA_LENGTH_BITS.Length) - { - throw new InvalidDataException("Deflate64: invalid data"); - } - _extraBits = S_EXTRA_LENGTH_BITS[symbol]; - Debug.Assert(_extraBits != 0, "We handle other cases separately!"); - } - _length = symbol; - goto case InflaterState.HaveInitialLength; - } - break; - - case InflaterState.HaveInitialLength: - if (_extraBits > 0) - { - _state = InflaterState.HaveInitialLength; - int bits = _input.GetBits(_extraBits); - if (bits < 0) - { - return false; - } - - if (_length < 0 || _length >= S_LENGTH_BASE.Length) - { - throw new InvalidDataException("Deflate64: invalid data"); - } - _length = S_LENGTH_BASE[_length] + bits; - } - _state = InflaterState.HaveFullLength; - goto case InflaterState.HaveFullLength; - - case InflaterState.HaveFullLength: - if (_blockType == BlockType.Dynamic) - { - _distanceCode = _distanceTree.GetNextSymbol(_input); - } - else - { - // get distance code directly for static block - _distanceCode = _input.GetBits(5); - if (_distanceCode >= 0) - { - _distanceCode = S_STATIC_DISTANCE_TREE_TABLE[_distanceCode]; - } - } - - if (_distanceCode < 0) - { - // running out input - return false; - } - - _state = InflaterState.HaveDistCode; - goto case InflaterState.HaveDistCode; - - case InflaterState.HaveDistCode: - // To avoid a table lookup we note that for distanceCode > 3, - // extra_bits = (distanceCode-2) >> 1 - int offset; - if (_distanceCode > 3) - { - _extraBits = (_distanceCode - 2) >> 1; - int bits = _input.GetBits(_extraBits); - if (bits < 0) - { - return false; - } - offset = S_DISTANCE_BASE_POSITION[_distanceCode] + bits; - } - else - { - offset = _distanceCode + 1; - } - - _output.WriteLengthDistance(_length, offset); - freeBytes -= _length; - _state = InflaterState.DecodeTop; - break; - - default: - Debug. /*Fail*/ - Assert(false, "check why we are here!"); - throw new InvalidDataException("Deflate64: unknown state"); - } - } - - return true; + result = DecodeBlock(out eob); + } + else if (_blockType == BlockType.Uncompressed) + { + result = DecodeUncompressedBlock(out eob); + } + else + { + throw new InvalidDataException("Deflate64: unknown block type"); } - // Format of the dynamic block header: - // 5 Bits: HLIT, # of Literal/Length codes - 257 (257 - 286) - // 5 Bits: HDIST, # of Distance codes - 1 (1 - 32) - // 4 Bits: HCLEN, # of Code Length codes - 4 (4 - 19) // - // (HCLEN + 4) x 3 bits: code lengths for the code length - // alphabet given just above, in the order: 16, 17, 18, - // 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 + // If we reached the end of the block and the block we were decoding had + // bfinal=1 (final block) // - // These code lengths are interpreted as 3-bit integers - // (0-7); as above, a code length of 0 means the - // corresponding symbol (literal/length or distance code - // length) is not used. - // - // HLIT + 257 code lengths for the literal/length alphabet, - // encoded using the code length Huffman code - // - // HDIST + 1 code lengths for the distance alphabet, - // encoded using the code length Huffman code - // - // The code length repeat codes can cross from HLIT + 257 to the - // HDIST + 1 code lengths. In other words, all code lengths form - // a single sequence of HLIT + HDIST + 258 values. - private bool DecodeDynamicBlockHeader() + if (eob && (_bfinal != 0)) + { + //if (_hasFormatReader) + // _state = InflaterState.StartReadingFooter; + //else + _state = InflaterState.Done; + } + return result; + } + + // Format of Non-compressed blocks (BTYPE=00): + // + // Any bits of input up to the next byte boundary are ignored. + // The rest of the block consists of the following information: + // + // 0 1 2 3 4... + // +---+---+---+---+================================+ + // | LEN | NLEN |... LEN bytes of literal data...| + // +---+---+---+---+================================+ + // + // LEN is the number of data bytes in the block. NLEN is the + // one's complement of LEN. + private bool DecodeUncompressedBlock(out bool endOfBlock) + { + endOfBlock = false; + while (true) { switch (_state) { - case InflaterState.ReadingNumLitCodes: - _literalLengthCodeCount = _input.GetBits(5); - if (_literalLengthCodeCount < 0) + case InflaterState.UncompressedAligning: // initial state when calling this function + // we must skip to a byte boundary + _input.SkipToByteBoundary(); + _state = InflaterState.UncompressedByte1; + goto case InflaterState.UncompressedByte1; + + case InflaterState.UncompressedByte1: // decoding block length + case InflaterState.UncompressedByte2: + case InflaterState.UncompressedByte3: + case InflaterState.UncompressedByte4: + var bits = _input.GetBits(8); + if (bits < 0) { return false; } - _literalLengthCodeCount += 257; - _state = InflaterState.ReadingNumDistCodes; - goto case InflaterState.ReadingNumDistCodes; - case InflaterState.ReadingNumDistCodes: - _distanceCodeCount = _input.GetBits(5); - if (_distanceCodeCount < 0) + _blockLengthBuffer[_state - InflaterState.UncompressedByte1] = (byte)bits; + if (_state == InflaterState.UncompressedByte4) { + _blockLength = + _blockLengthBuffer[0] + (_blockLengthBuffer[1] * 256); + var blockLengthComplement = + _blockLengthBuffer[2] + (_blockLengthBuffer[3] * 256); + + // make sure complement matches + if ((ushort)_blockLength != (ushort)(~blockLengthComplement)) + { + throw new InvalidDataException("Deflate64: invalid block length"); + } + } + + _state += 1; + break; + + case InflaterState.DecodingUncompressed: // copying block data + + // Directly copy bytes from input to output. + var bytesCopied = _output.CopyFrom(_input, _blockLength); + _blockLength -= bytesCopied; + + if (_blockLength == 0) + { + // Done with this block, need to re-init bit buffer for next block + _state = InflaterState.ReadingBFinal; + endOfBlock = true; + return true; + } + + // We can fail to copy all bytes for two reasons: + // Running out of Input + // running out of free space in output window + if (_output.FreeBytes == 0) + { + return true; + } + + return false; + + default: + Debug. /*Fail*/ + Assert(false, "check why we are here!"); + throw new InvalidDataException("Deflate64: unknown state"); + } + } + } + + private bool DecodeBlock(out bool endOfBlockCodeSeen) + { + endOfBlockCodeSeen = false; + + var freeBytes = _output.FreeBytes; // it is a little bit faster than frequently accessing the property + while (freeBytes > 65536) + { + // With Deflate64 we can have up to a 64kb length, so we ensure at least that much space is available + // in the OutputWindow to avoid overwriting previous unflushed output data. + + int symbol; + switch (_state) + { + case InflaterState.DecodeTop: + // decode an element from the literal tree + + // TODO: optimize this!!! + symbol = _literalLengthTree.GetNextSymbol(_input); + if (symbol < 0) + { + // running out of input return false; } - _distanceCodeCount += 1; - _state = InflaterState.ReadingNumCodeLengthCodes; - goto case InflaterState.ReadingNumCodeLengthCodes; - case InflaterState.ReadingNumCodeLengthCodes: - _codeLengthCodeCount = _input.GetBits(4); - if (_codeLengthCodeCount < 0) + if (symbol < 256) { - return false; + // literal + _output.Write((byte)symbol); + --freeBytes; } - _codeLengthCodeCount += 4; - _loopCounter = 0; - _state = InflaterState.ReadingCodeLengthCodes; - goto case InflaterState.ReadingCodeLengthCodes; - - case InflaterState.ReadingCodeLengthCodes: - while (_loopCounter < _codeLengthCodeCount) + else if (symbol == 256) { - int bits = _input.GetBits(3); + // end of block + endOfBlockCodeSeen = true; + // Reset state + _state = InflaterState.ReadingBFinal; + return true; + } + else + { + // length/distance pair + symbol -= 257; // length code started at 257 + if (symbol < 8) + { + symbol += 3; // match length = 3,4,5,6,7,8,9,10 + _extraBits = 0; + } + else if (!_deflate64 && symbol == 28) + { + // extra bits for code 285 is 0 + symbol = 258; // code 285 means length 258 + _extraBits = 0; + } + else + { + if (symbol < 0 || symbol >= S_EXTRA_LENGTH_BITS.Length) + { + throw new InvalidDataException("Deflate64: invalid data"); + } + _extraBits = S_EXTRA_LENGTH_BITS[symbol]; + Debug.Assert(_extraBits != 0, "We handle other cases separately!"); + } + _length = symbol; + goto case InflaterState.HaveInitialLength; + } + break; + + case InflaterState.HaveInitialLength: + if (_extraBits > 0) + { + _state = InflaterState.HaveInitialLength; + var bits = _input.GetBits(_extraBits); if (bits < 0) { return false; } - _codeLengthTreeCodeLength[S_CODE_ORDER[_loopCounter]] = (byte)bits; - ++_loopCounter; - } - for (int i = _codeLengthCodeCount; i < S_CODE_ORDER.Length; i++) + if (_length < 0 || _length >= S_LENGTH_BASE.Length) + { + throw new InvalidDataException("Deflate64: invalid data"); + } + _length = S_LENGTH_BASE[_length] + bits; + } + _state = InflaterState.HaveFullLength; + goto case InflaterState.HaveFullLength; + + case InflaterState.HaveFullLength: + if (_blockType == BlockType.Dynamic) { - _codeLengthTreeCodeLength[S_CODE_ORDER[i]] = 0; + _distanceCode = _distanceTree.GetNextSymbol(_input); } - - // create huffman tree for code length - _codeLengthTree = new HuffmanTree(_codeLengthTreeCodeLength); - _codeArraySize = _literalLengthCodeCount + _distanceCodeCount; - _loopCounter = 0; // reset loop count - - _state = InflaterState.ReadingTreeCodesBefore; - goto case InflaterState.ReadingTreeCodesBefore; - - case InflaterState.ReadingTreeCodesBefore: - case InflaterState.ReadingTreeCodesAfter: - while (_loopCounter < _codeArraySize) + else { - if (_state == InflaterState.ReadingTreeCodesBefore) + // get distance code directly for static block + _distanceCode = _input.GetBits(5); + if (_distanceCode >= 0) { - if ((_lengthCode = _codeLengthTree.GetNextSymbol(_input)) < 0) - { - return false; - } + _distanceCode = S_STATIC_DISTANCE_TREE_TABLE[_distanceCode]; } - - // The alphabet for code lengths is as follows: - // 0 - 15: Represent code lengths of 0 - 15 - // 16: Copy the previous code length 3 - 6 times. - // The next 2 bits indicate repeat length - // (0 = 3, ... , 3 = 6) - // Example: Codes 8, 16 (+2 bits 11), - // 16 (+2 bits 10) will expand to - // 12 code lengths of 8 (1 + 6 + 5) - // 17: Repeat a code length of 0 for 3 - 10 times. - // (3 bits of length) - // 18: Repeat a code length of 0 for 11 - 138 times - // (7 bits of length) - if (_lengthCode <= 15) - { - _codeList[_loopCounter++] = (byte)_lengthCode; - } - else - { - int repeatCount; - if (_lengthCode == 16) - { - if (!_input.EnsureBitsAvailable(2)) - { - _state = InflaterState.ReadingTreeCodesAfter; - return false; - } - - if (_loopCounter == 0) - { - // can't have "prev code" on first code - throw new InvalidDataException(); - } - - byte previousCode = _codeList[_loopCounter - 1]; - repeatCount = _input.GetBits(2) + 3; - - if (_loopCounter + repeatCount > _codeArraySize) - { - throw new InvalidDataException(); - } - - for (int j = 0; j < repeatCount; j++) - { - _codeList[_loopCounter++] = previousCode; - } - } - else if (_lengthCode == 17) - { - if (!_input.EnsureBitsAvailable(3)) - { - _state = InflaterState.ReadingTreeCodesAfter; - return false; - } - - repeatCount = _input.GetBits(3) + 3; - - if (_loopCounter + repeatCount > _codeArraySize) - { - throw new InvalidDataException(); - } - - for (int j = 0; j < repeatCount; j++) - { - _codeList[_loopCounter++] = 0; - } - } - else - { - // code == 18 - if (!_input.EnsureBitsAvailable(7)) - { - _state = InflaterState.ReadingTreeCodesAfter; - return false; - } - - repeatCount = _input.GetBits(7) + 11; - - if (_loopCounter + repeatCount > _codeArraySize) - { - throw new InvalidDataException(); - } - - for (int j = 0; j < repeatCount; j++) - { - _codeList[_loopCounter++] = 0; - } - } - } - _state = InflaterState.ReadingTreeCodesBefore; // we want to read the next code. } + + if (_distanceCode < 0) + { + // running out input + return false; + } + + _state = InflaterState.HaveDistCode; + goto case InflaterState.HaveDistCode; + + case InflaterState.HaveDistCode: + // To avoid a table lookup we note that for distanceCode > 3, + // extra_bits = (distanceCode-2) >> 1 + int offset; + if (_distanceCode > 3) + { + _extraBits = (_distanceCode - 2) >> 1; + var bits = _input.GetBits(_extraBits); + if (bits < 0) + { + return false; + } + offset = S_DISTANCE_BASE_POSITION[_distanceCode] + bits; + } + else + { + offset = _distanceCode + 1; + } + + _output.WriteLengthDistance(_length, offset); + freeBytes -= _length; + _state = InflaterState.DecodeTop; break; default: @@ -851,32 +654,228 @@ namespace SharpCompress.Compressors.Deflate64 Assert(false, "check why we are here!"); throw new InvalidDataException("Deflate64: unknown state"); } - - byte[] literalTreeCodeLength = new byte[HuffmanTree.MAX_LITERAL_TREE_ELEMENTS]; - byte[] distanceTreeCodeLength = new byte[HuffmanTree.MAX_DIST_TREE_ELEMENTS]; - - // Create literal and distance tables - Array.Copy(_codeList, literalTreeCodeLength, _literalLengthCodeCount); - Array.Copy( - _codeList, - _literalLengthCodeCount, - distanceTreeCodeLength, - 0, - _distanceCodeCount - ); - - // Make sure there is an end-of-block code, otherwise how could we ever end? - if (literalTreeCodeLength[HuffmanTree.END_OF_BLOCK_CODE] == 0) - { - throw new InvalidDataException(); - } - - _literalLengthTree = new HuffmanTree(literalTreeCodeLength); - _distanceTree = new HuffmanTree(distanceTreeCodeLength); - _state = InflaterState.DecodeTop; - return true; } - public void Dispose() { } + return true; } + + // Format of the dynamic block header: + // 5 Bits: HLIT, # of Literal/Length codes - 257 (257 - 286) + // 5 Bits: HDIST, # of Distance codes - 1 (1 - 32) + // 4 Bits: HCLEN, # of Code Length codes - 4 (4 - 19) + // + // (HCLEN + 4) x 3 bits: code lengths for the code length + // alphabet given just above, in the order: 16, 17, 18, + // 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 + // + // These code lengths are interpreted as 3-bit integers + // (0-7); as above, a code length of 0 means the + // corresponding symbol (literal/length or distance code + // length) is not used. + // + // HLIT + 257 code lengths for the literal/length alphabet, + // encoded using the code length Huffman code + // + // HDIST + 1 code lengths for the distance alphabet, + // encoded using the code length Huffman code + // + // The code length repeat codes can cross from HLIT + 257 to the + // HDIST + 1 code lengths. In other words, all code lengths form + // a single sequence of HLIT + HDIST + 258 values. + private bool DecodeDynamicBlockHeader() + { + switch (_state) + { + case InflaterState.ReadingNumLitCodes: + _literalLengthCodeCount = _input.GetBits(5); + if (_literalLengthCodeCount < 0) + { + return false; + } + _literalLengthCodeCount += 257; + _state = InflaterState.ReadingNumDistCodes; + goto case InflaterState.ReadingNumDistCodes; + + case InflaterState.ReadingNumDistCodes: + _distanceCodeCount = _input.GetBits(5); + if (_distanceCodeCount < 0) + { + return false; + } + _distanceCodeCount += 1; + _state = InflaterState.ReadingNumCodeLengthCodes; + goto case InflaterState.ReadingNumCodeLengthCodes; + + case InflaterState.ReadingNumCodeLengthCodes: + _codeLengthCodeCount = _input.GetBits(4); + if (_codeLengthCodeCount < 0) + { + return false; + } + _codeLengthCodeCount += 4; + _loopCounter = 0; + _state = InflaterState.ReadingCodeLengthCodes; + goto case InflaterState.ReadingCodeLengthCodes; + + case InflaterState.ReadingCodeLengthCodes: + while (_loopCounter < _codeLengthCodeCount) + { + var bits = _input.GetBits(3); + if (bits < 0) + { + return false; + } + _codeLengthTreeCodeLength[S_CODE_ORDER[_loopCounter]] = (byte)bits; + ++_loopCounter; + } + + for (var i = _codeLengthCodeCount; i < S_CODE_ORDER.Length; i++) + { + _codeLengthTreeCodeLength[S_CODE_ORDER[i]] = 0; + } + + // create huffman tree for code length + _codeLengthTree = new HuffmanTree(_codeLengthTreeCodeLength); + _codeArraySize = _literalLengthCodeCount + _distanceCodeCount; + _loopCounter = 0; // reset loop count + + _state = InflaterState.ReadingTreeCodesBefore; + goto case InflaterState.ReadingTreeCodesBefore; + + case InflaterState.ReadingTreeCodesBefore: + case InflaterState.ReadingTreeCodesAfter: + while (_loopCounter < _codeArraySize) + { + if (_state == InflaterState.ReadingTreeCodesBefore) + { + if ((_lengthCode = _codeLengthTree.GetNextSymbol(_input)) < 0) + { + return false; + } + } + + // The alphabet for code lengths is as follows: + // 0 - 15: Represent code lengths of 0 - 15 + // 16: Copy the previous code length 3 - 6 times. + // The next 2 bits indicate repeat length + // (0 = 3, ... , 3 = 6) + // Example: Codes 8, 16 (+2 bits 11), + // 16 (+2 bits 10) will expand to + // 12 code lengths of 8 (1 + 6 + 5) + // 17: Repeat a code length of 0 for 3 - 10 times. + // (3 bits of length) + // 18: Repeat a code length of 0 for 11 - 138 times + // (7 bits of length) + if (_lengthCode <= 15) + { + _codeList[_loopCounter++] = (byte)_lengthCode; + } + else + { + int repeatCount; + if (_lengthCode == 16) + { + if (!_input.EnsureBitsAvailable(2)) + { + _state = InflaterState.ReadingTreeCodesAfter; + return false; + } + + if (_loopCounter == 0) + { + // can't have "prev code" on first code + throw new InvalidDataException(); + } + + var previousCode = _codeList[_loopCounter - 1]; + repeatCount = _input.GetBits(2) + 3; + + if (_loopCounter + repeatCount > _codeArraySize) + { + throw new InvalidDataException(); + } + + for (var j = 0; j < repeatCount; j++) + { + _codeList[_loopCounter++] = previousCode; + } + } + else if (_lengthCode == 17) + { + if (!_input.EnsureBitsAvailable(3)) + { + _state = InflaterState.ReadingTreeCodesAfter; + return false; + } + + repeatCount = _input.GetBits(3) + 3; + + if (_loopCounter + repeatCount > _codeArraySize) + { + throw new InvalidDataException(); + } + + for (var j = 0; j < repeatCount; j++) + { + _codeList[_loopCounter++] = 0; + } + } + else + { + // code == 18 + if (!_input.EnsureBitsAvailable(7)) + { + _state = InflaterState.ReadingTreeCodesAfter; + return false; + } + + repeatCount = _input.GetBits(7) + 11; + + if (_loopCounter + repeatCount > _codeArraySize) + { + throw new InvalidDataException(); + } + + for (var j = 0; j < repeatCount; j++) + { + _codeList[_loopCounter++] = 0; + } + } + } + _state = InflaterState.ReadingTreeCodesBefore; // we want to read the next code. + } + break; + + default: + Debug. /*Fail*/ + Assert(false, "check why we are here!"); + throw new InvalidDataException("Deflate64: unknown state"); + } + + var literalTreeCodeLength = new byte[HuffmanTree.MAX_LITERAL_TREE_ELEMENTS]; + var distanceTreeCodeLength = new byte[HuffmanTree.MAX_DIST_TREE_ELEMENTS]; + + // Create literal and distance tables + Array.Copy(_codeList, literalTreeCodeLength, _literalLengthCodeCount); + Array.Copy( + _codeList, + _literalLengthCodeCount, + distanceTreeCodeLength, + 0, + _distanceCodeCount + ); + + // Make sure there is an end-of-block code, otherwise how could we ever end? + if (literalTreeCodeLength[HuffmanTree.END_OF_BLOCK_CODE] == 0) + { + throw new InvalidDataException(); + } + + _literalLengthTree = new HuffmanTree(literalTreeCodeLength); + _distanceTree = new HuffmanTree(distanceTreeCodeLength); + _state = InflaterState.DecodeTop; + return true; + } + + public void Dispose() { } } diff --git a/src/SharpCompress/Compressors/Deflate64/InflaterState.cs b/src/SharpCompress/Compressors/Deflate64/InflaterState.cs index 64450931..711c3245 100644 --- a/src/SharpCompress/Compressors/Deflate64/InflaterState.cs +++ b/src/SharpCompress/Compressors/Deflate64/InflaterState.cs @@ -2,41 +2,40 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -namespace SharpCompress.Compressors.Deflate64 +namespace SharpCompress.Compressors.Deflate64; + +// Do not rearrange the enum values. +internal enum InflaterState { - // Do not rearrange the enum values. - internal enum InflaterState - { - ReadingHeader = 0, // Only applies to GZIP + ReadingHeader = 0, // Only applies to GZIP - ReadingBFinal = 2, // About to read bfinal bit - ReadingBType = 3, // About to read blockType bits + ReadingBFinal = 2, // About to read bfinal bit + ReadingBType = 3, // About to read blockType bits - ReadingNumLitCodes = 4, // About to read # literal codes - ReadingNumDistCodes = 5, // About to read # dist codes - ReadingNumCodeLengthCodes = 6, // About to read # code length codes - ReadingCodeLengthCodes = 7, // In the middle of reading the code length codes - ReadingTreeCodesBefore = 8, // In the middle of reading tree codes (loop top) - ReadingTreeCodesAfter = 9, // In the middle of reading tree codes (extension; code > 15) + ReadingNumLitCodes = 4, // About to read # literal codes + ReadingNumDistCodes = 5, // About to read # dist codes + ReadingNumCodeLengthCodes = 6, // About to read # code length codes + ReadingCodeLengthCodes = 7, // In the middle of reading the code length codes + ReadingTreeCodesBefore = 8, // In the middle of reading tree codes (loop top) + ReadingTreeCodesAfter = 9, // In the middle of reading tree codes (extension; code > 15) - DecodeTop = 10, // About to decode a literal (char/match) in a compressed block - HaveInitialLength = 11, // Decoding a match, have the literal code (base length) - HaveFullLength = 12, // Ditto, now have the full match length (incl. extra length bits) - HaveDistCode = 13, // Ditto, now have the distance code also, need extra dist bits + DecodeTop = 10, // About to decode a literal (char/match) in a compressed block + HaveInitialLength = 11, // Decoding a match, have the literal code (base length) + HaveFullLength = 12, // Ditto, now have the full match length (incl. extra length bits) + HaveDistCode = 13, // Ditto, now have the distance code also, need extra dist bits - /* uncompressed blocks */ - UncompressedAligning = 15, - UncompressedByte1 = 16, - UncompressedByte2 = 17, - UncompressedByte3 = 18, - UncompressedByte4 = 19, - DecodingUncompressed = 20, + /* uncompressed blocks */ + UncompressedAligning = 15, + UncompressedByte1 = 16, + UncompressedByte2 = 17, + UncompressedByte3 = 18, + UncompressedByte4 = 19, + DecodingUncompressed = 20, - // These three apply only to GZIP - StartReadingFooter = 21, // (Initialisation for reading footer) - ReadingFooter = 22, - VerifyingFooter = 23, + // These three apply only to GZIP + StartReadingFooter = 21, // (Initialisation for reading footer) + ReadingFooter = 22, + VerifyingFooter = 23, - Done = 24 // Finished - } + Done = 24 // Finished } diff --git a/src/SharpCompress/Compressors/Deflate64/InputBuffer.cs b/src/SharpCompress/Compressors/Deflate64/InputBuffer.cs index a7357565..28d61e42 100644 --- a/src/SharpCompress/Compressors/Deflate64/InputBuffer.cs +++ b/src/SharpCompress/Compressors/Deflate64/InputBuffer.cs @@ -7,40 +7,50 @@ using System; using System.Diagnostics; -namespace SharpCompress.Compressors.Deflate64 +namespace SharpCompress.Compressors.Deflate64; + +// This class can be used to read bits from an byte array quickly. +// Normally we get bits from 'bitBuffer' field and bitsInBuffer stores +// the number of bits available in 'BitBuffer'. +// When we used up the bits in bitBuffer, we will try to get byte from +// the byte array and copy the byte to appropiate position in bitBuffer. +// +// The byte array is not reused. We will go from 'start' to 'end'. +// When we reach the end, most read operations will return -1, +// which means we are running out of input. + +internal sealed class InputBuffer { - // This class can be used to read bits from an byte array quickly. - // Normally we get bits from 'bitBuffer' field and bitsInBuffer stores - // the number of bits available in 'BitBuffer'. - // When we used up the bits in bitBuffer, we will try to get byte from - // the byte array and copy the byte to appropiate position in bitBuffer. - // - // The byte array is not reused. We will go from 'start' to 'end'. - // When we reach the end, most read operations will return -1, - // which means we are running out of input. + private byte[] _buffer; // byte array to store input + private int _start; // start poisition of the buffer + private int _end; // end position of the buffer + private uint _bitBuffer = 0; // store the bits here, we can quickly shift in this buffer + private int _bitsInBuffer = 0; // number of bits available in bitBuffer - internal sealed class InputBuffer + /// Total bits available in the input buffer. + public int AvailableBits => _bitsInBuffer; + + /// Total bytes available in the input buffer. + public int AvailableBytes => (_end - _start) + (_bitsInBuffer / 8); + + /// Ensure that count bits are in the bit buffer. + /// Can be up to 16. + /// Returns false if input is not sufficient to make this true. + public bool EnsureBitsAvailable(int count) { - private byte[] _buffer; // byte array to store input - private int _start; // start poisition of the buffer - private int _end; // end position of the buffer - private uint _bitBuffer = 0; // store the bits here, we can quickly shift in this buffer - private int _bitsInBuffer = 0; // number of bits available in bitBuffer + Debug.Assert(0 < count && count <= 16, "count is invalid."); - /// Total bits available in the input buffer. - public int AvailableBits => _bitsInBuffer; - - /// Total bytes available in the input buffer. - public int AvailableBytes => (_end - _start) + (_bitsInBuffer / 8); - - /// Ensure that count bits are in the bit buffer. - /// Can be up to 16. - /// Returns false if input is not sufficient to make this true. - public bool EnsureBitsAvailable(int count) + // manual inlining to improve perf + if (_bitsInBuffer < count) { - Debug.Assert(0 < count && count <= 16, "count is invalid."); + if (NeedsInput()) + { + return false; + } + // insert a byte to bitbuffer + _bitBuffer |= (uint)_buffer[_start++] << _bitsInBuffer; + _bitsInBuffer += 8; - // manual inlining to improve perf if (_bitsInBuffer < count) { if (NeedsInput()) @@ -50,158 +60,147 @@ namespace SharpCompress.Compressors.Deflate64 // insert a byte to bitbuffer _bitBuffer |= (uint)_buffer[_start++] << _bitsInBuffer; _bitsInBuffer += 8; - - if (_bitsInBuffer < count) - { - if (NeedsInput()) - { - return false; - } - // insert a byte to bitbuffer - _bitBuffer |= (uint)_buffer[_start++] << _bitsInBuffer; - _bitsInBuffer += 8; - } } - - return true; } - /// - /// This function will try to load 16 or more bits into bitBuffer. - /// It returns whatever is contained in bitBuffer after loading. - /// The main difference between this and GetBits is that this will - /// never return -1. So the caller needs to check AvailableBits to - /// see how many bits are available. - /// - public uint TryLoad16Bits() + return true; + } + + /// + /// This function will try to load 16 or more bits into bitBuffer. + /// It returns whatever is contained in bitBuffer after loading. + /// The main difference between this and GetBits is that this will + /// never return -1. So the caller needs to check AvailableBits to + /// see how many bits are available. + /// + public uint TryLoad16Bits() + { + if (_bitsInBuffer < 8) { - if (_bitsInBuffer < 8) + if (_start < _end) { - if (_start < _end) - { - _bitBuffer |= (uint)_buffer[_start++] << _bitsInBuffer; - _bitsInBuffer += 8; - } - - if (_start < _end) - { - _bitBuffer |= (uint)_buffer[_start++] << _bitsInBuffer; - _bitsInBuffer += 8; - } - } - else if (_bitsInBuffer < 16) - { - if (_start < _end) - { - _bitBuffer |= (uint)_buffer[_start++] << _bitsInBuffer; - _bitsInBuffer += 8; - } + _bitBuffer |= (uint)_buffer[_start++] << _bitsInBuffer; + _bitsInBuffer += 8; } - return _bitBuffer; + if (_start < _end) + { + _bitBuffer |= (uint)_buffer[_start++] << _bitsInBuffer; + _bitsInBuffer += 8; + } } - - private uint GetBitMask(int count) => ((uint)1 << count) - 1; - - /// Gets count bits from the input buffer. Returns -1 if not enough bits available. - public int GetBits(int count) + else if (_bitsInBuffer < 16) { - Debug.Assert(0 < count && count <= 16, "count is invalid."); - - if (!EnsureBitsAvailable(count)) + if (_start < _end) { - return -1; + _bitBuffer |= (uint)_buffer[_start++] << _bitsInBuffer; + _bitsInBuffer += 8; } - - int result = (int)(_bitBuffer & GetBitMask(count)); - _bitBuffer >>= count; - _bitsInBuffer -= count; - return result; } - /// - /// Copies length bytes from input buffer to output buffer starting at output[offset]. - /// You have to make sure, that the buffer is byte aligned. If not enough bytes are - /// available, copies fewer bytes. - /// - /// Returns the number of bytes copied, 0 if no byte is available. - public int CopyTo(byte[] output, int offset, int length) + return _bitBuffer; + } + + private uint GetBitMask(int count) => ((uint)1 << count) - 1; + + /// Gets count bits from the input buffer. Returns -1 if not enough bits available. + public int GetBits(int count) + { + Debug.Assert(0 < count && count <= 16, "count is invalid."); + + if (!EnsureBitsAvailable(count)) { - Debug.Assert(output != null); - Debug.Assert(offset >= 0); - Debug.Assert(length >= 0); - Debug.Assert(offset <= output.Length - length); - Debug.Assert((_bitsInBuffer % 8) == 0); - - // Copy the bytes in bitBuffer first. - int bytesFromBitBuffer = 0; - while (_bitsInBuffer > 0 && length > 0) - { - output[offset++] = (byte)_bitBuffer; - _bitBuffer >>= 8; - _bitsInBuffer -= 8; - length--; - bytesFromBitBuffer++; - } - - if (length == 0) - { - return bytesFromBitBuffer; - } - - int avail = _end - _start; - if (length > avail) - { - length = avail; - } - - Array.Copy(_buffer, _start, output, offset, length); - _start += length; - return bytesFromBitBuffer + length; + return -1; } - /// - /// Return true is all input bytes are used. - /// This means the caller can call SetInput to add more input. - /// - public bool NeedsInput() => _start == _end; + var result = (int)(_bitBuffer & GetBitMask(count)); + _bitBuffer >>= count; + _bitsInBuffer -= count; + return result; + } - /// - /// Set the byte array to be processed. - /// All the bits remained in bitBuffer will be processed before the new bytes. - /// We don't clone the byte array here since it is expensive. - /// The caller should make sure after a buffer is passed in. - /// It will not be changed before calling this function again. - /// - public void SetInput(byte[] buffer, int offset, int length) + /// + /// Copies length bytes from input buffer to output buffer starting at output[offset]. + /// You have to make sure, that the buffer is byte aligned. If not enough bytes are + /// available, copies fewer bytes. + /// + /// Returns the number of bytes copied, 0 if no byte is available. + public int CopyTo(byte[] output, int offset, int length) + { + Debug.Assert(output != null); + Debug.Assert(offset >= 0); + Debug.Assert(length >= 0); + Debug.Assert(offset <= output.Length - length); + Debug.Assert((_bitsInBuffer % 8) == 0); + + // Copy the bytes in bitBuffer first. + var bytesFromBitBuffer = 0; + while (_bitsInBuffer > 0 && length > 0) { - Debug.Assert(buffer != null); - Debug.Assert(offset >= 0); - Debug.Assert(length >= 0); - Debug.Assert(offset <= buffer.Length - length); - Debug.Assert(_start == _end); - - _buffer = buffer; - _start = offset; - _end = offset + length; + output[offset++] = (byte)_bitBuffer; + _bitBuffer >>= 8; + _bitsInBuffer -= 8; + length--; + bytesFromBitBuffer++; } - /// Skip n bits in the buffer. - public void SkipBits(int n) + if (length == 0) { - Debug.Assert( - _bitsInBuffer >= n, - "No enough bits in the buffer, Did you call EnsureBitsAvailable?" - ); - _bitBuffer >>= n; - _bitsInBuffer -= n; + return bytesFromBitBuffer; } - /// Skips to the next byte boundary. - public void SkipToByteBoundary() + var avail = _end - _start; + if (length > avail) { - _bitBuffer >>= (_bitsInBuffer % 8); - _bitsInBuffer = _bitsInBuffer - (_bitsInBuffer % 8); + length = avail; } + + Array.Copy(_buffer, _start, output, offset, length); + _start += length; + return bytesFromBitBuffer + length; + } + + /// + /// Return true is all input bytes are used. + /// This means the caller can call SetInput to add more input. + /// + public bool NeedsInput() => _start == _end; + + /// + /// Set the byte array to be processed. + /// All the bits remained in bitBuffer will be processed before the new bytes. + /// We don't clone the byte array here since it is expensive. + /// The caller should make sure after a buffer is passed in. + /// It will not be changed before calling this function again. + /// + public void SetInput(byte[] buffer, int offset, int length) + { + Debug.Assert(buffer != null); + Debug.Assert(offset >= 0); + Debug.Assert(length >= 0); + Debug.Assert(offset <= buffer.Length - length); + Debug.Assert(_start == _end); + + _buffer = buffer; + _start = offset; + _end = offset + length; + } + + /// Skip n bits in the buffer. + public void SkipBits(int n) + { + Debug.Assert( + _bitsInBuffer >= n, + "No enough bits in the buffer, Did you call EnsureBitsAvailable?" + ); + _bitBuffer >>= n; + _bitsInBuffer -= n; + } + + /// Skips to the next byte boundary. + public void SkipToByteBoundary() + { + _bitBuffer >>= (_bitsInBuffer % 8); + _bitsInBuffer -= (_bitsInBuffer % 8); } } diff --git a/src/SharpCompress/Compressors/Deflate64/Match.cs b/src/SharpCompress/Compressors/Deflate64/Match.cs index 4d5ce54b..c75cbe7a 100644 --- a/src/SharpCompress/Compressors/Deflate64/Match.cs +++ b/src/SharpCompress/Compressors/Deflate64/Match.cs @@ -2,16 +2,15 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -namespace SharpCompress.Compressors.Deflate64 +namespace SharpCompress.Compressors.Deflate64; + +/// +/// This class represents a match in the history window. +/// +internal sealed class Match { - /// - /// This class represents a match in the history window. - /// - internal sealed class Match - { - internal MatchState State { get; set; } - internal int Position { get; set; } - internal int Length { get; set; } - internal byte Symbol { get; set; } - } + internal MatchState State { get; set; } + internal int Position { get; set; } + internal int Length { get; set; } + internal byte Symbol { get; set; } } diff --git a/src/SharpCompress/Compressors/Deflate64/MatchState.cs b/src/SharpCompress/Compressors/Deflate64/MatchState.cs index f88913bc..858e91e8 100644 --- a/src/SharpCompress/Compressors/Deflate64/MatchState.cs +++ b/src/SharpCompress/Compressors/Deflate64/MatchState.cs @@ -2,12 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -namespace SharpCompress.Compressors.Deflate64 +namespace SharpCompress.Compressors.Deflate64; + +internal enum MatchState { - internal enum MatchState - { - HasSymbol = 1, - HasMatch = 2, - HasSymbolAndMatch = 3 - } + HasSymbol = 1, + HasMatch = 2, + HasSymbolAndMatch = 3 } diff --git a/src/SharpCompress/Compressors/Deflate64/OutputWindow.cs b/src/SharpCompress/Compressors/Deflate64/OutputWindow.cs index d48cd5fb..90b65cd3 100644 --- a/src/SharpCompress/Compressors/Deflate64/OutputWindow.cs +++ b/src/SharpCompress/Compressors/Deflate64/OutputWindow.cs @@ -5,149 +5,148 @@ using System; using System.Diagnostics; -namespace SharpCompress.Compressors.Deflate64 +namespace SharpCompress.Compressors.Deflate64; + +/// +/// This class maintains a window for decompressed output. +/// We need to keep this because the decompressed information can be +/// a literal or a length/distance pair. For length/distance pair, +/// we need to look back in the output window and copy bytes from there. +/// We use a byte array of WindowSize circularly. +/// +internal sealed class OutputWindow { - /// - /// This class maintains a window for decompressed output. - /// We need to keep this because the decompressed information can be - /// a literal or a length/distance pair. For length/distance pair, - /// we need to look back in the output window and copy bytes from there. - /// We use a byte array of WindowSize circularly. - /// - internal sealed class OutputWindow + // With Deflate64 we can have up to a 65536 length as well as up to a 65538 distance. This means we need a Window that is at + // least 131074 bytes long so we have space to retrieve up to a full 64kb in lookback and place it in our buffer without + // overwriting existing data. OutputWindow requires that the WindowSize be an exponent of 2, so we round up to 2^18. + private const int WINDOW_SIZE = 262144; + private const int WINDOW_MASK = 262143; + + private readonly byte[] _window = new byte[WINDOW_SIZE]; // The window is 2^18 bytes + private int _end; // this is the position to where we should write next byte + private int _bytesUsed; // The number of bytes in the output window which is not consumed. + + /// Add a byte to output window. + public void Write(byte b) { - // With Deflate64 we can have up to a 65536 length as well as up to a 65538 distance. This means we need a Window that is at - // least 131074 bytes long so we have space to retrieve up to a full 64kb in lookback and place it in our buffer without - // overwriting existing data. OutputWindow requires that the WindowSize be an exponent of 2, so we round up to 2^18. - private const int WINDOW_SIZE = 262144; - private const int WINDOW_MASK = 262143; + Debug.Assert(_bytesUsed < WINDOW_SIZE, "Can't add byte when window is full!"); + _window[_end++] = b; + _end &= WINDOW_MASK; + ++_bytesUsed; + } - private readonly byte[] _window = new byte[WINDOW_SIZE]; // The window is 2^18 bytes - private int _end; // this is the position to where we should write next byte - private int _bytesUsed; // The number of bytes in the output window which is not consumed. + public void WriteLengthDistance(int length, int distance) + { + Debug.Assert((_bytesUsed + length) <= WINDOW_SIZE, "No Enough space"); - /// Add a byte to output window. - public void Write(byte b) + // move backwards distance bytes in the output stream, + // and copy length bytes from this position to the output stream. + _bytesUsed += length; + var copyStart = (_end - distance) & WINDOW_MASK; // start position for coping. + + var border = WINDOW_SIZE - length; + if (copyStart <= border && _end < border) { - Debug.Assert(_bytesUsed < WINDOW_SIZE, "Can't add byte when window is full!"); - _window[_end++] = b; - _end &= WINDOW_MASK; - ++_bytesUsed; - } - - public void WriteLengthDistance(int length, int distance) - { - Debug.Assert((_bytesUsed + length) <= WINDOW_SIZE, "No Enough space"); - - // move backwards distance bytes in the output stream, - // and copy length bytes from this position to the output stream. - _bytesUsed += length; - int copyStart = (_end - distance) & WINDOW_MASK; // start position for coping. - - int border = WINDOW_SIZE - length; - if (copyStart <= border && _end < border) + if (length <= distance) { - if (length <= distance) - { - Array.Copy(_window, copyStart, _window, _end, length); - _end += length; - } - else - { - // The referenced string may overlap the current - // position; for example, if the last 2 bytes decoded have values - // X and Y, a string reference with - // adds X,Y,X,Y,X to the output stream. - while (length-- > 0) - { - _window[_end++] = _window[copyStart++]; - } - } + Array.Copy(_window, copyStart, _window, _end, length); + _end += length; } else { - // copy byte by byte + // The referenced string may overlap the current + // position; for example, if the last 2 bytes decoded have values + // X and Y, a string reference with + // adds X,Y,X,Y,X to the output stream. while (length-- > 0) { _window[_end++] = _window[copyStart++]; - _end &= WINDOW_MASK; - copyStart &= WINDOW_MASK; } } } - - /// - /// Copy up to length of bytes from input directly. - /// This is used for uncompressed block. - /// - public int CopyFrom(InputBuffer input, int length) + else { - length = Math.Min(Math.Min(length, WINDOW_SIZE - _bytesUsed), input.AvailableBytes); - int copied; - - // We might need wrap around to copy all bytes. - int tailLen = WINDOW_SIZE - _end; - if (length > tailLen) + // copy byte by byte + while (length-- > 0) { - // copy the first part - copied = input.CopyTo(_window, _end, tailLen); - if (copied == tailLen) - { - // only try to copy the second part if we have enough bytes in input - copied += input.CopyTo(_window, 0, length - tailLen); - } + _window[_end++] = _window[copyStart++]; + _end &= WINDOW_MASK; + copyStart &= WINDOW_MASK; } - else - { - // only one copy is needed if there is no wrap around. - copied = input.CopyTo(_window, _end, length); - } - - _end = (_end + copied) & WINDOW_MASK; - _bytesUsed += copied; - return copied; - } - - /// Free space in output window. - public int FreeBytes => WINDOW_SIZE - _bytesUsed; - - /// Bytes not consumed in output window. - public int AvailableBytes => _bytesUsed; - - /// Copy the decompressed bytes to output array. - public int CopyTo(byte[] output, int offset, int length) - { - int copyEnd; - - if (length > _bytesUsed) - { - // we can copy all the decompressed bytes out - copyEnd = _end; - length = _bytesUsed; - } - else - { - copyEnd = (_end - _bytesUsed + length) & WINDOW_MASK; // copy length of bytes - } - - int copied = length; - - int tailLen = length - copyEnd; - if (tailLen > 0) - { - // this means we need to copy two parts separately - // copy tailLen bytes from the end of output window - Array.Copy(_window, WINDOW_SIZE - tailLen, output, offset, tailLen); - offset += tailLen; - length = copyEnd; - } - Array.Copy(_window, copyEnd - length, output, offset, length); - _bytesUsed -= copied; - Debug.Assert( - _bytesUsed >= 0, - "check this function and find why we copied more bytes than we have" - ); - return copied; } } + + /// + /// Copy up to length of bytes from input directly. + /// This is used for uncompressed block. + /// + public int CopyFrom(InputBuffer input, int length) + { + length = Math.Min(Math.Min(length, WINDOW_SIZE - _bytesUsed), input.AvailableBytes); + int copied; + + // We might need wrap around to copy all bytes. + var tailLen = WINDOW_SIZE - _end; + if (length > tailLen) + { + // copy the first part + copied = input.CopyTo(_window, _end, tailLen); + if (copied == tailLen) + { + // only try to copy the second part if we have enough bytes in input + copied += input.CopyTo(_window, 0, length - tailLen); + } + } + else + { + // only one copy is needed if there is no wrap around. + copied = input.CopyTo(_window, _end, length); + } + + _end = (_end + copied) & WINDOW_MASK; + _bytesUsed += copied; + return copied; + } + + /// Free space in output window. + public int FreeBytes => WINDOW_SIZE - _bytesUsed; + + /// Bytes not consumed in output window. + public int AvailableBytes => _bytesUsed; + + /// Copy the decompressed bytes to output array. + public int CopyTo(byte[] output, int offset, int length) + { + int copyEnd; + + if (length > _bytesUsed) + { + // we can copy all the decompressed bytes out + copyEnd = _end; + length = _bytesUsed; + } + else + { + copyEnd = (_end - _bytesUsed + length) & WINDOW_MASK; // copy length of bytes + } + + var copied = length; + + var tailLen = length - copyEnd; + if (tailLen > 0) + { + // this means we need to copy two parts separately + // copy tailLen bytes from the end of output window + Array.Copy(_window, WINDOW_SIZE - tailLen, output, offset, tailLen); + offset += tailLen; + length = copyEnd; + } + Array.Copy(_window, copyEnd - length, output, offset, length); + _bytesUsed -= copied; + Debug.Assert( + _bytesUsed >= 0, + "check this function and find why we copied more bytes than we have" + ); + return copied; + } } diff --git a/src/SharpCompress/Compressors/Filters/BCJ2Filter.cs b/src/SharpCompress/Compressors/Filters/BCJ2Filter.cs index 636f5dc0..c3212118 100644 --- a/src/SharpCompress/Compressors/Filters/BCJ2Filter.cs +++ b/src/SharpCompress/Compressors/Filters/BCJ2Filter.cs @@ -1,230 +1,229 @@ -using System; +using System; using System.IO; -namespace SharpCompress.Compressors.Filters +namespace SharpCompress.Compressors.Filters; + +internal class BCJ2Filter : Stream { - internal class BCJ2Filter : Stream + private readonly Stream _baseStream; + private readonly byte[] _input = new byte[4096]; + private int _inputOffset; + private int _inputCount; + private bool _endReached; + + private long _position; + private readonly byte[] _output = new byte[4]; + private int _outputOffset; + private int _outputCount; + + private readonly byte[] _control; + private readonly byte[] _data1; + private readonly byte[] _data2; + + private int _controlPos; + private int _data1Pos; + private int _data2Pos; + + private readonly ushort[] _p = new ushort[256 + 2]; + private uint _range, + _code; + private byte _prevByte; + private bool _isDisposed; + + private const int K_NUM_TOP_BITS = 24; + private const int K_TOP_VALUE = 1 << K_NUM_TOP_BITS; + + private const int K_NUM_BIT_MODEL_TOTAL_BITS = 11; + private const int K_BIT_MODEL_TOTAL = 1 << K_NUM_BIT_MODEL_TOTAL_BITS; + private const int K_NUM_MOVE_BITS = 5; + + private static bool IsJ(byte b0, byte b1) { - private readonly Stream _baseStream; - private readonly byte[] _input = new byte[4096]; - private int _inputOffset; - private int _inputCount; - private bool _endReached; + return (b1 & 0xFE) == 0xE8 || IsJcc(b0, b1); + } - private long _position; - private readonly byte[] _output = new byte[4]; - private int _outputOffset; - private int _outputCount; + private static bool IsJcc(byte b0, byte b1) + { + return b0 == 0x0F && (b1 & 0xF0) == 0x80; + } - private readonly byte[] _control; - private readonly byte[] _data1; - private readonly byte[] _data2; + public BCJ2Filter(byte[] control, byte[] data1, byte[] data2, Stream baseStream) + { + _control = control; + _data1 = data1; + _data2 = data2; + _baseStream = baseStream; - private int _controlPos; - private int _data1Pos; - private int _data2Pos; - - private readonly ushort[] _p = new ushort[256 + 2]; - private uint _range, - _code; - private byte _prevByte; - private bool _isDisposed; - - private const int K_NUM_TOP_BITS = 24; - private const int K_TOP_VALUE = 1 << K_NUM_TOP_BITS; - - private const int K_NUM_BIT_MODEL_TOTAL_BITS = 11; - private const int K_BIT_MODEL_TOTAL = 1 << K_NUM_BIT_MODEL_TOTAL_BITS; - private const int K_NUM_MOVE_BITS = 5; - - private static bool IsJ(byte b0, byte b1) + int i; + for (i = 0; i < _p.Length; i++) { - return (b1 & 0xFE) == 0xE8 || IsJcc(b0, b1); + _p[i] = K_BIT_MODEL_TOTAL >> 1; } - private static bool IsJcc(byte b0, byte b1) + _code = 0; + _range = 0xFFFFFFFF; + for (i = 0; i < 5; i++) { - return b0 == 0x0F && (b1 & 0xF0) == 0x80; + _code = (_code << 8) | control[_controlPos++]; } + } - public BCJ2Filter(byte[] control, byte[] data1, byte[] data2, Stream baseStream) + protected override void Dispose(bool disposing) + { + if (_isDisposed) { - _control = control; - _data1 = data1; - _data2 = data2; - _baseStream = baseStream; + return; + } + _isDisposed = true; + base.Dispose(disposing); + _baseStream.Dispose(); + } - int i; - for (i = 0; i < _p.Length; i++) + public override bool CanRead => true; + + public override bool CanSeek => false; + + public override bool CanWrite => false; + + public override void Flush() + { + throw new NotSupportedException(); + } + + public override long Length => _baseStream.Length + _data1.Length + _data2.Length; + + public override long Position + { + get => _position; + set => throw new NotSupportedException(); + } + + public override int Read(byte[] buffer, int offset, int count) + { + var size = 0; + byte b = 0; + + while (!_endReached && size < count) + { + while (_outputOffset < _outputCount) { - _p[i] = K_BIT_MODEL_TOTAL >> 1; - } - - _code = 0; - _range = 0xFFFFFFFF; - for (i = 0; i < 5; i++) - { - _code = (_code << 8) | control[_controlPos++]; - } - } - - protected override void Dispose(bool disposing) - { - if (_isDisposed) - { - return; - } - _isDisposed = true; - base.Dispose(disposing); - _baseStream.Dispose(); - } - - public override bool CanRead => true; - - public override bool CanSeek => false; - - public override bool CanWrite => false; - - public override void Flush() - { - throw new NotSupportedException(); - } - - public override long Length => _baseStream.Length + _data1.Length + _data2.Length; - - public override long Position - { - get => _position; - set => throw new NotSupportedException(); - } - - public override int Read(byte[] buffer, int offset, int count) - { - int size = 0; - byte b = 0; - - while (!_endReached && size < count) - { - while (_outputOffset < _outputCount) - { - b = _output[_outputOffset++]; - buffer[offset++] = b; - size++; - _position++; - - _prevByte = b; - if (size == count) - { - return size; - } - } - - if (_inputOffset == _inputCount) - { - _inputOffset = 0; - _inputCount = _baseStream.Read(_input, 0, _input.Length); - if (_inputCount == 0) - { - _endReached = true; - break; - } - } - - b = _input[_inputOffset++]; + b = _output[_outputOffset++]; buffer[offset++] = b; size++; _position++; - if (!IsJ(_prevByte, b)) + _prevByte = b; + if (size == count) { + return size; + } + } + + if (_inputOffset == _inputCount) + { + _inputOffset = 0; + _inputCount = _baseStream.Read(_input, 0, _input.Length); + if (_inputCount == 0) + { + _endReached = true; + break; + } + } + + b = _input[_inputOffset++]; + buffer[offset++] = b; + size++; + _position++; + + if (!IsJ(_prevByte, b)) + { + _prevByte = b; + } + else + { + int prob; + if (b == 0xE8) + { + prob = _prevByte; + } + else if (b == 0xE9) + { + prob = 256; + } + else + { + prob = 257; + } + + var bound = (_range >> K_NUM_BIT_MODEL_TOTAL_BITS) * _p[prob]; + if (_code < bound) + { + _range = bound; + _p[prob] += (ushort)((K_BIT_MODEL_TOTAL - _p[prob]) >> K_NUM_MOVE_BITS); + if (_range < K_TOP_VALUE) + { + _range <<= 8; + _code = (_code << 8) | _control[_controlPos++]; + } _prevByte = b; } else { - int prob; + _range -= bound; + _code -= bound; + _p[prob] -= (ushort)(_p[prob] >> K_NUM_MOVE_BITS); + if (_range < K_TOP_VALUE) + { + _range <<= 8; + _code = (_code << 8) | _control[_controlPos++]; + } + + uint dest; if (b == 0xE8) { - prob = _prevByte; - } - else if (b == 0xE9) - { - prob = 256; + dest = (uint)( + (_data1[_data1Pos++] << 24) + | (_data1[_data1Pos++] << 16) + | (_data1[_data1Pos++] << 8) + | _data1[_data1Pos++] + ); } else { - prob = 257; + dest = (uint)( + (_data2[_data2Pos++] << 24) + | (_data2[_data2Pos++] << 16) + | (_data2[_data2Pos++] << 8) + | _data2[_data2Pos++] + ); } + dest -= (uint)(_position + 4); - uint bound = (_range >> K_NUM_BIT_MODEL_TOTAL_BITS) * _p[prob]; - if (_code < bound) - { - _range = bound; - _p[prob] += (ushort)((K_BIT_MODEL_TOTAL - _p[prob]) >> K_NUM_MOVE_BITS); - if (_range < K_TOP_VALUE) - { - _range <<= 8; - _code = (_code << 8) | _control[_controlPos++]; - } - _prevByte = b; - } - else - { - _range -= bound; - _code -= bound; - _p[prob] -= (ushort)(_p[prob] >> K_NUM_MOVE_BITS); - if (_range < K_TOP_VALUE) - { - _range <<= 8; - _code = (_code << 8) | _control[_controlPos++]; - } - - uint dest; - if (b == 0xE8) - { - dest = (uint)( - (_data1[_data1Pos++] << 24) - | (_data1[_data1Pos++] << 16) - | (_data1[_data1Pos++] << 8) - | _data1[_data1Pos++] - ); - } - else - { - dest = (uint)( - (_data2[_data2Pos++] << 24) - | (_data2[_data2Pos++] << 16) - | (_data2[_data2Pos++] << 8) - | _data2[_data2Pos++] - ); - } - dest -= (uint)(_position + 4); - - _output[0] = (byte)dest; - _output[1] = (byte)(dest >> 8); - _output[2] = (byte)(dest >> 16); - _output[3] = (byte)(dest >> 24); - _outputOffset = 0; - _outputCount = 4; - } + _output[0] = (byte)dest; + _output[1] = (byte)(dest >> 8); + _output[2] = (byte)(dest >> 16); + _output[3] = (byte)(dest >> 24); + _outputOffset = 0; + _outputCount = 4; } } - - return size; } - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } + return size; + } - public override void SetLength(long value) - { - throw new NotSupportedException(); - } + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } - public override void Write(byte[] buffer, int offset, int count) - { - throw new NotSupportedException(); - } + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + public override void Write(byte[] buffer, int offset, int count) + { + throw new NotSupportedException(); } } diff --git a/src/SharpCompress/Compressors/Filters/BCJFilter.cs b/src/SharpCompress/Compressors/Filters/BCJFilter.cs index 57b025a8..416725db 100644 --- a/src/SharpCompress/Compressors/Filters/BCJFilter.cs +++ b/src/SharpCompress/Compressors/Filters/BCJFilter.cs @@ -1,125 +1,124 @@ -using System.IO; +using System.IO; -namespace SharpCompress.Compressors.Filters +namespace SharpCompress.Compressors.Filters; + +internal class BCJFilter : Filter { - internal class BCJFilter : Filter + private static readonly bool[] MASK_TO_ALLOWED_STATUS = { - private static readonly bool[] MASK_TO_ALLOWED_STATUS = + true, + true, + true, + false, + true, + false, + false, + false + }; + + private static readonly int[] MASK_TO_BIT_NUMBER = { 0, 1, 2, 2, 3, 3, 3, 3 }; + + private int _pos; + private int _prevMask; + + public BCJFilter(bool isEncoder, Stream baseStream) : base(isEncoder, baseStream, 5) + { + _pos = 5; + } + + private static bool Test86MsByte(byte b) + { + return b == 0x00 || b == 0xFF; + } + + protected override int Transform(byte[] buffer, int offset, int count) + { + var prevPos = offset - 1; + var end = offset + count - 5; + int i; + + for (i = offset; i <= end; ++i) { - true, - true, - true, - false, - true, - false, - false, - false - }; - - private static readonly int[] MASK_TO_BIT_NUMBER = { 0, 1, 2, 2, 3, 3, 3, 3 }; - - private int _pos; - private int _prevMask; - - public BCJFilter(bool isEncoder, Stream baseStream) : base(isEncoder, baseStream, 5) - { - _pos = 5; - } - - private static bool Test86MsByte(byte b) - { - return b == 0x00 || b == 0xFF; - } - - protected override int Transform(byte[] buffer, int offset, int count) - { - int prevPos = offset - 1; - int end = offset + count - 5; - int i; - - for (i = offset; i <= end; ++i) + if ((buffer[i] & 0xFE) != 0xE8) { - if ((buffer[i] & 0xFE) != 0xE8) - { - continue; - } - - prevPos = i - prevPos; - if ((prevPos & ~3) != 0) - { - // (unsigned)prevPos > 3 - _prevMask = 0; - } - else - { - _prevMask = (_prevMask << (prevPos - 1)) & 7; - if (_prevMask != 0) - { - if ( - !MASK_TO_ALLOWED_STATUS[_prevMask] - || Test86MsByte(buffer[i + 4 - MASK_TO_BIT_NUMBER[_prevMask]]) - ) - { - prevPos = i; - _prevMask = (_prevMask << 1) | 1; - continue; - } - } - } - - prevPos = i; - - if (Test86MsByte(buffer[i + 4])) - { - int src = - buffer[i + 1] - | (buffer[i + 2] << 8) - | (buffer[i + 3] << 16) - | (buffer[i + 4] << 24); - int dest; - while (true) - { - if (_isEncoder) - { - dest = src + (_pos + i - offset); - } - else - { - dest = src - (_pos + i - offset); - } - - if (_prevMask == 0) - { - break; - } - - int index = MASK_TO_BIT_NUMBER[_prevMask] * 8; - if (!Test86MsByte((byte)(dest >> (24 - index)))) - { - break; - } - - src = dest ^ ((1 << (32 - index)) - 1); - } - - buffer[i + 1] = (byte)dest; - buffer[i + 2] = (byte)(dest >> 8); - buffer[i + 3] = (byte)(dest >> 16); - buffer[i + 4] = (byte)(~(((dest >> 24) & 1) - 1)); - i += 4; - } - else - { - _prevMask = (_prevMask << 1) | 1; - } + continue; } prevPos = i - prevPos; - _prevMask = ((prevPos & ~3) != 0) ? 0 : _prevMask << (prevPos - 1); + if ((prevPos & ~3) != 0) + { + // (unsigned)prevPos > 3 + _prevMask = 0; + } + else + { + _prevMask = (_prevMask << (prevPos - 1)) & 7; + if (_prevMask != 0) + { + if ( + !MASK_TO_ALLOWED_STATUS[_prevMask] + || Test86MsByte(buffer[i + 4 - MASK_TO_BIT_NUMBER[_prevMask]]) + ) + { + prevPos = i; + _prevMask = (_prevMask << 1) | 1; + continue; + } + } + } - i -= offset; - _pos += i; - return i; + prevPos = i; + + if (Test86MsByte(buffer[i + 4])) + { + var src = + buffer[i + 1] + | (buffer[i + 2] << 8) + | (buffer[i + 3] << 16) + | (buffer[i + 4] << 24); + int dest; + while (true) + { + if (_isEncoder) + { + dest = src + (_pos + i - offset); + } + else + { + dest = src - (_pos + i - offset); + } + + if (_prevMask == 0) + { + break; + } + + var index = MASK_TO_BIT_NUMBER[_prevMask] * 8; + if (!Test86MsByte((byte)(dest >> (24 - index)))) + { + break; + } + + src = dest ^ ((1 << (32 - index)) - 1); + } + + buffer[i + 1] = (byte)dest; + buffer[i + 2] = (byte)(dest >> 8); + buffer[i + 3] = (byte)(dest >> 16); + buffer[i + 4] = (byte)(~(((dest >> 24) & 1) - 1)); + i += 4; + } + else + { + _prevMask = (_prevMask << 1) | 1; + } } + + prevPos = i - prevPos; + _prevMask = ((prevPos & ~3) != 0) ? 0 : _prevMask << (prevPos - 1); + + i -= offset; + _pos += i; + return i; } } diff --git a/src/SharpCompress/Compressors/Filters/BranchExecFilter.cs b/src/SharpCompress/Compressors/Filters/BranchExecFilter.cs index 6e8278cb..8dffc4d5 100644 --- a/src/SharpCompress/Compressors/Filters/BranchExecFilter.cs +++ b/src/SharpCompress/Compressors/Filters/BranchExecFilter.cs @@ -5,309 +5,326 @@ */ using System; -using System.Collections.Generic; using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace SharpCompress.Compressors.Filters +namespace SharpCompress.Compressors.Filters; + +[CLSCompliant(false)] +public sealed class BranchExecFilter { - [CLSCompliant(false)] - public sealed class BranchExecFilter + public enum Alignment : int { - public enum Alignment : int + ARCH_x86_ALIGNMENT = 1, + ARCH_PowerPC_ALIGNMENT = 4, + ARCH_IA64_ALIGNMENT = 16, + ARCH_ARM_ALIGNMENT = 4, + ARCH_ARMTHUMB_ALIGNMENT = 2, + ARCH_SPARC_ALIGNMENT = 4, + } + + public static void X86Converter(byte[] data, uint ip, ref uint state) + { + long i = 0; + long size = data.Length; + uint pos = 0; + var mask = state & 7; + if (size < 5) { - ARCH_x86_ALIGNMENT = 1, - ARCH_PowerPC_ALIGNMENT = 4, - ARCH_IA64_ALIGNMENT = 16, - ARCH_ARM_ALIGNMENT = 4, - ARCH_ARMTHUMB_ALIGNMENT = 2, - ARCH_SPARC_ALIGNMENT = 4, - } - - public static void X86Converter(byte[] data, UInt32 ip, ref UInt32 state) - { - long i = 0; - long size = data.Length; - UInt32 pos = 0; - UInt32 mask = state & 7; - if (size < 5) - return; - size -= 4; - ip += 5; - - for (; ; ) - { - i = pos; - - for (; i < size; i++) - { - if ((data[i] & 0xFE) == 0xE8) - { - break; - } - } - - UInt32 d = (UInt32)(i) - pos; - pos = (UInt32)i; - if (i >= size) - { - state = (d > 2 ? 0 : mask >> (int)d); - return; - } - if (d > 2) - { - mask = 0; - } - else - { - mask >>= (int)d; - if ( - mask != 0 - && ( - mask > 4 - || mask == 3 - || (((((data[(UInt32)(mask >> 1) + 1])) + 1) & 0xFE) == 0) - ) - ) - { - mask = (mask >> 1) | 4; - pos++; - continue; - } - } - - if ((((data[i + 4]) + 1) & 0xFE) == 0) - { - UInt32 inst = - ((UInt32)data[i + 4] << 24) - | ((UInt32)data[i + 3] << 16) - | ((UInt32)data[i + 2] << 8) - | ((UInt32)data[i + 1]); - UInt32 cur = ip + (UInt32)pos; - pos += 5; - - inst -= cur; - if (mask != 0) - { - UInt32 sh = (mask & 6) << 2; - if (((((((Byte)(inst >> (int)sh))) + 1) & 0xFE) == 0)) - { - inst ^= (((UInt32)0x100 << (int)sh) - 1); - inst -= cur; - } - mask = 0; - } - data[i + 1] = (Byte)inst; - data[i + 2] = (Byte)(inst >> 8); - data[i + 3] = (Byte)(inst >> 16); - data[i + 4] = (Byte)(0 - ((inst >> 24) & 1)); - } - else - { - mask = (mask >> 1) | 4; - pos++; - } - } - } - - public static void PowerPCConverter(byte[] data, UInt32 ip) - { - long i = 0; - long size = data.Length; - size &= ~(UInt32)3; - ip -= 4; - - for (; ; ) // infinite loop - { - for (; ; ) // infinite loop - { - if (i >= size) - return; - i += 4; - - if ((data[i - 4] & 0xFC) == 0x48 && (data[i - 1] & 3) == 1) - break; - } - { - UInt32 inst = BitConverter.ToUInt32(data, (int)i - 4); - - if (BitConverter.IsLittleEndian) - { - inst = Utility.SwapUINT32(inst); - } - - inst -= (UInt32)(ip + i); - inst &= 0x03FFFFFF; - inst |= 0x48000000; - - Utility.SetBigUInt32(ref data, inst, (i - 4)); - } - } - } - - public static void ARMConverter(byte[] data, UInt32 ip) - { - long i = 0; - long size = data.Length; - size &= ~(UInt32)3; - ip += 4; - - for (; ; ) // infinite loop - { - for (; ; ) // infinite loop - { - if (i >= size) - { - return; - } - - i += 4; - if (data[i - 1] == 0xEB) - break; - } - - UInt32 inst = BitConverter.ToUInt32(data, (int)i - 4); - inst <<= 2; - inst -= (UInt32)(ip + i); - inst >>= 2; - inst &= 0x00FFFFFF; - inst |= 0xEB000000; - - Utility.SetLittleUInt32(ref data, inst, i - 4); - } - } - - public static void ARMTConverter(byte[] data, UInt32 ip) - { - long i = 0; - long size = data.Length; - size &= ~(UInt32)1; - long lim = size - 4; - - for (; ; ) - { - UInt32 b1; - for (; ; ) - { - UInt32 b3; - if (i > lim) - return; - b1 = data[i + 1]; - b3 = data[i + 3]; - i += 2; - b1 ^= 8; - if ((b3 & b1) >= 0xF8) - break; - } - - UInt32 inst = - ((UInt32)b1 << 19) - + (((UInt32)data[i + 1] & 0x7) << 8) - + (((UInt32)data[i - 2] << 11)) - + (data[i]); - - i += 2; - - UInt32 cur = ((UInt32)(ip + i)) >> 1; - inst -= cur; - - data[i - 4] = (Byte)(inst >> 11); - data[i - 3] = (Byte)(0xF0 | ((inst >> 19) & 0x7)); - data[i - 2] = (Byte)inst; - data[i - 1] = (Byte)(0xF8 | (inst >> 8)); - } - } - - public static void IA64Converter(byte[] data, UInt32 ip) - { - UInt32 i = 0; - long size = data.Length; - if (size < 16) - throw new InvalidDataException("Unexpected data size"); - size -= 16; - - do - { - UInt32 m = ((UInt32)0x334B0000 >> (data[i] & 0x1E)) & 3; - if (m != 0) - { - m++; - do - { - UInt32 iterator = (UInt32)((i + (m * 5) - 8)); - if ( - ((data[iterator + 3] >> (int)m) & 15) == 5 - && ( - ((data[iterator - 1] | ((UInt32)data[iterator] << 8)) >> (int)m) - & 0x70 - ) == 0 - ) - { - UInt32 raw = BitConverter.ToUInt32(data, (int)iterator); - UInt32 inst = raw >> (int)m; - inst = (inst & 0xFFFFF) | ((inst & (1 << 23)) >> 3); - - inst <<= 4; - inst -= (ip + (UInt32)i); - inst >>= 4; - - inst &= 0x1FFFFF; - inst += 0x700000; - inst &= 0x8FFFFF; - raw &= ~((UInt32)0x8FFFFF << (int)m); - raw |= (inst << (int)m); - - Utility.SetLittleUInt32(ref data, raw, iterator); - } - } while (++m <= 4); - } - i += 16; - } while (i <= size); return; } - public static void SPARCConverter(byte[] data, UInt32 ip) - { - long i = 0; - long size = data.Length; - size &= ~(UInt32)3; - ip -= 4; + size -= 4; + ip += 5; + for (; ; ) + { + i = pos; + + for (; i < size; i++) + { + if ((data[i] & 0xFE) == 0xE8) + { + break; + } + } + + var d = (uint)(i) - pos; + pos = (uint)i; + if (i >= size) + { + state = (d > 2 ? 0 : mask >> (int)d); + return; + } + if (d > 2) + { + mask = 0; + } + else + { + mask >>= (int)d; + if ( + mask != 0 + && ( + mask > 4 + || mask == 3 + || (((((data[(mask >> 1) + 1])) + 1) & 0xFE) == 0) + ) + ) + { + mask = (mask >> 1) | 4; + pos++; + continue; + } + } + + if ((((data[i + 4]) + 1) & 0xFE) == 0) + { + var inst = + ((uint)data[i + 4] << 24) + | ((uint)data[i + 3] << 16) + | ((uint)data[i + 2] << 8) + | data[i + 1]; + var cur = ip + pos; + pos += 5; + + inst -= cur; + if (mask != 0) + { + var sh = (mask & 6) << 2; + if (((((((byte)(inst >> (int)sh))) + 1) & 0xFE) == 0)) + { + inst ^= (((uint)0x100 << (int)sh) - 1); + inst -= cur; + } + mask = 0; + } + data[i + 1] = (byte)inst; + data[i + 2] = (byte)(inst >> 8); + data[i + 3] = (byte)(inst >> 16); + data[i + 4] = (byte)(0 - ((inst >> 24) & 1)); + } + else + { + mask = (mask >> 1) | 4; + pos++; + } + } + } + + public static void PowerPCConverter(byte[] data, uint ip) + { + long i = 0; + long size = data.Length; + size &= ~(uint)3; + ip -= 4; + + for (; ; ) // infinite loop + { for (; ; ) // infinite loop { - for (; ; ) // infinite loop + if (i >= size) { - if (i >= size) - return; - - i += 4; - if ( - (data[i - 4] == 0x40 && (data[i - 3] & 0xC0) == 0) - || (data[i - 4] == 0x7F && (data[i - 3] >= 0xC0)) - ) - break; + return; } - UInt32 inst = BitConverter.ToUInt32(data, (int)i - 4); + i += 4; + + if ((data[i - 4] & 0xFC) == 0x48 && (data[i - 1] & 3) == 1) + { + break; + } + } + { + var inst = BitConverter.ToUInt32(data, (int)i - 4); if (BitConverter.IsLittleEndian) { inst = Utility.SwapUINT32(inst); } - inst <<= 2; - inst -= (UInt32)(ip + i); - - inst &= 0x01FFFFFF; - inst -= (UInt32)1 << 24; - inst ^= 0xFF000000; - inst >>= 2; - inst |= 0x40000000; + inst -= (uint)(ip + i); + inst &= 0x03FFFFFF; + inst |= 0x48000000; Utility.SetBigUInt32(ref data, inst, (i - 4)); } } } + + public static void ARMConverter(byte[] data, uint ip) + { + long i = 0; + long size = data.Length; + size &= ~(uint)3; + ip += 4; + + for (; ; ) // infinite loop + { + for (; ; ) // infinite loop + { + if (i >= size) + { + return; + } + + i += 4; + if (data[i - 1] == 0xEB) + { + break; + } + } + + var inst = BitConverter.ToUInt32(data, (int)i - 4); + inst <<= 2; + inst -= (uint)(ip + i); + inst >>= 2; + inst &= 0x00FFFFFF; + inst |= 0xEB000000; + + Utility.SetLittleUInt32(ref data, inst, i - 4); + } + } + + public static void ARMTConverter(byte[] data, uint ip) + { + long i = 0; + long size = data.Length; + size &= ~(uint)1; + var lim = size - 4; + + for (; ; ) + { + uint b1; + for (; ; ) + { + uint b3; + if (i > lim) + { + return; + } + + b1 = data[i + 1]; + b3 = data[i + 3]; + i += 2; + b1 ^= 8; + if ((b3 & b1) >= 0xF8) + { + break; + } + } + + var inst = + (b1 << 19) + + (((uint)data[i + 1] & 0x7) << 8) + + (((uint)data[i - 2] << 11)) + + (data[i]); + + i += 2; + + var cur = ((uint)(ip + i)) >> 1; + inst -= cur; + + data[i - 4] = (byte)(inst >> 11); + data[i - 3] = (byte)(0xF0 | ((inst >> 19) & 0x7)); + data[i - 2] = (byte)inst; + data[i - 1] = (byte)(0xF8 | (inst >> 8)); + } + } + + public static void IA64Converter(byte[] data, uint ip) + { + uint i = 0; + long size = data.Length; + if (size < 16) + { + throw new InvalidDataException("Unexpected data size"); + } + + size -= 16; + + do + { + var m = ((uint)0x334B0000 >> (data[i] & 0x1E)) & 3; + if (m != 0) + { + m++; + do + { + var iterator = (i + (m * 5) - 8); + if ( + ((data[iterator + 3] >> (int)m) & 15) == 5 + && ( + ((data[iterator - 1] | ((uint)data[iterator] << 8)) >> (int)m) + & 0x70 + ) == 0 + ) + { + var raw = BitConverter.ToUInt32(data, (int)iterator); + var inst = raw >> (int)m; + inst = (inst & 0xFFFFF) | ((inst & (1 << 23)) >> 3); + + inst <<= 4; + inst -= (ip + i); + inst >>= 4; + + inst &= 0x1FFFFF; + inst += 0x700000; + inst &= 0x8FFFFF; + raw &= ~((uint)0x8FFFFF << (int)m); + raw |= (inst << (int)m); + + Utility.SetLittleUInt32(ref data, raw, iterator); + } + } while (++m <= 4); + } + i += 16; + } while (i <= size); + return; + } + + public static void SPARCConverter(byte[] data, uint ip) + { + long i = 0; + long size = data.Length; + size &= ~(uint)3; + ip -= 4; + + for (; ; ) // infinite loop + { + for (; ; ) // infinite loop + { + if (i >= size) + { + return; + } + + i += 4; + if ( + (data[i - 4] == 0x40 && (data[i - 3] & 0xC0) == 0) + || (data[i - 4] == 0x7F && (data[i - 3] >= 0xC0)) + ) + { + break; + } + } + + var inst = BitConverter.ToUInt32(data, (int)i - 4); + + if (BitConverter.IsLittleEndian) + { + inst = Utility.SwapUINT32(inst); + } + + inst <<= 2; + inst -= (uint)(ip + i); + + inst &= 0x01FFFFFF; + inst -= (uint)1 << 24; + inst ^= 0xFF000000; + inst >>= 2; + inst |= 0x40000000; + + Utility.SetBigUInt32(ref data, inst, (i - 4)); + } + } } diff --git a/src/SharpCompress/Compressors/Filters/Filter.cs b/src/SharpCompress/Compressors/Filters/Filter.cs index 1ee8c076..d7f183f9 100644 --- a/src/SharpCompress/Compressors/Filters/Filter.cs +++ b/src/SharpCompress/Compressors/Filters/Filter.cs @@ -1,158 +1,157 @@ -using System; +using System; using System.IO; -namespace SharpCompress.Compressors.Filters +namespace SharpCompress.Compressors.Filters; + +internal abstract class Filter : Stream { - internal abstract class Filter : Stream + protected bool _isEncoder; + protected Stream _baseStream; + + private readonly byte[] _tail; + private readonly byte[] _window; + private int _transformed; + private int _read; + private bool _endReached; + private bool _isDisposed; + + protected Filter(bool isEncoder, Stream baseStream, int lookahead) { - protected bool _isEncoder; - protected Stream _baseStream; + _isEncoder = isEncoder; + _baseStream = baseStream; + _tail = new byte[lookahead - 1]; + _window = new byte[_tail.Length * 2]; + } - private readonly byte[] _tail; - private readonly byte[] _window; - private int _transformed; - private int _read; - private bool _endReached; - private bool _isDisposed; - - protected Filter(bool isEncoder, Stream baseStream, int lookahead) + protected override void Dispose(bool disposing) + { + if (_isDisposed) { - _isEncoder = isEncoder; - _baseStream = baseStream; - _tail = new byte[lookahead - 1]; - _window = new byte[_tail.Length * 2]; + return; } + _isDisposed = true; + base.Dispose(disposing); + _baseStream.Dispose(); + } - protected override void Dispose(bool disposing) + public override bool CanRead => !_isEncoder; + + public override bool CanSeek => false; + + public override bool CanWrite => _isEncoder; + + public override void Flush() + { + throw new NotSupportedException(); + } + + public override long Length => _baseStream.Length; + + public override long Position + { + get => _baseStream.Position; + set => throw new NotSupportedException(); + } + + public override int Read(byte[] buffer, int offset, int count) + { + var size = 0; + + if (_transformed > 0) { - if (_isDisposed) + var copySize = _transformed; + if (copySize > count) { - return; + copySize = count; } - _isDisposed = true; - base.Dispose(disposing); - _baseStream.Dispose(); + Buffer.BlockCopy(_tail, 0, buffer, offset, copySize); + _transformed -= copySize; + _read -= copySize; + offset += copySize; + count -= copySize; + size += copySize; + Buffer.BlockCopy(_tail, copySize, _tail, 0, _read); } - - public override bool CanRead => !_isEncoder; - - public override bool CanSeek => false; - - public override bool CanWrite => _isEncoder; - - public override void Flush() + if (count == 0) { - throw new NotSupportedException(); - } - - public override long Length => _baseStream.Length; - - public override long Position - { - get => _baseStream.Position; - set => throw new NotSupportedException(); - } - - public override int Read(byte[] buffer, int offset, int count) - { - int size = 0; - - if (_transformed > 0) - { - int copySize = _transformed; - if (copySize > count) - { - copySize = count; - } - Buffer.BlockCopy(_tail, 0, buffer, offset, copySize); - _transformed -= copySize; - _read -= copySize; - offset += copySize; - count -= copySize; - size += copySize; - Buffer.BlockCopy(_tail, copySize, _tail, 0, _read); - } - if (count == 0) - { - return size; - } - - int inSize = _read; - if (inSize > count) - { - inSize = count; - } - Buffer.BlockCopy(_tail, 0, buffer, offset, inSize); - _read -= inSize; - Buffer.BlockCopy(_tail, inSize, _tail, 0, _read); - while (!_endReached && inSize < count) - { - int baseRead = _baseStream.Read(buffer, offset + inSize, count - inSize); - inSize += baseRead; - if (baseRead == 0) - { - _endReached = true; - } - } - while (!_endReached && _read < _tail.Length) - { - int baseRead = _baseStream.Read(_tail, _read, _tail.Length - _read); - _read += baseRead; - if (baseRead == 0) - { - _endReached = true; - } - } - - if (inSize > _tail.Length) - { - _transformed = Transform(buffer, offset, inSize); - offset += _transformed; - count -= _transformed; - size += _transformed; - inSize -= _transformed; - _transformed = 0; - } - - if (count == 0) - { - return size; - } - - Buffer.BlockCopy(buffer, offset, _window, 0, inSize); - Buffer.BlockCopy(_tail, 0, _window, inSize, _read); - if (inSize + _read > _tail.Length) - { - _transformed = Transform(_window, 0, inSize + _read); - } - else - { - _transformed = inSize + _read; - } - Buffer.BlockCopy(_window, 0, buffer, offset, inSize); - Buffer.BlockCopy(_window, inSize, _tail, 0, _read); - size += inSize; - _transformed -= inSize; - return size; } - public override long Seek(long offset, SeekOrigin origin) + var inSize = _read; + if (inSize > count) { - throw new NotSupportedException(); + inSize = count; + } + Buffer.BlockCopy(_tail, 0, buffer, offset, inSize); + _read -= inSize; + Buffer.BlockCopy(_tail, inSize, _tail, 0, _read); + while (!_endReached && inSize < count) + { + var baseRead = _baseStream.Read(buffer, offset + inSize, count - inSize); + inSize += baseRead; + if (baseRead == 0) + { + _endReached = true; + } + } + while (!_endReached && _read < _tail.Length) + { + var baseRead = _baseStream.Read(_tail, _read, _tail.Length - _read); + _read += baseRead; + if (baseRead == 0) + { + _endReached = true; + } } - public override void SetLength(long value) + if (inSize > _tail.Length) { - throw new NotSupportedException(); + _transformed = Transform(buffer, offset, inSize); + offset += _transformed; + count -= _transformed; + size += _transformed; + inSize -= _transformed; + _transformed = 0; } - public override void Write(byte[] buffer, int offset, int count) + if (count == 0) { - Transform(buffer, offset, count); - _baseStream.Write(buffer, offset, count); + return size; } - protected abstract int Transform(byte[] buffer, int offset, int count); + Buffer.BlockCopy(buffer, offset, _window, 0, inSize); + Buffer.BlockCopy(_tail, 0, _window, inSize, _read); + if (inSize + _read > _tail.Length) + { + _transformed = Transform(_window, 0, inSize + _read); + } + else + { + _transformed = inSize + _read; + } + Buffer.BlockCopy(_window, 0, buffer, offset, inSize); + Buffer.BlockCopy(_window, inSize, _tail, 0, _read); + size += inSize; + _transformed -= inSize; + + return size; } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } + + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + public override void Write(byte[] buffer, int offset, int count) + { + Transform(buffer, offset, count); + _baseStream.Write(buffer, offset, count); + } + + protected abstract int Transform(byte[] buffer, int offset, int count); } diff --git a/src/SharpCompress/Compressors/LZMA/Bcj2DecoderStream.cs b/src/SharpCompress/Compressors/LZMA/Bcj2DecoderStream.cs index 649801a3..fe66d4cd 100644 --- a/src/SharpCompress/Compressors/LZMA/Bcj2DecoderStream.cs +++ b/src/SharpCompress/Compressors/LZMA/Bcj2DecoderStream.cs @@ -1,280 +1,263 @@ -using System; +using System; using System.Collections.Generic; using System.IO; -namespace SharpCompress.Compressors.LZMA +namespace SharpCompress.Compressors.LZMA; + +internal class Bcj2DecoderStream : DecoderStream2 { - internal class Bcj2DecoderStream : DecoderStream2 + private const int K_NUM_TOP_BITS = 24; + private const uint K_TOP_VALUE = (1 << K_NUM_TOP_BITS); + + private class RangeDecoder { - private const int K_NUM_TOP_BITS = 24; - private const uint K_TOP_VALUE = (1 << K_NUM_TOP_BITS); + internal readonly Stream _mStream; + internal uint _range; + internal uint _code; - private class RangeDecoder + public RangeDecoder(Stream stream) { - internal readonly Stream _mStream; - internal uint _range; - internal uint _code; - - public RangeDecoder(Stream stream) + _mStream = stream; + _range = 0xFFFFFFFF; + for (var i = 0; i < 5; i++) { - _mStream = stream; - _range = 0xFFFFFFFF; - for (int i = 0; i < 5; i++) - { - _code = (_code << 8) | ReadByte(); - } - } - - public byte ReadByte() - { - int bt = _mStream.ReadByte(); - if (bt < 0) - { - throw new EndOfStreamException(); - } - - return (byte)bt; - } - - public void Dispose() - { - _mStream.Dispose(); + _code = (_code << 8) | ReadByte(); } } - private class StatusDecoder + public byte ReadByte() { - private const int NUM_MOVE_BITS = 5; - - private const int K_NUM_BIT_MODEL_TOTAL_BITS = 11; - private const uint K_BIT_MODEL_TOTAL = 1u << K_NUM_BIT_MODEL_TOTAL_BITS; - - private uint _prob; - - public StatusDecoder() + var bt = _mStream.ReadByte(); + if (bt < 0) { - _prob = K_BIT_MODEL_TOTAL / 2; + throw new EndOfStreamException(); } - private void UpdateModel(uint symbol) - { - /* - Prob -= (Prob + ((symbol - 1) & ((1 << numMoveBits) - 1))) >> numMoveBits; - Prob += (1 - symbol) << (kNumBitModelTotalBits - numMoveBits); - */ - if (symbol == 0) - { - _prob += (K_BIT_MODEL_TOTAL - _prob) >> NUM_MOVE_BITS; - } - else - { - _prob -= (_prob) >> NUM_MOVE_BITS; - } - } + return (byte)bt; + } - public uint Decode(RangeDecoder decoder) + public void Dispose() + { + _mStream.Dispose(); + } + } + + private class StatusDecoder + { + private const int NUM_MOVE_BITS = 5; + + private const int K_NUM_BIT_MODEL_TOTAL_BITS = 11; + private const uint K_BIT_MODEL_TOTAL = 1u << K_NUM_BIT_MODEL_TOTAL_BITS; + + private uint _prob; + + public StatusDecoder() + { + _prob = K_BIT_MODEL_TOTAL / 2; + } + + public uint Decode(RangeDecoder decoder) + { + var newBound = (decoder._range >> K_NUM_BIT_MODEL_TOTAL_BITS) * _prob; + if (decoder._code < newBound) { - uint newBound = (decoder._range >> K_NUM_BIT_MODEL_TOTAL_BITS) * _prob; - if (decoder._code < newBound) - { - decoder._range = newBound; - _prob += (K_BIT_MODEL_TOTAL - _prob) >> NUM_MOVE_BITS; - if (decoder._range < K_TOP_VALUE) - { - decoder._code = (decoder._code << 8) | decoder.ReadByte(); - decoder._range <<= 8; - } - return 0; - } - decoder._range -= newBound; - decoder._code -= newBound; - _prob -= _prob >> NUM_MOVE_BITS; + decoder._range = newBound; + _prob += (K_BIT_MODEL_TOTAL - _prob) >> NUM_MOVE_BITS; if (decoder._range < K_TOP_VALUE) { decoder._code = (decoder._code << 8) | decoder.ReadByte(); decoder._range <<= 8; } - return 1; - } - } - - private readonly Stream _mMainStream; - private readonly Stream _mCallStream; - private readonly Stream _mJumpStream; - private readonly RangeDecoder _mRangeDecoder; - private readonly StatusDecoder[] _mStatusDecoder; - private long _mWritten; - private readonly IEnumerator _mIter; - private bool _mFinished; - private bool _isDisposed; - - public Bcj2DecoderStream(Stream[] streams, byte[] info, long limit) - { - if (info != null && info.Length > 0) - { - throw new NotSupportedException(); - } - - if (streams.Length != 4) - { - throw new NotSupportedException(); - } - - _mMainStream = streams[0]; - _mCallStream = streams[1]; - _mJumpStream = streams[2]; - _mRangeDecoder = new RangeDecoder(streams[3]); - - _mStatusDecoder = new StatusDecoder[256 + 2]; - for (int i = 0; i < _mStatusDecoder.Length; i++) - { - _mStatusDecoder[i] = new StatusDecoder(); - } - - _mIter = Run().GetEnumerator(); - } - - protected override void Dispose(bool disposing) - { - if (_isDisposed) - { - return; - } - _isDisposed = true; - base.Dispose(disposing); - _mMainStream.Dispose(); - _mCallStream.Dispose(); - _mJumpStream.Dispose(); - } - - private static bool IsJcc(byte b0, byte b1) - { - return b0 == 0x0F && (b1 & 0xF0) == 0x80; - } - - private static bool IsJ(byte b0, byte b1) - { - return (b1 & 0xFE) == 0xE8 || IsJcc(b0, b1); - } - - private static int GetIndex(byte b0, byte b1) - { - if (b1 == 0xE8) - { - return b0; - } - if (b1 == 0xE9) - { - return 256; - } - return 257; - } - - public override int Read(byte[] buffer, int offset, int count) - { - if (count == 0 || _mFinished) - { return 0; } - - for (int i = 0; i < count; i++) + decoder._range -= newBound; + decoder._code -= newBound; + _prob -= _prob >> NUM_MOVE_BITS; + if (decoder._range < K_TOP_VALUE) { - if (!_mIter.MoveNext()) - { - _mFinished = true; - return i; - } - - buffer[offset + i] = _mIter.Current; + decoder._code = (decoder._code << 8) | decoder.ReadByte(); + decoder._range <<= 8; } + return 1; + } + } - return count; + private readonly Stream _mMainStream; + private readonly Stream _mCallStream; + private readonly Stream _mJumpStream; + private readonly RangeDecoder _mRangeDecoder; + private readonly StatusDecoder[] _mStatusDecoder; + private long _mWritten; + private readonly IEnumerator _mIter; + private bool _mFinished; + private bool _isDisposed; + + public Bcj2DecoderStream(Stream[] streams, byte[] info, long limit) + { + if (info != null && info.Length > 0) + { + throw new NotSupportedException(); } - public override int ReadByte() + if (streams.Length != 4) { - if (_mFinished) - { - return -1; - } + throw new NotSupportedException(); + } + _mMainStream = streams[0]; + _mCallStream = streams[1]; + _mJumpStream = streams[2]; + _mRangeDecoder = new RangeDecoder(streams[3]); + + _mStatusDecoder = new StatusDecoder[256 + 2]; + for (var i = 0; i < _mStatusDecoder.Length; i++) + { + _mStatusDecoder[i] = new StatusDecoder(); + } + + _mIter = Run().GetEnumerator(); + } + + protected override void Dispose(bool disposing) + { + if (_isDisposed) + { + return; + } + _isDisposed = true; + base.Dispose(disposing); + _mMainStream.Dispose(); + _mCallStream.Dispose(); + _mJumpStream.Dispose(); + } + + private static bool IsJcc(byte b0, byte b1) + { + return b0 == 0x0F && (b1 & 0xF0) == 0x80; + } + + private static bool IsJ(byte b0, byte b1) + { + return (b1 & 0xFE) == 0xE8 || IsJcc(b0, b1); + } + + private static int GetIndex(byte b0, byte b1) + { + if (b1 == 0xE8) + { + return b0; + } + if (b1 == 0xE9) + { + return 256; + } + return 257; + } + + public override int Read(byte[] buffer, int offset, int count) + { + if (count == 0 || _mFinished) + { + return 0; + } + + for (var i = 0; i < count; i++) + { if (!_mIter.MoveNext()) { _mFinished = true; - return -1; + return i; } - return _mIter.Current; + buffer[offset + i] = _mIter.Current; } - public IEnumerable Run() + return count; + } + + public override int ReadByte() + { + if (_mFinished) { - const uint kBurstSize = (1u << 18); + return -1; + } - byte prevByte = 0; - uint processedBytes = 0; - for (; ; ) + if (!_mIter.MoveNext()) + { + _mFinished = true; + return -1; + } + + return _mIter.Current; + } + + public IEnumerable Run() + { + const uint kBurstSize = (1u << 18); + + byte prevByte = 0; + uint processedBytes = 0; + for (; ; ) + { + byte b = 0; + uint i; + for (i = 0; i < kBurstSize; i++) { - byte b = 0; - uint i; - for (i = 0; i < kBurstSize; i++) + var tmp = _mMainStream.ReadByte(); + if (tmp < 0) { - int tmp = _mMainStream.ReadByte(); - if (tmp < 0) + yield break; + } + + b = (byte)tmp; + _mWritten++; + yield return b; + if (IsJ(prevByte, b)) + { + break; + } + + prevByte = b; + } + + processedBytes += i; + if (i == kBurstSize) + { + continue; + } + + if (_mStatusDecoder[GetIndex(prevByte, b)].Decode(_mRangeDecoder) == 1) + { + var s = (b == 0xE8) ? _mCallStream : _mJumpStream; + + uint src = 0; + for (i = 0; i < 4; i++) + { + var b0 = s.ReadByte(); + if (b0 < 0) { - yield break; + throw new EndOfStreamException(); } - b = (byte)tmp; - _mWritten++; - yield return b; - if (IsJ(prevByte, b)) - { - break; - } - - prevByte = b; + src <<= 8; + src |= (uint)b0; } - processedBytes += i; - if (i == kBurstSize) - { - continue; - } - - if (_mStatusDecoder[GetIndex(prevByte, b)].Decode(_mRangeDecoder) == 1) - { - Stream s = (b == 0xE8) ? _mCallStream : _mJumpStream; - - uint src = 0; - for (i = 0; i < 4; i++) - { - int b0 = s.ReadByte(); - if (b0 < 0) - { - throw new EndOfStreamException(); - } - - src <<= 8; - src |= (uint)b0; - } - - uint dest = src - (uint)(_mWritten + 4); - _mWritten++; - yield return (byte)dest; - _mWritten++; - yield return (byte)(dest >> 8); - _mWritten++; - yield return (byte)(dest >> 16); - _mWritten++; - yield return (byte)(dest >> 24); - prevByte = (byte)(dest >> 24); - processedBytes += 4; - } - else - { - prevByte = b; - } + var dest = src - (uint)(_mWritten + 4); + _mWritten++; + yield return (byte)dest; + _mWritten++; + yield return (byte)(dest >> 8); + _mWritten++; + yield return (byte)(dest >> 16); + _mWritten++; + yield return (byte)(dest >> 24); + prevByte = (byte)(dest >> 24); + processedBytes += 4; + } + else + { + prevByte = b; } } } diff --git a/src/SharpCompress/Compressors/LZMA/BitVector.cs b/src/SharpCompress/Compressors/LZMA/BitVector.cs index 5995512a..5b40536d 100644 --- a/src/SharpCompress/Compressors/LZMA/BitVector.cs +++ b/src/SharpCompress/Compressors/LZMA/BitVector.cs @@ -1,100 +1,99 @@ -using System; +using System; using System.Collections.Generic; using System.Text; -namespace SharpCompress.Compressors.LZMA +namespace SharpCompress.Compressors.LZMA; + +internal class BitVector { - internal class BitVector + private readonly uint[] _mBits; + + public BitVector(int length) { - private readonly uint[] _mBits; + Length = length; + _mBits = new uint[(length + 31) >> 5]; + } - public BitVector(int length) + public BitVector(int length, bool initValue) + { + Length = length; + _mBits = new uint[(length + 31) >> 5]; + + if (initValue) { - Length = length; - _mBits = new uint[(length + 31) >> 5]; - } - - public BitVector(int length, bool initValue) - { - Length = length; - _mBits = new uint[(length + 31) >> 5]; - - if (initValue) + for (var i = 0; i < _mBits.Length; i++) { - for (int i = 0; i < _mBits.Length; i++) - { - _mBits[i] = ~0u; - } + _mBits[i] = ~0u; } } - - public BitVector(List bits) : this(bits.Count) - { - for (int i = 0; i < bits.Count; i++) - { - if (bits[i]) - { - SetBit(i); - } - } - } - - public bool[] ToArray() - { - bool[] bits = new bool[Length]; - for (int i = 0; i < bits.Length; i++) - { - bits[i] = this[i]; - } - return bits; - } - - public int Length { get; } - - public bool this[int index] - { - get - { - if (index < 0 || index >= Length) - { - throw new ArgumentOutOfRangeException(nameof(index)); - } - - return (_mBits[index >> 5] & (1u << (index & 31))) != 0; - } - } - - public void SetBit(int index) - { - if (index < 0 || index >= Length) - { - throw new ArgumentOutOfRangeException(nameof(index)); - } - - _mBits[index >> 5] |= 1u << (index & 31); - } - - internal bool GetAndSet(int index) - { - if (index < 0 || index >= Length) - { - throw new ArgumentOutOfRangeException(nameof(index)); - } - - uint bits = _mBits[index >> 5]; - uint mask = 1u << (index & 31); - _mBits[index >> 5] |= mask; - return (bits & mask) != 0; - } - - public override string ToString() - { - StringBuilder sb = new StringBuilder(Length); - for (int i = 0; i < Length; i++) - { - sb.Append(this[i] ? 'x' : '.'); - } - return sb.ToString(); - } + } + + public BitVector(List bits) : this(bits.Count) + { + for (var i = 0; i < bits.Count; i++) + { + if (bits[i]) + { + SetBit(i); + } + } + } + + public bool[] ToArray() + { + var bits = new bool[Length]; + for (var i = 0; i < bits.Length; i++) + { + bits[i] = this[i]; + } + return bits; + } + + public int Length { get; } + + public bool this[int index] + { + get + { + if (index < 0 || index >= Length) + { + throw new ArgumentOutOfRangeException(nameof(index)); + } + + return (_mBits[index >> 5] & (1u << (index & 31))) != 0; + } + } + + public void SetBit(int index) + { + if (index < 0 || index >= Length) + { + throw new ArgumentOutOfRangeException(nameof(index)); + } + + _mBits[index >> 5] |= 1u << (index & 31); + } + + internal bool GetAndSet(int index) + { + if (index < 0 || index >= Length) + { + throw new ArgumentOutOfRangeException(nameof(index)); + } + + var bits = _mBits[index >> 5]; + var mask = 1u << (index & 31); + _mBits[index >> 5] |= mask; + return (bits & mask) != 0; + } + + public override string ToString() + { + var sb = new StringBuilder(Length); + for (var i = 0; i < Length; i++) + { + sb.Append(this[i] ? 'x' : '.'); + } + return sb.ToString(); } } diff --git a/src/SharpCompress/Compressors/LZMA/CRC.cs b/src/SharpCompress/Compressors/LZMA/CRC.cs index 478cb944..cccce883 100644 --- a/src/SharpCompress/Compressors/LZMA/CRC.cs +++ b/src/SharpCompress/Compressors/LZMA/CRC.cs @@ -1,89 +1,88 @@ -using System; +using System; using System.IO; -namespace SharpCompress.Compressors.LZMA +namespace SharpCompress.Compressors.LZMA; + +internal static class Crc { - internal static class Crc + internal const uint INIT_CRC = 0xFFFFFFFF; + internal static readonly uint[] TABLE = new uint[4 * 256]; + + static Crc() { - internal const uint INIT_CRC = 0xFFFFFFFF; - internal static readonly uint[] TABLE = new uint[4 * 256]; + const uint kCrcPoly = 0xEDB88320; - static Crc() + for (uint i = 0; i < 256; i++) { - const uint kCrcPoly = 0xEDB88320; - - for (uint i = 0; i < 256; i++) + var r = i; + for (var j = 0; j < 8; j++) { - uint r = i; - for (int j = 0; j < 8; j++) - { - r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1)); - } - - TABLE[i] = r; + r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1)); } - for (uint i = 256; i < TABLE.Length; i++) - { - uint r = TABLE[i - 256]; - TABLE[i] = TABLE[r & 0xFF] ^ (r >> 8); - } + TABLE[i] = r; } - public static uint From(Stream stream, long length) + for (uint i = 256; i < TABLE.Length; i++) { - uint crc = INIT_CRC; - byte[] buffer = new byte[Math.Min(length, 4 << 10)]; - while (length > 0) - { - int delta = stream.Read(buffer, 0, (int)Math.Min(length, buffer.Length)); - if (delta == 0) - { - throw new EndOfStreamException(); - } - crc = Update(crc, buffer, 0, delta); - length -= delta; - } - return Finish(crc); - } - - public static uint Finish(uint crc) - { - return ~crc; - } - - public static uint Update(uint crc, byte bt) - { - return TABLE[(crc & 0xFF) ^ bt] ^ (crc >> 8); - } - - public static uint Update(uint crc, uint value) - { - crc ^= value; - return TABLE[0x300 + (crc & 0xFF)] - ^ TABLE[0x200 + ((crc >> 8) & 0xFF)] - ^ TABLE[0x100 + ((crc >> 16) & 0xFF)] - ^ TABLE[0x000 + (crc >> 24)]; - } - - public static uint Update(uint crc, ulong value) - { - return Update(Update(crc, (uint)value), (uint)(value >> 32)); - } - - public static uint Update(uint crc, long value) - { - return Update(crc, (ulong)value); - } - - public static uint Update(uint crc, byte[] buffer, int offset, int length) - { - for (int i = 0; i < length; i++) - { - crc = Update(crc, buffer[offset + i]); - } - - return crc; + var r = TABLE[i - 256]; + TABLE[i] = TABLE[r & 0xFF] ^ (r >> 8); } } + + public static uint From(Stream stream, long length) + { + var crc = INIT_CRC; + var buffer = new byte[Math.Min(length, 4 << 10)]; + while (length > 0) + { + var delta = stream.Read(buffer, 0, (int)Math.Min(length, buffer.Length)); + if (delta == 0) + { + throw new EndOfStreamException(); + } + crc = Update(crc, buffer, 0, delta); + length -= delta; + } + return Finish(crc); + } + + public static uint Finish(uint crc) + { + return ~crc; + } + + public static uint Update(uint crc, byte bt) + { + return TABLE[(crc & 0xFF) ^ bt] ^ (crc >> 8); + } + + public static uint Update(uint crc, uint value) + { + crc ^= value; + return TABLE[0x300 + (crc & 0xFF)] + ^ TABLE[0x200 + ((crc >> 8) & 0xFF)] + ^ TABLE[0x100 + ((crc >> 16) & 0xFF)] + ^ TABLE[0x000 + (crc >> 24)]; + } + + public static uint Update(uint crc, ulong value) + { + return Update(Update(crc, (uint)value), (uint)(value >> 32)); + } + + public static uint Update(uint crc, long value) + { + return Update(crc, (ulong)value); + } + + public static uint Update(uint crc, byte[] buffer, int offset, int length) + { + for (var i = 0; i < length; i++) + { + crc = Update(crc, buffer[offset + i]); + } + + return crc; + } } diff --git a/src/SharpCompress/Compressors/LZMA/DecoderStream.cs b/src/SharpCompress/Compressors/LZMA/DecoderStream.cs index 084e2a5f..11c62528 100644 --- a/src/SharpCompress/Compressors/LZMA/DecoderStream.cs +++ b/src/SharpCompress/Compressors/LZMA/DecoderStream.cs @@ -1,231 +1,228 @@ -using System; +using System; using System.IO; using SharpCompress.Common.SevenZip; using SharpCompress.Compressors.LZMA.Utilites; using SharpCompress.IO; -namespace SharpCompress.Compressors.LZMA +namespace SharpCompress.Compressors.LZMA; + +internal abstract class DecoderStream2 : Stream { - internal abstract class DecoderStream2 : Stream + public override bool CanRead => true; + + public override bool CanSeek => false; + + public override bool CanWrite => false; + + public override void Flush() { - public override bool CanRead => true; - - public override bool CanSeek => false; - - public override bool CanWrite => false; - - public override void Flush() - { - throw new NotSupportedException(); - } - - public override long Length => throw new NotSupportedException(); - - public override long Position - { - get => throw new NotSupportedException(); - set => throw new NotSupportedException(); - } - - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } - - public override void SetLength(long value) - { - throw new NotSupportedException(); - } - - public override void Write(byte[] buffer, int offset, int count) - { - throw new NotSupportedException(); - } + throw new NotSupportedException(); } - internal static class DecoderStreamHelper + public override long Length => throw new NotSupportedException(); + + public override long Position { - private static int FindCoderIndexForOutStreamIndex(CFolder folderInfo, int outStreamIndex) - { - for (int coderIndex = 0; coderIndex < folderInfo._coders.Count; coderIndex++) - { - var coderInfo = folderInfo._coders[coderIndex]; - outStreamIndex -= coderInfo._numOutStreams; - if (outStreamIndex < 0) - { - return coderIndex; - } - } + get => throw new NotSupportedException(); + set => throw new NotSupportedException(); + } - throw new InvalidOperationException("Could not link output stream to coder."); - } + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } - private static void FindPrimaryOutStreamIndex( - CFolder folderInfo, - out int primaryCoderIndex, - out int primaryOutStreamIndex - ) - { - bool foundPrimaryOutStream = false; - primaryCoderIndex = -1; - primaryOutStreamIndex = -1; + public override void SetLength(long value) + { + throw new NotSupportedException(); + } - for ( - int outStreamIndex = 0, coderIndex = 0; - coderIndex < folderInfo._coders.Count; - coderIndex++ - ) - { - for ( - int coderOutStreamIndex = 0; - coderOutStreamIndex < folderInfo._coders[coderIndex]._numOutStreams; - coderOutStreamIndex++, outStreamIndex++ - ) - { - if (folderInfo.FindBindPairForOutStream(outStreamIndex) < 0) - { - if (foundPrimaryOutStream) - { - throw new NotSupportedException("Multiple output streams."); - } - - foundPrimaryOutStream = true; - primaryCoderIndex = coderIndex; - primaryOutStreamIndex = outStreamIndex; - } - } - } - - if (!foundPrimaryOutStream) - { - throw new NotSupportedException("No output stream."); - } - } - - private static Stream CreateDecoderStream( - Stream[] packStreams, - long[] packSizes, - Stream[] outStreams, - CFolder folderInfo, - int coderIndex, - IPasswordProvider pass - ) - { - var coderInfo = folderInfo._coders[coderIndex]; - if (coderInfo._numOutStreams != 1) - { - throw new NotSupportedException("Multiple output streams are not supported."); - } - - int inStreamId = 0; - for (int i = 0; i < coderIndex; i++) - { - inStreamId += folderInfo._coders[i]._numInStreams; - } - - int outStreamId = 0; - for (int i = 0; i < coderIndex; i++) - { - outStreamId += folderInfo._coders[i]._numOutStreams; - } - - Stream[] inStreams = new Stream[coderInfo._numInStreams]; - - for (int i = 0; i < inStreams.Length; i++, inStreamId++) - { - int bindPairIndex = folderInfo.FindBindPairForInStream(inStreamId); - if (bindPairIndex >= 0) - { - int pairedOutIndex = folderInfo._bindPairs[bindPairIndex]._outIndex; - - if (outStreams[pairedOutIndex] != null) - { - throw new NotSupportedException( - "Overlapping stream bindings are not supported." - ); - } - - int otherCoderIndex = FindCoderIndexForOutStreamIndex( - folderInfo, - pairedOutIndex - ); - inStreams[i] = CreateDecoderStream( - packStreams, - packSizes, - outStreams, - folderInfo, - otherCoderIndex, - pass - ); - - //inStreamSizes[i] = folderInfo.UnpackSizes[pairedOutIndex]; - - if (outStreams[pairedOutIndex] != null) - { - throw new NotSupportedException( - "Overlapping stream bindings are not supported." - ); - } - - outStreams[pairedOutIndex] = inStreams[i]; - } - else - { - int index = folderInfo.FindPackStreamArrayIndex(inStreamId); - if (index < 0) - { - throw new NotSupportedException("Could not find input stream binding."); - } - - inStreams[i] = packStreams[index]; - - //inStreamSizes[i] = packSizes[index]; - } - } - - long unpackSize = folderInfo._unpackSizes[outStreamId]; - return DecoderRegistry.CreateDecoderStream( - coderInfo._methodId, - inStreams, - coderInfo._props, - pass, - unpackSize - ); - } - - internal static Stream CreateDecoderStream( - Stream inStream, - long startPos, - long[] packSizes, - CFolder folderInfo, - IPasswordProvider pass - ) - { - if (!folderInfo.CheckStructure()) - { - throw new NotSupportedException("Unsupported stream binding structure."); - } - - Stream[] inStreams = new Stream[folderInfo._packStreams.Count]; - for (int j = 0; j < folderInfo._packStreams.Count; j++) - { - inStreams[j] = new BufferedSubStream(inStream, startPos, packSizes[j]); - startPos += packSizes[j]; - } - - Stream[] outStreams = new Stream[folderInfo._unpackSizes.Count]; - - int primaryCoderIndex, - primaryOutStreamIndex; - FindPrimaryOutStreamIndex(folderInfo, out primaryCoderIndex, out primaryOutStreamIndex); - return CreateDecoderStream( - inStreams, - packSizes, - outStreams, - folderInfo, - primaryCoderIndex, - pass - ); - } + public override void Write(byte[] buffer, int offset, int count) + { + throw new NotSupportedException(); + } +} + +internal static class DecoderStreamHelper +{ + private static int FindCoderIndexForOutStreamIndex(CFolder folderInfo, int outStreamIndex) + { + for (var coderIndex = 0; coderIndex < folderInfo._coders.Count; coderIndex++) + { + var coderInfo = folderInfo._coders[coderIndex]; + outStreamIndex -= coderInfo._numOutStreams; + if (outStreamIndex < 0) + { + return coderIndex; + } + } + + throw new InvalidOperationException("Could not link output stream to coder."); + } + + private static void FindPrimaryOutStreamIndex( + CFolder folderInfo, + out int primaryCoderIndex, + out int primaryOutStreamIndex + ) + { + var foundPrimaryOutStream = false; + primaryCoderIndex = -1; + primaryOutStreamIndex = -1; + + for ( + int outStreamIndex = 0, coderIndex = 0; + coderIndex < folderInfo._coders.Count; + coderIndex++ + ) + { + for ( + var coderOutStreamIndex = 0; + coderOutStreamIndex < folderInfo._coders[coderIndex]._numOutStreams; + coderOutStreamIndex++, outStreamIndex++ + ) + { + if (folderInfo.FindBindPairForOutStream(outStreamIndex) < 0) + { + if (foundPrimaryOutStream) + { + throw new NotSupportedException("Multiple output streams."); + } + + foundPrimaryOutStream = true; + primaryCoderIndex = coderIndex; + primaryOutStreamIndex = outStreamIndex; + } + } + } + + if (!foundPrimaryOutStream) + { + throw new NotSupportedException("No output stream."); + } + } + + private static Stream CreateDecoderStream( + Stream[] packStreams, + long[] packSizes, + Stream[] outStreams, + CFolder folderInfo, + int coderIndex, + IPasswordProvider pass + ) + { + var coderInfo = folderInfo._coders[coderIndex]; + if (coderInfo._numOutStreams != 1) + { + throw new NotSupportedException("Multiple output streams are not supported."); + } + + var inStreamId = 0; + for (var i = 0; i < coderIndex; i++) + { + inStreamId += folderInfo._coders[i]._numInStreams; + } + + var outStreamId = 0; + for (var i = 0; i < coderIndex; i++) + { + outStreamId += folderInfo._coders[i]._numOutStreams; + } + + var inStreams = new Stream[coderInfo._numInStreams]; + + for (var i = 0; i < inStreams.Length; i++, inStreamId++) + { + var bindPairIndex = folderInfo.FindBindPairForInStream(inStreamId); + if (bindPairIndex >= 0) + { + var pairedOutIndex = folderInfo._bindPairs[bindPairIndex]._outIndex; + + if (outStreams[pairedOutIndex] != null) + { + throw new NotSupportedException( + "Overlapping stream bindings are not supported." + ); + } + + var otherCoderIndex = FindCoderIndexForOutStreamIndex( + folderInfo, + pairedOutIndex + ); + inStreams[i] = CreateDecoderStream( + packStreams, + packSizes, + outStreams, + folderInfo, + otherCoderIndex, + pass + ); + + //inStreamSizes[i] = folderInfo.UnpackSizes[pairedOutIndex]; + + if (outStreams[pairedOutIndex] != null) + { + throw new NotSupportedException( + "Overlapping stream bindings are not supported." + ); + } + + outStreams[pairedOutIndex] = inStreams[i]; + } + else + { + var index = folderInfo.FindPackStreamArrayIndex(inStreamId); + if (index < 0) + { + throw new NotSupportedException("Could not find input stream binding."); + } + + inStreams[i] = packStreams[index]; + + //inStreamSizes[i] = packSizes[index]; + } + } + + var unpackSize = folderInfo._unpackSizes[outStreamId]; + return DecoderRegistry.CreateDecoderStream( + coderInfo._methodId, + inStreams, + coderInfo._props, + pass, + unpackSize + ); + } + + internal static Stream CreateDecoderStream( + Stream inStream, + long startPos, + long[] packSizes, + CFolder folderInfo, + IPasswordProvider pass + ) + { + if (!folderInfo.CheckStructure()) + { + throw new NotSupportedException("Unsupported stream binding structure."); + } + + var inStreams = new Stream[folderInfo._packStreams.Count]; + for (var j = 0; j < folderInfo._packStreams.Count; j++) + { + inStreams[j] = new BufferedSubStream(inStream, startPos, packSizes[j]); + startPos += packSizes[j]; + } + + var outStreams = new Stream[folderInfo._unpackSizes.Count]; + + FindPrimaryOutStreamIndex(folderInfo, out var primaryCoderIndex, out var primaryOutStreamIndex); + return CreateDecoderStream( + inStreams, + packSizes, + outStreams, + folderInfo, + primaryCoderIndex, + pass + ); } } diff --git a/src/SharpCompress/Compressors/LZMA/ICoder.cs b/src/SharpCompress/Compressors/LZMA/ICoder.cs index a571ddc5..c0fd198b 100644 --- a/src/SharpCompress/Compressors/LZMA/ICoder.cs +++ b/src/SharpCompress/Compressors/LZMA/ICoder.cs @@ -1,171 +1,170 @@ using System; using System.IO; -namespace SharpCompress.Compressors.LZMA +namespace SharpCompress.Compressors.LZMA; + +/// +/// The exception that is thrown when an error in input stream occurs during decoding. +/// +internal class DataErrorException : Exception +{ + public DataErrorException() : base("Data Error") { } +} + +/// +/// The exception that is thrown when the value of an argument is outside the allowable range. +/// +internal class InvalidParamException : Exception +{ + public InvalidParamException() : base("Invalid Parameter") { } +} + +public interface ICodeProgress { /// - /// The exception that is thrown when an error in input stream occurs during decoding. + /// Callback progress. /// - internal class DataErrorException : Exception - { - public DataErrorException() : base("Data Error") { } - } - - /// - /// The exception that is thrown when the value of an argument is outside the allowable range. - /// - internal class InvalidParamException : Exception - { - public InvalidParamException() : base("Invalid Parameter") { } - } - - public interface ICodeProgress - { - /// - /// Callback progress. - /// - /// - /// input size. -1 if unknown. - /// - /// - /// output size. -1 if unknown. - /// - void SetProgress(Int64 inSize, Int64 outSize); - } - - internal interface ICoder - { - /// - /// Codes streams. - /// - /// - /// input Stream. - /// - /// - /// output Stream. - /// - /// - /// input Size. -1 if unknown. - /// - /// - /// output Size. -1 if unknown. - /// - /// - /// callback progress reference. - /// - void Code( - Stream inStream, - Stream outStream, - Int64 inSize, - Int64 outSize, - ICodeProgress progress - ); - } - - /* - public interface ICoder2 - { - void Code(ISequentialInStream []inStreams, - const UInt64 []inSizes, - ISequentialOutStream []outStreams, - UInt64 []outSizes, - ICodeProgress progress); - }; - */ - - /// - /// Provides the fields that represent properties idenitifiers for compressing. - /// - internal enum CoderPropId - { - /// - /// Specifies default property. - /// - DefaultProp = 0, - - /// - /// Specifies size of dictionary. - /// - DictionarySize, - - /// - /// Specifies size of memory for PPM*. - /// - UsedMemorySize, - - /// - /// Specifies order for PPM methods. - /// - Order, - - /// - /// Specifies Block Size. - /// - BlockSize, - - /// - /// Specifies number of postion state bits for LZMA (0 - x - 4). - /// - PosStateBits, - - /// - /// Specifies number of literal context bits for LZMA (0 - x - 8). - /// - LitContextBits, - - /// - /// Specifies number of literal position bits for LZMA (0 - x - 4). - /// - LitPosBits, - - /// - /// Specifies number of fast bytes for LZ*. - /// - NumFastBytes, - - /// - /// Specifies match finder. LZMA: "BT2", "BT4" or "BT4B". - /// - MatchFinder, - - /// - /// Specifies the number of match finder cyckes. - /// - MatchFinderCycles, - - /// - /// Specifies number of passes. - /// - NumPasses, - - /// - /// Specifies number of algorithm. - /// - Algorithm, - - /// - /// Specifies the number of threads. - /// - NumThreads, - - /// - /// Specifies mode with end marker. - /// - EndMarker - } - - internal interface ISetCoderProperties - { - void SetCoderProperties(CoderPropId[] propIDs, object[] properties); - } - - internal interface IWriteCoderProperties - { - void WriteCoderProperties(Stream outStream); - } - - internal interface ISetDecoderProperties - { - void SetDecoderProperties(byte[] properties); - } + /// + /// input size. -1 if unknown. + /// + /// + /// output size. -1 if unknown. + /// + void SetProgress(long inSize, long outSize); +} + +internal interface ICoder +{ + /// + /// Codes streams. + /// + /// + /// input Stream. + /// + /// + /// output Stream. + /// + /// + /// input Size. -1 if unknown. + /// + /// + /// output Size. -1 if unknown. + /// + /// + /// callback progress reference. + /// + void Code( + Stream inStream, + Stream outStream, + long inSize, + long outSize, + ICodeProgress progress + ); +} + +/* +public interface ICoder2 +{ + void Code(ISequentialInStream []inStreams, + const UInt64 []inSizes, + ISequentialOutStream []outStreams, + UInt64 []outSizes, + ICodeProgress progress); +}; +*/ + +/// +/// Provides the fields that represent properties idenitifiers for compressing. +/// +internal enum CoderPropId +{ + /// + /// Specifies default property. + /// + DefaultProp = 0, + + /// + /// Specifies size of dictionary. + /// + DictionarySize, + + /// + /// Specifies size of memory for PPM*. + /// + UsedMemorySize, + + /// + /// Specifies order for PPM methods. + /// + Order, + + /// + /// Specifies Block Size. + /// + BlockSize, + + /// + /// Specifies number of postion state bits for LZMA (0 - x - 4). + /// + PosStateBits, + + /// + /// Specifies number of literal context bits for LZMA (0 - x - 8). + /// + LitContextBits, + + /// + /// Specifies number of literal position bits for LZMA (0 - x - 4). + /// + LitPosBits, + + /// + /// Specifies number of fast bytes for LZ*. + /// + NumFastBytes, + + /// + /// Specifies match finder. LZMA: "BT2", "BT4" or "BT4B". + /// + MatchFinder, + + /// + /// Specifies the number of match finder cyckes. + /// + MatchFinderCycles, + + /// + /// Specifies number of passes. + /// + NumPasses, + + /// + /// Specifies number of algorithm. + /// + Algorithm, + + /// + /// Specifies the number of threads. + /// + NumThreads, + + /// + /// Specifies mode with end marker. + /// + EndMarker +} + +internal interface ISetCoderProperties +{ + void SetCoderProperties(CoderPropId[] propIDs, object[] properties); +} + +internal interface IWriteCoderProperties +{ + void WriteCoderProperties(Stream outStream); +} + +internal interface ISetDecoderProperties +{ + void SetDecoderProperties(byte[] properties); } diff --git a/src/SharpCompress/Compressors/LZMA/LZ/LzBinTree.cs b/src/SharpCompress/Compressors/LZMA/LZ/LzBinTree.cs index 6d630b59..958294a1 100644 --- a/src/SharpCompress/Compressors/LZMA/LZ/LzBinTree.cs +++ b/src/SharpCompress/Compressors/LZMA/LZ/LzBinTree.cs @@ -3,159 +3,317 @@ using System; using System.IO; -namespace SharpCompress.Compressors.LZMA.LZ +namespace SharpCompress.Compressors.LZMA.LZ; + +internal sealed class BinTree : InWindow { - internal sealed class BinTree : InWindow + private uint _cyclicBufferPos; + private uint _cyclicBufferSize; + private uint _matchMaxLen; + + private uint[] _son; + private uint[] _hash; + + private uint _cutValue = 0xFF; + private uint _hashMask; + private uint _hashSizeSum; + + private bool _hashArray = true; + + private const uint K_HASH2_SIZE = 1 << 10; + private const uint K_HASH3_SIZE = 1 << 16; + private const uint K_BT2_HASH_SIZE = 1 << 16; + private const uint K_START_MAX_LEN = 1; + private const uint K_HASH3_OFFSET = K_HASH2_SIZE; + private const uint K_EMPTY_HASH_VALUE = 0; + private const uint K_MAX_VAL_FOR_NORMALIZE = ((uint)1 << 31) - 1; + + private uint _kNumHashDirectBytes; + private uint _kMinMatchCheck = 4; + private uint _kFixHashSize = K_HASH2_SIZE + K_HASH3_SIZE; + + public void SetType(int numHashBytes) { - private UInt32 _cyclicBufferPos; - private UInt32 _cyclicBufferSize; - private UInt32 _matchMaxLen; - - private UInt32[] _son; - private UInt32[] _hash; - - private UInt32 _cutValue = 0xFF; - private UInt32 _hashMask; - private UInt32 _hashSizeSum; - - private bool _hashArray = true; - - private const UInt32 K_HASH2_SIZE = 1 << 10; - private const UInt32 K_HASH3_SIZE = 1 << 16; - private const UInt32 K_BT2_HASH_SIZE = 1 << 16; - private const UInt32 K_START_MAX_LEN = 1; - private const UInt32 K_HASH3_OFFSET = K_HASH2_SIZE; - private const UInt32 K_EMPTY_HASH_VALUE = 0; - private const UInt32 K_MAX_VAL_FOR_NORMALIZE = ((UInt32)1 << 31) - 1; - - private UInt32 _kNumHashDirectBytes; - private UInt32 _kMinMatchCheck = 4; - private UInt32 _kFixHashSize = K_HASH2_SIZE + K_HASH3_SIZE; - - public void SetType(int numHashBytes) + _hashArray = (numHashBytes > 2); + if (_hashArray) { - _hashArray = (numHashBytes > 2); - if (_hashArray) + _kNumHashDirectBytes = 0; + _kMinMatchCheck = 4; + _kFixHashSize = K_HASH2_SIZE + K_HASH3_SIZE; + } + else + { + _kNumHashDirectBytes = 2; + _kMinMatchCheck = 2 + 1; + _kFixHashSize = 0; + } + } + + public new void SetStream(Stream stream) + { + base.SetStream(stream); + } + + public new void ReleaseStream() + { + base.ReleaseStream(); + } + + public new void Init() + { + base.Init(); + for (uint i = 0; i < _hashSizeSum; i++) + { + _hash[i] = K_EMPTY_HASH_VALUE; + } + _cyclicBufferPos = 0; + ReduceOffsets(-1); + } + + public new void MovePos() + { + if (++_cyclicBufferPos >= _cyclicBufferSize) + { + _cyclicBufferPos = 0; + } + base.MovePos(); + if (_pos == K_MAX_VAL_FOR_NORMALIZE) + { + Normalize(); + } + } + + public new byte GetIndexByte(int index) + { + return base.GetIndexByte(index); + } + + public new uint GetMatchLen(int index, uint distance, uint limit) + { + return base.GetMatchLen(index, distance, limit); + } + + public new uint GetNumAvailableBytes() + { + return base.GetNumAvailableBytes(); + } + + public void Create( + uint historySize, + uint keepAddBufferBefore, + uint matchMaxLen, + uint keepAddBufferAfter + ) + { + if (historySize > K_MAX_VAL_FOR_NORMALIZE - 256) + { + throw new ArgumentOutOfRangeException(nameof(historySize)); + } + _cutValue = 16 + (matchMaxLen >> 1); + + var windowReservSize = + ((historySize + keepAddBufferBefore + matchMaxLen + keepAddBufferAfter) / 2) + 256; + + Create( + historySize + keepAddBufferBefore, + matchMaxLen + keepAddBufferAfter, + windowReservSize + ); + + _matchMaxLen = matchMaxLen; + + var cyclicBufferSize = historySize + 1; + if (_cyclicBufferSize != cyclicBufferSize) + { + _son = new uint[(_cyclicBufferSize = cyclicBufferSize) * 2]; + } + + var hs = K_BT2_HASH_SIZE; + + if (_hashArray) + { + hs = historySize - 1; + hs |= (hs >> 1); + hs |= (hs >> 2); + hs |= (hs >> 4); + hs |= (hs >> 8); + hs >>= 1; + hs |= 0xFFFF; + if (hs > (1 << 24)) { - _kNumHashDirectBytes = 0; - _kMinMatchCheck = 4; - _kFixHashSize = K_HASH2_SIZE + K_HASH3_SIZE; + hs >>= 1; + } + _hashMask = hs; + hs++; + hs += _kFixHashSize; + } + if (hs != _hashSizeSum) + { + _hash = new uint[_hashSizeSum = hs]; + } + } + + public uint GetMatches(uint[] distances) + { + uint lenLimit; + if (_pos + _matchMaxLen <= _streamPos) + { + lenLimit = _matchMaxLen; + } + else + { + lenLimit = _streamPos - _pos; + if (lenLimit < _kMinMatchCheck) + { + MovePos(); + return 0; + } + } + + uint offset = 0; + var matchMinPos = (_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0; + var cur = _bufferOffset + _pos; + var maxLen = K_START_MAX_LEN; // to avoid items for len < hashSize; + uint hashValue, + hash2Value = 0, + hash3Value = 0; + + if (_hashArray) + { + var temp = Crc.TABLE[_bufferBase[cur]] ^ _bufferBase[cur + 1]; + hash2Value = temp & (K_HASH2_SIZE - 1); + temp ^= ((uint)(_bufferBase[cur + 2]) << 8); + hash3Value = temp & (K_HASH3_SIZE - 1); + hashValue = (temp ^ (Crc.TABLE[_bufferBase[cur + 3]] << 5)) & _hashMask; + } + else + { + hashValue = _bufferBase[cur] ^ ((uint)(_bufferBase[cur + 1]) << 8); + } + + var curMatch = _hash[_kFixHashSize + hashValue]; + if (_hashArray) + { + var curMatch2 = _hash[hash2Value]; + var curMatch3 = _hash[K_HASH3_OFFSET + hash3Value]; + _hash[hash2Value] = _pos; + _hash[K_HASH3_OFFSET + hash3Value] = _pos; + if (curMatch2 > matchMinPos) + { + if (_bufferBase[_bufferOffset + curMatch2] == _bufferBase[cur]) + { + distances[offset++] = maxLen = 2; + distances[offset++] = _pos - curMatch2 - 1; + } + } + if (curMatch3 > matchMinPos) + { + if (_bufferBase[_bufferOffset + curMatch3] == _bufferBase[cur]) + { + if (curMatch3 == curMatch2) + { + offset -= 2; + } + distances[offset++] = maxLen = 3; + distances[offset++] = _pos - curMatch3 - 1; + curMatch2 = curMatch3; + } + } + if (offset != 0 && curMatch2 == curMatch) + { + offset -= 2; + maxLen = K_START_MAX_LEN; + } + } + + _hash[_kFixHashSize + hashValue] = _pos; + + var ptr0 = (_cyclicBufferPos << 1) + 1; + var ptr1 = (_cyclicBufferPos << 1); + + uint len0, + len1; + len0 = len1 = _kNumHashDirectBytes; + + if (_kNumHashDirectBytes != 0) + { + if (curMatch > matchMinPos) + { + if ( + _bufferBase[_bufferOffset + curMatch + _kNumHashDirectBytes] + != _bufferBase[cur + _kNumHashDirectBytes] + ) + { + distances[offset++] = maxLen = _kNumHashDirectBytes; + distances[offset++] = _pos - curMatch - 1; + } + } + } + + var count = _cutValue; + + while (true) + { + if (curMatch <= matchMinPos || count-- == 0) + { + _son[ptr0] = _son[ptr1] = K_EMPTY_HASH_VALUE; + break; + } + var delta = _pos - curMatch; + var cyclicPos = + ( + (delta <= _cyclicBufferPos) + ? (_cyclicBufferPos - delta) + : (_cyclicBufferPos - delta + _cyclicBufferSize) + ) << 1; + + var pby1 = _bufferOffset + curMatch; + var len = Math.Min(len0, len1); + if (_bufferBase[pby1 + len] == _bufferBase[cur + len]) + { + while (++len != lenLimit) + { + if (_bufferBase[pby1 + len] != _bufferBase[cur + len]) + { + break; + } + } + if (maxLen < len) + { + distances[offset++] = maxLen = len; + distances[offset++] = delta - 1; + if (len == lenLimit) + { + _son[ptr1] = _son[cyclicPos]; + _son[ptr0] = _son[cyclicPos + 1]; + break; + } + } + } + if (_bufferBase[pby1 + len] < _bufferBase[cur + len]) + { + _son[ptr1] = curMatch; + ptr1 = cyclicPos + 1; + curMatch = _son[ptr1]; + len1 = len; } else { - _kNumHashDirectBytes = 2; - _kMinMatchCheck = 2 + 1; - _kFixHashSize = 0; + _son[ptr0] = curMatch; + ptr0 = cyclicPos; + curMatch = _son[ptr0]; + len0 = len; } } + MovePos(); + return offset; + } - public new void SetStream(Stream stream) + public void Skip(uint num) + { + do { - base.SetStream(stream); - } - - public new void ReleaseStream() - { - base.ReleaseStream(); - } - - public new void Init() - { - base.Init(); - for (UInt32 i = 0; i < _hashSizeSum; i++) - { - _hash[i] = K_EMPTY_HASH_VALUE; - } - _cyclicBufferPos = 0; - ReduceOffsets(-1); - } - - public new void MovePos() - { - if (++_cyclicBufferPos >= _cyclicBufferSize) - { - _cyclicBufferPos = 0; - } - base.MovePos(); - if (_pos == K_MAX_VAL_FOR_NORMALIZE) - { - Normalize(); - } - } - - public new Byte GetIndexByte(Int32 index) - { - return base.GetIndexByte(index); - } - - public new UInt32 GetMatchLen(Int32 index, UInt32 distance, UInt32 limit) - { - return base.GetMatchLen(index, distance, limit); - } - - public new UInt32 GetNumAvailableBytes() - { - return base.GetNumAvailableBytes(); - } - - public void Create( - UInt32 historySize, - UInt32 keepAddBufferBefore, - UInt32 matchMaxLen, - UInt32 keepAddBufferAfter - ) - { - if (historySize > K_MAX_VAL_FOR_NORMALIZE - 256) - { - throw new ArgumentOutOfRangeException(nameof(historySize)); - } - _cutValue = 16 + (matchMaxLen >> 1); - - UInt32 windowReservSize = - (historySize + keepAddBufferBefore + matchMaxLen + keepAddBufferAfter) / 2 + 256; - - base.Create( - historySize + keepAddBufferBefore, - matchMaxLen + keepAddBufferAfter, - windowReservSize - ); - - _matchMaxLen = matchMaxLen; - - UInt32 cyclicBufferSize = historySize + 1; - if (_cyclicBufferSize != cyclicBufferSize) - { - _son = new UInt32[(_cyclicBufferSize = cyclicBufferSize) * 2]; - } - - UInt32 hs = K_BT2_HASH_SIZE; - - if (_hashArray) - { - hs = historySize - 1; - hs |= (hs >> 1); - hs |= (hs >> 2); - hs |= (hs >> 4); - hs |= (hs >> 8); - hs >>= 1; - hs |= 0xFFFF; - if (hs > (1 << 24)) - { - hs >>= 1; - } - _hashMask = hs; - hs++; - hs += _kFixHashSize; - } - if (hs != _hashSizeSum) - { - _hash = new UInt32[_hashSizeSum = hs]; - } - } - - public UInt32 GetMatches(UInt32[] distances) - { - UInt32 lenLimit; + uint lenLimit; if (_pos + _matchMaxLen <= _streamPos) { lenLimit = _matchMaxLen; @@ -166,92 +324,41 @@ namespace SharpCompress.Compressors.LZMA.LZ if (lenLimit < _kMinMatchCheck) { MovePos(); - return 0; + continue; } } - UInt32 offset = 0; - UInt32 matchMinPos = (_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0; - UInt32 cur = _bufferOffset + _pos; - UInt32 maxLen = K_START_MAX_LEN; // to avoid items for len < hashSize; - UInt32 hashValue, - hash2Value = 0, - hash3Value = 0; + var matchMinPos = (_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0; + var cur = _bufferOffset + _pos; + + uint hashValue; if (_hashArray) { - UInt32 temp = Crc.TABLE[_bufferBase[cur]] ^ _bufferBase[cur + 1]; - hash2Value = temp & (K_HASH2_SIZE - 1); - temp ^= ((UInt32)(_bufferBase[cur + 2]) << 8); - hash3Value = temp & (K_HASH3_SIZE - 1); + var temp = Crc.TABLE[_bufferBase[cur]] ^ _bufferBase[cur + 1]; + var hash2Value = temp & (K_HASH2_SIZE - 1); + _hash[hash2Value] = _pos; + temp ^= ((uint)(_bufferBase[cur + 2]) << 8); + var hash3Value = temp & (K_HASH3_SIZE - 1); + _hash[K_HASH3_OFFSET + hash3Value] = _pos; hashValue = (temp ^ (Crc.TABLE[_bufferBase[cur + 3]] << 5)) & _hashMask; } else { - hashValue = _bufferBase[cur] ^ ((UInt32)(_bufferBase[cur + 1]) << 8); - } - - UInt32 curMatch = _hash[_kFixHashSize + hashValue]; - if (_hashArray) - { - UInt32 curMatch2 = _hash[hash2Value]; - UInt32 curMatch3 = _hash[K_HASH3_OFFSET + hash3Value]; - _hash[hash2Value] = _pos; - _hash[K_HASH3_OFFSET + hash3Value] = _pos; - if (curMatch2 > matchMinPos) - { - if (_bufferBase[_bufferOffset + curMatch2] == _bufferBase[cur]) - { - distances[offset++] = maxLen = 2; - distances[offset++] = _pos - curMatch2 - 1; - } - } - if (curMatch3 > matchMinPos) - { - if (_bufferBase[_bufferOffset + curMatch3] == _bufferBase[cur]) - { - if (curMatch3 == curMatch2) - { - offset -= 2; - } - distances[offset++] = maxLen = 3; - distances[offset++] = _pos - curMatch3 - 1; - curMatch2 = curMatch3; - } - } - if (offset != 0 && curMatch2 == curMatch) - { - offset -= 2; - maxLen = K_START_MAX_LEN; - } + hashValue = _bufferBase[cur] ^ ((uint)(_bufferBase[cur + 1]) << 8); } + var curMatch = _hash[_kFixHashSize + hashValue]; _hash[_kFixHashSize + hashValue] = _pos; - UInt32 ptr0 = (_cyclicBufferPos << 1) + 1; - UInt32 ptr1 = (_cyclicBufferPos << 1); + var ptr0 = (_cyclicBufferPos << 1) + 1; + var ptr1 = (_cyclicBufferPos << 1); - UInt32 len0, + uint len0, len1; len0 = len1 = _kNumHashDirectBytes; - if (_kNumHashDirectBytes != 0) - { - if (curMatch > matchMinPos) - { - if ( - _bufferBase[_bufferOffset + curMatch + _kNumHashDirectBytes] - != _bufferBase[cur + _kNumHashDirectBytes] - ) - { - distances[offset++] = maxLen = _kNumHashDirectBytes; - distances[offset++] = _pos - curMatch - 1; - } - } - } - - UInt32 count = _cutValue; - + var count = _cutValue; while (true) { if (curMatch <= matchMinPos || count-- == 0) @@ -259,16 +366,17 @@ namespace SharpCompress.Compressors.LZMA.LZ _son[ptr0] = _son[ptr1] = K_EMPTY_HASH_VALUE; break; } - UInt32 delta = _pos - curMatch; - UInt32 cyclicPos = + + var delta = _pos - curMatch; + var cyclicPos = ( (delta <= _cyclicBufferPos) ? (_cyclicBufferPos - delta) : (_cyclicBufferPos - delta + _cyclicBufferSize) ) << 1; - UInt32 pby1 = _bufferOffset + curMatch; - UInt32 len = Math.Min(len0, len1); + var pby1 = _bufferOffset + curMatch; + var len = Math.Min(len0, len1); if (_bufferBase[pby1 + len] == _bufferBase[cur + len]) { while (++len != lenLimit) @@ -278,16 +386,11 @@ namespace SharpCompress.Compressors.LZMA.LZ break; } } - if (maxLen < len) + if (len == lenLimit) { - distances[offset++] = maxLen = len; - distances[offset++] = delta - 1; - if (len == lenLimit) - { - _son[ptr1] = _son[cyclicPos]; - _son[ptr0] = _son[cyclicPos + 1]; - break; - } + _son[ptr1] = _son[cyclicPos]; + _son[ptr0] = _son[cyclicPos + 1]; + break; } } if (_bufferBase[pby1 + len] < _bufferBase[cur + len]) @@ -306,140 +409,36 @@ namespace SharpCompress.Compressors.LZMA.LZ } } MovePos(); - return offset; - } + } while (--num != 0); + } - public void Skip(UInt32 num) + private void NormalizeLinks(uint[] items, uint numItems, uint subValue) + { + for (uint i = 0; i < numItems; i++) { - do + var value = items[i]; + if (value <= subValue) { - UInt32 lenLimit; - if (_pos + _matchMaxLen <= _streamPos) - { - lenLimit = _matchMaxLen; - } - else - { - lenLimit = _streamPos - _pos; - if (lenLimit < _kMinMatchCheck) - { - MovePos(); - continue; - } - } - - UInt32 matchMinPos = (_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0; - UInt32 cur = _bufferOffset + _pos; - - UInt32 hashValue; - - if (_hashArray) - { - UInt32 temp = Crc.TABLE[_bufferBase[cur]] ^ _bufferBase[cur + 1]; - UInt32 hash2Value = temp & (K_HASH2_SIZE - 1); - _hash[hash2Value] = _pos; - temp ^= ((UInt32)(_bufferBase[cur + 2]) << 8); - UInt32 hash3Value = temp & (K_HASH3_SIZE - 1); - _hash[K_HASH3_OFFSET + hash3Value] = _pos; - hashValue = (temp ^ (Crc.TABLE[_bufferBase[cur + 3]] << 5)) & _hashMask; - } - else - { - hashValue = _bufferBase[cur] ^ ((UInt32)(_bufferBase[cur + 1]) << 8); - } - - UInt32 curMatch = _hash[_kFixHashSize + hashValue]; - _hash[_kFixHashSize + hashValue] = _pos; - - UInt32 ptr0 = (_cyclicBufferPos << 1) + 1; - UInt32 ptr1 = (_cyclicBufferPos << 1); - - UInt32 len0, - len1; - len0 = len1 = _kNumHashDirectBytes; - - UInt32 count = _cutValue; - while (true) - { - if (curMatch <= matchMinPos || count-- == 0) - { - _son[ptr0] = _son[ptr1] = K_EMPTY_HASH_VALUE; - break; - } - - UInt32 delta = _pos - curMatch; - UInt32 cyclicPos = - ( - (delta <= _cyclicBufferPos) - ? (_cyclicBufferPos - delta) - : (_cyclicBufferPos - delta + _cyclicBufferSize) - ) << 1; - - UInt32 pby1 = _bufferOffset + curMatch; - UInt32 len = Math.Min(len0, len1); - if (_bufferBase[pby1 + len] == _bufferBase[cur + len]) - { - while (++len != lenLimit) - { - if (_bufferBase[pby1 + len] != _bufferBase[cur + len]) - { - break; - } - } - if (len == lenLimit) - { - _son[ptr1] = _son[cyclicPos]; - _son[ptr0] = _son[cyclicPos + 1]; - break; - } - } - if (_bufferBase[pby1 + len] < _bufferBase[cur + len]) - { - _son[ptr1] = curMatch; - ptr1 = cyclicPos + 1; - curMatch = _son[ptr1]; - len1 = len; - } - else - { - _son[ptr0] = curMatch; - ptr0 = cyclicPos; - curMatch = _son[ptr0]; - len0 = len; - } - } - MovePos(); - } while (--num != 0); - } - - private void NormalizeLinks(UInt32[] items, UInt32 numItems, UInt32 subValue) - { - for (UInt32 i = 0; i < numItems; i++) - { - UInt32 value = items[i]; - if (value <= subValue) - { - value = K_EMPTY_HASH_VALUE; - } - else - { - value -= subValue; - } - items[i] = value; + value = K_EMPTY_HASH_VALUE; } - } - - private void Normalize() - { - UInt32 subValue = _pos - _cyclicBufferSize; - NormalizeLinks(_son, _cyclicBufferSize * 2, subValue); - NormalizeLinks(_hash, _hashSizeSum, subValue); - ReduceOffsets((Int32)subValue); - } - - public void SetCutValue(UInt32 cutValue) - { - _cutValue = cutValue; + else + { + value -= subValue; + } + items[i] = value; } } + + private void Normalize() + { + var subValue = _pos - _cyclicBufferSize; + NormalizeLinks(_son, _cyclicBufferSize * 2, subValue); + NormalizeLinks(_hash, _hashSizeSum, subValue); + ReduceOffsets((int)subValue); + } + + public void SetCutValue(uint cutValue) + { + _cutValue = cutValue; + } } diff --git a/src/SharpCompress/Compressors/LZMA/LZ/LzInWindow.cs b/src/SharpCompress/Compressors/LZMA/LZ/LzInWindow.cs index 943009d2..26353624 100644 --- a/src/SharpCompress/Compressors/LZMA/LZ/LzInWindow.cs +++ b/src/SharpCompress/Compressors/LZMA/LZ/LzInWindow.cs @@ -1,186 +1,184 @@ #nullable disable -using System; using System.IO; -namespace SharpCompress.Compressors.LZMA.LZ +namespace SharpCompress.Compressors.LZMA.LZ; + +internal class InWindow { - internal class InWindow + public byte[] _bufferBase; // pointer to buffer with data + private Stream _stream; + private uint _posLimit; // offset (from _buffer) of first byte when new block reading must be done + private bool _streamEndWasReached; // if (true) then _streamPos shows real end of stream + + private uint _pointerToLastSafePosition; + + public uint _bufferOffset; + + public uint _blockSize; // Size of Allocated memory block + public uint _pos; // offset (from _buffer) of curent byte + private uint _keepSizeBefore; // how many BYTEs must be kept in buffer before _pos + private uint _keepSizeAfter; // how many BYTEs must be kept buffer after _pos + public uint _streamPos; // offset (from _buffer) of first not read byte from Stream + + public void MoveBlock() { - public Byte[] _bufferBase; // pointer to buffer with data - private Stream _stream; - private UInt32 _posLimit; // offset (from _buffer) of first byte when new block reading must be done - private bool _streamEndWasReached; // if (true) then _streamPos shows real end of stream + var offset = _bufferOffset + _pos - _keepSizeBefore; - private UInt32 _pointerToLastSafePosition; - - public UInt32 _bufferOffset; - - public UInt32 _blockSize; // Size of Allocated memory block - public UInt32 _pos; // offset (from _buffer) of curent byte - private UInt32 _keepSizeBefore; // how many BYTEs must be kept in buffer before _pos - private UInt32 _keepSizeAfter; // how many BYTEs must be kept buffer after _pos - public UInt32 _streamPos; // offset (from _buffer) of first not read byte from Stream - - public void MoveBlock() + // we need one additional byte, since MovePos moves on 1 byte. + if (offset > 0) { - UInt32 offset = _bufferOffset + _pos - _keepSizeBefore; - - // we need one additional byte, since MovePos moves on 1 byte. - if (offset > 0) - { - offset--; - } - - UInt32 numBytes = _bufferOffset + _streamPos - offset; - - // check negative offset ???? - for (UInt32 i = 0; i < numBytes; i++) - { - _bufferBase[i] = _bufferBase[offset + i]; - } - _bufferOffset -= offset; + offset--; } - public virtual void ReadBlock() + var numBytes = _bufferOffset + _streamPos - offset; + + // check negative offset ???? + for (uint i = 0; i < numBytes; i++) { - if (_streamEndWasReached) + _bufferBase[i] = _bufferBase[offset + i]; + } + _bufferOffset -= offset; + } + + public virtual void ReadBlock() + { + if (_streamEndWasReached) + { + return; + } + while (true) + { + var size = (int)((0 - _bufferOffset) + _blockSize - _streamPos); + if (size == 0) { return; } - while (true) + var numReadBytes = + _stream != null + ? _stream.Read(_bufferBase, (int)(_bufferOffset + _streamPos), size) + : 0; + if (numReadBytes == 0) { - int size = (int)((0 - _bufferOffset) + _blockSize - _streamPos); - if (size == 0) - { - return; - } - int numReadBytes = - _stream != null - ? _stream.Read(_bufferBase, (int)(_bufferOffset + _streamPos), size) - : 0; - if (numReadBytes == 0) - { - _posLimit = _streamPos; - UInt32 pointerToPostion = _bufferOffset + _posLimit; - if (pointerToPostion > _pointerToLastSafePosition) - { - _posLimit = _pointerToLastSafePosition - _bufferOffset; - } - - _streamEndWasReached = true; - return; - } - _streamPos += (UInt32)numReadBytes; - if (_streamPos >= _pos + _keepSizeAfter) - { - _posLimit = _streamPos - _keepSizeAfter; - } - } - } - - private void Free() - { - _bufferBase = null; - } - - public void Create(UInt32 keepSizeBefore, UInt32 keepSizeAfter, UInt32 keepSizeReserv) - { - _keepSizeBefore = keepSizeBefore; - _keepSizeAfter = keepSizeAfter; - UInt32 blockSize = keepSizeBefore + keepSizeAfter + keepSizeReserv; - if (_bufferBase is null || _blockSize != blockSize) - { - Free(); - _blockSize = blockSize; - _bufferBase = new Byte[_blockSize]; - } - _pointerToLastSafePosition = _blockSize - keepSizeAfter; - _streamEndWasReached = false; - } - - public void SetStream(Stream stream) - { - _stream = stream; - if (_streamEndWasReached) - { - _streamEndWasReached = false; - if (IsDataStarved) - { - ReadBlock(); - } - } - } - - public void ReleaseStream() - { - _stream = null; - } - - public void Init() - { - _bufferOffset = 0; - _pos = 0; - _streamPos = 0; - _streamEndWasReached = false; - ReadBlock(); - } - - public void MovePos() - { - _pos++; - if (_pos > _posLimit) - { - UInt32 pointerToPostion = _bufferOffset + _pos; + _posLimit = _streamPos; + var pointerToPostion = _bufferOffset + _posLimit; if (pointerToPostion > _pointerToLastSafePosition) { - MoveBlock(); + _posLimit = _pointerToLastSafePosition - _bufferOffset; } + + _streamEndWasReached = true; + return; + } + _streamPos += (uint)numReadBytes; + if (_streamPos >= _pos + _keepSizeAfter) + { + _posLimit = _streamPos - _keepSizeAfter; + } + } + } + + private void Free() + { + _bufferBase = null; + } + + public void Create(uint keepSizeBefore, uint keepSizeAfter, uint keepSizeReserv) + { + _keepSizeBefore = keepSizeBefore; + _keepSizeAfter = keepSizeAfter; + var blockSize = keepSizeBefore + keepSizeAfter + keepSizeReserv; + if (_bufferBase is null || _blockSize != blockSize) + { + Free(); + _blockSize = blockSize; + _bufferBase = new byte[_blockSize]; + } + _pointerToLastSafePosition = _blockSize - keepSizeAfter; + _streamEndWasReached = false; + } + + public void SetStream(Stream stream) + { + _stream = stream; + if (_streamEndWasReached) + { + _streamEndWasReached = false; + if (IsDataStarved) + { ReadBlock(); } } - - public Byte GetIndexByte(Int32 index) - { - return _bufferBase[_bufferOffset + _pos + index]; - } - - // index + limit have not to exceed _keepSizeAfter; - public UInt32 GetMatchLen(Int32 index, UInt32 distance, UInt32 limit) - { - if (_streamEndWasReached) - { - if ((_pos + index) + limit > _streamPos) - { - limit = _streamPos - (UInt32)(_pos + index); - } - } - distance++; - - // Byte *pby = _buffer + (size_t)_pos + index; - UInt32 pby = _bufferOffset + _pos + (UInt32)index; - - UInt32 i; - for (i = 0; i < limit && _bufferBase[pby + i] == _bufferBase[pby + i - distance]; i++) - { - ; - } - return i; - } - - public UInt32 GetNumAvailableBytes() - { - return _streamPos - _pos; - } - - public void ReduceOffsets(Int32 subValue) - { - _bufferOffset += (UInt32)subValue; - _posLimit -= (UInt32)subValue; - _pos -= (UInt32)subValue; - _streamPos -= (UInt32)subValue; - } - - public bool IsDataStarved => _streamPos - _pos < _keepSizeAfter; } + + public void ReleaseStream() + { + _stream = null; + } + + public void Init() + { + _bufferOffset = 0; + _pos = 0; + _streamPos = 0; + _streamEndWasReached = false; + ReadBlock(); + } + + public void MovePos() + { + _pos++; + if (_pos > _posLimit) + { + var pointerToPostion = _bufferOffset + _pos; + if (pointerToPostion > _pointerToLastSafePosition) + { + MoveBlock(); + } + ReadBlock(); + } + } + + public byte GetIndexByte(int index) + { + return _bufferBase[_bufferOffset + _pos + index]; + } + + // index + limit have not to exceed _keepSizeAfter; + public uint GetMatchLen(int index, uint distance, uint limit) + { + if (_streamEndWasReached) + { + if ((_pos + index) + limit > _streamPos) + { + limit = _streamPos - (uint)(_pos + index); + } + } + distance++; + + // Byte *pby = _buffer + (size_t)_pos + index; + var pby = _bufferOffset + _pos + (uint)index; + + uint i; + for (i = 0; i < limit && _bufferBase[pby + i] == _bufferBase[pby + i - distance]; i++) + { + ; + } + return i; + } + + public uint GetNumAvailableBytes() + { + return _streamPos - _pos; + } + + public void ReduceOffsets(int subValue) + { + _bufferOffset += (uint)subValue; + _posLimit -= (uint)subValue; + _pos -= (uint)subValue; + _streamPos -= (uint)subValue; + } + + public bool IsDataStarved => _streamPos - _pos < _keepSizeAfter; } diff --git a/src/SharpCompress/Compressors/LZMA/LZ/LzOutWindow.cs b/src/SharpCompress/Compressors/LZMA/LZ/LzOutWindow.cs index 6542ff91..42eb38b3 100644 --- a/src/SharpCompress/Compressors/LZMA/LZ/LzOutWindow.cs +++ b/src/SharpCompress/Compressors/LZMA/LZ/LzOutWindow.cs @@ -3,205 +3,204 @@ using System; using System.IO; -namespace SharpCompress.Compressors.LZMA.LZ +namespace SharpCompress.Compressors.LZMA.LZ; + +internal class OutWindow { - internal class OutWindow + private byte[] _buffer; + private int _windowSize; + private int _pos; + private int _streamPos; + private int _pendingLen; + private int _pendingDist; + private Stream _stream; + + public long _total; + public long _limit; + + public void Create(int windowSize) { - private byte[] _buffer; - private int _windowSize; - private int _pos; - private int _streamPos; - private int _pendingLen; - private int _pendingDist; - private Stream _stream; - - public long _total; - public long _limit; - - public void Create(int windowSize) + if (_windowSize != windowSize) + { + _buffer = new byte[windowSize]; + } + else + { + _buffer[windowSize - 1] = 0; + } + _windowSize = windowSize; + _pos = 0; + _streamPos = 0; + _pendingLen = 0; + _total = 0; + _limit = 0; + } + + public void Reset() + { + Create(_windowSize); + } + + public void Init(Stream stream) + { + ReleaseStream(); + _stream = stream; + } + + public void Train(Stream stream) + { + var len = stream.Length; + var size = (len < _windowSize) ? (int)len : _windowSize; + stream.Position = len - size; + _total = 0; + _limit = size; + _pos = _windowSize - size; + CopyStream(stream, size); + if (_pos == _windowSize) { - if (_windowSize != windowSize) - { - _buffer = new byte[windowSize]; - } - else - { - _buffer[windowSize - 1] = 0; - } - _windowSize = windowSize; _pos = 0; - _streamPos = 0; - _pendingLen = 0; - _total = 0; - _limit = 0; } + _streamPos = _pos; + } - public void Reset() + public void ReleaseStream() + { + Flush(); + _stream = null; + } + + public void Flush() + { + if (_stream is null) { - Create(_windowSize); + return; } - - public void Init(Stream stream) + var size = _pos - _streamPos; + if (size == 0) { - ReleaseStream(); - _stream = stream; + return; } - - public void Train(Stream stream) + _stream.Write(_buffer, _streamPos, size); + if (_pos >= _windowSize) { - long len = stream.Length; - int size = (len < _windowSize) ? (int)len : _windowSize; - stream.Position = len - size; - _total = 0; - _limit = size; - _pos = _windowSize - size; - CopyStream(stream, size); - if (_pos == _windowSize) + _pos = 0; + } + _streamPos = _pos; + } + + public void CopyBlock(int distance, int len) + { + var size = len; + var pos = _pos - distance - 1; + if (pos < 0) + { + pos += _windowSize; + } + for (; size > 0 && _pos < _windowSize && _total < _limit; size--) + { + if (pos >= _windowSize) { - _pos = 0; + pos = 0; } - _streamPos = _pos; - } - - public void ReleaseStream() - { - Flush(); - _stream = null; - } - - public void Flush() - { - if (_stream is null) - { - return; - } - int size = _pos - _streamPos; - if (size == 0) - { - return; - } - _stream.Write(_buffer, _streamPos, size); - if (_pos >= _windowSize) - { - _pos = 0; - } - _streamPos = _pos; - } - - public void CopyBlock(int distance, int len) - { - int size = len; - int pos = _pos - distance - 1; - if (pos < 0) - { - pos += _windowSize; - } - for (; size > 0 && _pos < _windowSize && _total < _limit; size--) - { - if (pos >= _windowSize) - { - pos = 0; - } - _buffer[_pos++] = _buffer[pos++]; - _total++; - if (_pos >= _windowSize) - { - Flush(); - } - } - _pendingLen = size; - _pendingDist = distance; - } - - public void PutByte(byte b) - { - _buffer[_pos++] = b; + _buffer[_pos++] = _buffer[pos++]; _total++; if (_pos >= _windowSize) { Flush(); } } - - public byte GetByte(int distance) - { - int pos = _pos - distance - 1; - if (pos < 0) - { - pos += _windowSize; - } - return _buffer[pos]; - } - - public int CopyStream(Stream stream, int len) - { - int size = len; - while (size > 0 && _pos < _windowSize && _total < _limit) - { - int curSize = _windowSize - _pos; - if (curSize > _limit - _total) - { - curSize = (int)(_limit - _total); - } - if (curSize > size) - { - curSize = size; - } - int numReadBytes = stream.Read(_buffer, _pos, curSize); - if (numReadBytes == 0) - { - throw new DataErrorException(); - } - size -= numReadBytes; - _pos += numReadBytes; - _total += numReadBytes; - if (_pos >= _windowSize) - { - Flush(); - } - } - return len - size; - } - - public void SetLimit(long size) - { - _limit = _total + size; - } - - public bool HasSpace => _pos < _windowSize && _total < _limit; - - public bool HasPending => _pendingLen > 0; - - public int Read(byte[] buffer, int offset, int count) - { - if (_streamPos >= _pos) - { - return 0; - } - - int size = _pos - _streamPos; - if (size > count) - { - size = count; - } - Buffer.BlockCopy(_buffer, _streamPos, buffer, offset, size); - _streamPos += size; - if (_streamPos >= _windowSize) - { - _pos = 0; - _streamPos = 0; - } - return size; - } - - public void CopyPending() - { - if (_pendingLen > 0) - { - CopyBlock(_pendingDist, _pendingLen); - } - } - - public int AvailableBytes => _pos - _streamPos; + _pendingLen = size; + _pendingDist = distance; } + + public void PutByte(byte b) + { + _buffer[_pos++] = b; + _total++; + if (_pos >= _windowSize) + { + Flush(); + } + } + + public byte GetByte(int distance) + { + var pos = _pos - distance - 1; + if (pos < 0) + { + pos += _windowSize; + } + return _buffer[pos]; + } + + public int CopyStream(Stream stream, int len) + { + var size = len; + while (size > 0 && _pos < _windowSize && _total < _limit) + { + var curSize = _windowSize - _pos; + if (curSize > _limit - _total) + { + curSize = (int)(_limit - _total); + } + if (curSize > size) + { + curSize = size; + } + var numReadBytes = stream.Read(_buffer, _pos, curSize); + if (numReadBytes == 0) + { + throw new DataErrorException(); + } + size -= numReadBytes; + _pos += numReadBytes; + _total += numReadBytes; + if (_pos >= _windowSize) + { + Flush(); + } + } + return len - size; + } + + public void SetLimit(long size) + { + _limit = _total + size; + } + + public bool HasSpace => _pos < _windowSize && _total < _limit; + + public bool HasPending => _pendingLen > 0; + + public int Read(byte[] buffer, int offset, int count) + { + if (_streamPos >= _pos) + { + return 0; + } + + var size = _pos - _streamPos; + if (size > count) + { + size = count; + } + Buffer.BlockCopy(_buffer, _streamPos, buffer, offset, size); + _streamPos += size; + if (_streamPos >= _windowSize) + { + _pos = 0; + _streamPos = 0; + } + return size; + } + + public void CopyPending() + { + if (_pendingLen > 0) + { + CopyBlock(_pendingDist, _pendingLen); + } + } + + public int AvailableBytes => _pos - _streamPos; } diff --git a/src/SharpCompress/Compressors/LZMA/LZipStream.cs b/src/SharpCompress/Compressors/LZMA/LZipStream.cs index 912e4eff..5d799619 100644 --- a/src/SharpCompress/Compressors/LZMA/LZipStream.cs +++ b/src/SharpCompress/Compressors/LZMA/LZipStream.cs @@ -4,245 +4,244 @@ using System.IO; using SharpCompress.Crypto; using SharpCompress.IO; -namespace SharpCompress.Compressors.LZMA +namespace SharpCompress.Compressors.LZMA; + +// TODO: +// - Write as well as read +// - Multi-volume support +// - Use of the data size / member size values at the end of the stream + +/// +/// Stream supporting the LZIP format, as documented at http://www.nongnu.org/lzip/manual/lzip_manual.html +/// +public sealed class LZipStream : Stream { - // TODO: - // - Write as well as read - // - Multi-volume support - // - Use of the data size / member size values at the end of the stream + private readonly Stream _stream; + private readonly CountingWritableSubStream? _countingWritableSubStream; + private bool _disposed; + private bool _finished; - /// - /// Stream supporting the LZIP format, as documented at http://www.nongnu.org/lzip/manual/lzip_manual.html - /// - public sealed class LZipStream : Stream + private long _writeCount; + + public LZipStream(Stream stream, CompressionMode mode) { - private readonly Stream _stream; - private readonly CountingWritableSubStream? _countingWritableSubStream; - private bool _disposed; - private bool _finished; + Mode = mode; - private long _writeCount; - - public LZipStream(Stream stream, CompressionMode mode) + if (mode == CompressionMode.Decompress) { - Mode = mode; - - if (mode == CompressionMode.Decompress) + var dSize = ValidateAndReadSize(stream); + if (dSize == 0) { - int dSize = ValidateAndReadSize(stream); - if (dSize == 0) - { - throw new IOException("Not an LZip stream"); - } - byte[] properties = GetProperties(dSize); - _stream = new LzmaStream(properties, stream); - } - else - { - //default - int dSize = 104 * 1024; - WriteHeaderSize(stream); - - _countingWritableSubStream = new CountingWritableSubStream(stream); - _stream = new Crc32Stream( - new LzmaStream( - new LzmaEncoderProperties(true, dSize), - false, - _countingWritableSubStream - ) - ); + throw new IOException("Not an LZip stream"); } + var properties = GetProperties(dSize); + _stream = new LzmaStream(properties, stream); } - - public void Finish() + else { - if (!_finished) - { - if (Mode == CompressionMode.Compress) - { - var crc32Stream = (Crc32Stream)_stream; - crc32Stream.WrappedStream.Dispose(); - crc32Stream.Dispose(); - var compressedCount = _countingWritableSubStream!.Count; + //default + var dSize = 104 * 1024; + WriteHeaderSize(stream); - Span intBuf = stackalloc byte[8]; - BinaryPrimitives.WriteUInt32LittleEndian(intBuf, crc32Stream.Crc); - _countingWritableSubStream.Write(intBuf.Slice(0, 4)); - - BinaryPrimitives.WriteInt64LittleEndian(intBuf, _writeCount); - _countingWritableSubStream.Write(intBuf); - - //total with headers - BinaryPrimitives.WriteUInt64LittleEndian(intBuf, compressedCount + 6 + 20); - _countingWritableSubStream.Write(intBuf); - } - _finished = true; - } + _countingWritableSubStream = new CountingWritableSubStream(stream); + _stream = new Crc32Stream( + new LzmaStream( + new LzmaEncoderProperties(true, dSize), + false, + _countingWritableSubStream + ) + ); } + } - #region Stream methods - - protected override void Dispose(bool disposing) + public void Finish() + { + if (!_finished) { - if (_disposed) + if (Mode == CompressionMode.Compress) { - return; - } - _disposed = true; - if (disposing) - { - Finish(); - _stream.Dispose(); + var crc32Stream = (Crc32Stream)_stream; + crc32Stream.WrappedStream.Dispose(); + crc32Stream.Dispose(); + var compressedCount = _countingWritableSubStream!.Count; + + Span intBuf = stackalloc byte[8]; + BinaryPrimitives.WriteUInt32LittleEndian(intBuf, crc32Stream.Crc); + _countingWritableSubStream.Write(intBuf.Slice(0, 4)); + + BinaryPrimitives.WriteInt64LittleEndian(intBuf, _writeCount); + _countingWritableSubStream.Write(intBuf); + + //total with headers + BinaryPrimitives.WriteUInt64LittleEndian(intBuf, compressedCount + 6 + 20); + _countingWritableSubStream.Write(intBuf); } + _finished = true; } + } - public CompressionMode Mode { get; } + #region Stream methods - public override bool CanRead => Mode == CompressionMode.Decompress; - - public override bool CanSeek => false; - - public override bool CanWrite => Mode == CompressionMode.Compress; - - public override void Flush() + protected override void Dispose(bool disposing) + { + if (_disposed) { - _stream.Flush(); + return; } - - // TODO: Both Length and Position are sometimes feasible, but would require - // reading the output length when we initialize. - public override long Length => throw new NotImplementedException(); - - public override long Position + _disposed = true; + if (disposing) { - get => throw new NotImplementedException(); - set => throw new NotImplementedException(); + Finish(); + _stream.Dispose(); } + } - public override int Read(byte[] buffer, int offset, int count) => - _stream.Read(buffer, offset, count); + public CompressionMode Mode { get; } - public override int ReadByte() => _stream.ReadByte(); + public override bool CanRead => Mode == CompressionMode.Decompress; - public override long Seek(long offset, SeekOrigin origin) => - throw new NotSupportedException(); + public override bool CanSeek => false; - public override void SetLength(long value) => throw new NotImplementedException(); + public override bool CanWrite => Mode == CompressionMode.Compress; + + public override void Flush() + { + _stream.Flush(); + } + + // TODO: Both Length and Position are sometimes feasible, but would require + // reading the output length when we initialize. + public override long Length => throw new NotImplementedException(); + + public override long Position + { + get => throw new NotImplementedException(); + set => throw new NotImplementedException(); + } + + public override int Read(byte[] buffer, int offset, int count) => + _stream.Read(buffer, offset, count); + + public override int ReadByte() => _stream.ReadByte(); + + public override long Seek(long offset, SeekOrigin origin) => + throw new NotSupportedException(); + + public override void SetLength(long value) => throw new NotImplementedException(); #if !NETFRAMEWORK && !NETSTANDARD2_0 - public override int Read(Span buffer) - { - return _stream.Read(buffer); - } + public override int Read(Span buffer) + { + return _stream.Read(buffer); + } - public override void Write(ReadOnlySpan buffer) - { - _stream.Write(buffer); + public override void Write(ReadOnlySpan buffer) + { + _stream.Write(buffer); - _writeCount += buffer.Length; - } + _writeCount += buffer.Length; + } #endif - public override void Write(byte[] buffer, int offset, int count) - { - _stream.Write(buffer, offset, count); - _writeCount += count; - } - - public override void WriteByte(byte value) - { - _stream.WriteByte(value); - ++_writeCount; - } - - #endregion - - /// - /// Determines if the given stream is positioned at the start of a v1 LZip - /// file, as indicated by the ASCII characters "LZIP" and a version byte - /// of 1, followed by at least one byte. - /// - /// The stream to read from. Must not be null. - /// true if the given stream is an LZip file, false otherwise. - public static bool IsLZipFile(Stream stream) => ValidateAndReadSize(stream) != 0; - - /// - /// Reads the 6-byte header of the stream, and returns 0 if either the header - /// couldn't be read or it isn't a validate LZIP header, or the dictionary - /// size if it *is* a valid LZIP file. - /// - public static int ValidateAndReadSize(Stream stream) - { - if (stream is null) - { - throw new ArgumentNullException(nameof(stream)); - } - - // Read the header - Span header = stackalloc byte[6]; - int n = stream.Read(header); - - // TODO: Handle reading only part of the header? - - if (n != 6) - { - return 0; - } - - if ( - header[0] != 'L' - || header[1] != 'Z' - || header[2] != 'I' - || header[3] != 'P' - || header[4] != 1 /* version 1 */ - ) - { - return 0; - } - int basePower = header[5] & 0x1F; - int subtractionNumerator = (header[5] & 0xE0) >> 5; - return (1 << basePower) - subtractionNumerator * (1 << (basePower - 4)); - } - - private static readonly byte[] headerBytes = new byte[6] - { - (byte)'L', - (byte)'Z', - (byte)'I', - (byte)'P', - 1, - 113 - }; - - public static void WriteHeaderSize(Stream stream) - { - if (stream is null) - { - throw new ArgumentNullException(nameof(stream)); - } - - // hard coding the dictionary size encoding - stream.Write(headerBytes, 0, 6); - } - - /// - /// Creates a byte array to communicate the parameters and dictionary size to LzmaStream. - /// - private static byte[] GetProperties(int dictionarySize) => - new byte[] - { - // Parameters as per http://www.nongnu.org/lzip/manual/lzip_manual.html#Stream-format - // but encoded as a single byte in the format LzmaStream expects. - // literal_context_bits = 3 - // literal_pos_state_bits = 0 - // pos_state_bits = 2 - 93, - // Dictionary size as 4-byte little-endian value - (byte)(dictionarySize & 0xff), - (byte)((dictionarySize >> 8) & 0xff), - (byte)((dictionarySize >> 16) & 0xff), - (byte)((dictionarySize >> 24) & 0xff) - }; + public override void Write(byte[] buffer, int offset, int count) + { + _stream.Write(buffer, offset, count); + _writeCount += count; } + + public override void WriteByte(byte value) + { + _stream.WriteByte(value); + ++_writeCount; + } + + #endregion + + /// + /// Determines if the given stream is positioned at the start of a v1 LZip + /// file, as indicated by the ASCII characters "LZIP" and a version byte + /// of 1, followed by at least one byte. + /// + /// The stream to read from. Must not be null. + /// true if the given stream is an LZip file, false otherwise. + public static bool IsLZipFile(Stream stream) => ValidateAndReadSize(stream) != 0; + + /// + /// Reads the 6-byte header of the stream, and returns 0 if either the header + /// couldn't be read or it isn't a validate LZIP header, or the dictionary + /// size if it *is* a valid LZIP file. + /// + public static int ValidateAndReadSize(Stream stream) + { + if (stream is null) + { + throw new ArgumentNullException(nameof(stream)); + } + + // Read the header + Span header = stackalloc byte[6]; + var n = stream.Read(header); + + // TODO: Handle reading only part of the header? + + if (n != 6) + { + return 0; + } + + if ( + header[0] != 'L' + || header[1] != 'Z' + || header[2] != 'I' + || header[3] != 'P' + || header[4] != 1 /* version 1 */ + ) + { + return 0; + } + var basePower = header[5] & 0x1F; + var subtractionNumerator = (header[5] & 0xE0) >> 5; + return (1 << basePower) - (subtractionNumerator * (1 << (basePower - 4))); + } + + private static readonly byte[] headerBytes = new byte[6] + { + (byte)'L', + (byte)'Z', + (byte)'I', + (byte)'P', + 1, + 113 + }; + + public static void WriteHeaderSize(Stream stream) + { + if (stream is null) + { + throw new ArgumentNullException(nameof(stream)); + } + + // hard coding the dictionary size encoding + stream.Write(headerBytes, 0, 6); + } + + /// + /// Creates a byte array to communicate the parameters and dictionary size to LzmaStream. + /// + private static byte[] GetProperties(int dictionarySize) => + new byte[] + { + // Parameters as per http://www.nongnu.org/lzip/manual/lzip_manual.html#Stream-format + // but encoded as a single byte in the format LzmaStream expects. + // literal_context_bits = 3 + // literal_pos_state_bits = 0 + // pos_state_bits = 2 + 93, + // Dictionary size as 4-byte little-endian value + (byte)(dictionarySize & 0xff), + (byte)((dictionarySize >> 8) & 0xff), + (byte)((dictionarySize >> 16) & 0xff), + (byte)((dictionarySize >> 24) & 0xff) + }; } diff --git a/src/SharpCompress/Compressors/LZMA/Log.cs b/src/SharpCompress/Compressors/LZMA/Log.cs index a31d2b69..d19a46d2 100644 --- a/src/SharpCompress/Compressors/LZMA/Log.cs +++ b/src/SharpCompress/Compressors/LZMA/Log.cs @@ -1,86 +1,85 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; -namespace SharpCompress.Compressors.LZMA +namespace SharpCompress.Compressors.LZMA; + +internal static class Log { - internal static class Log + private static readonly Stack INDENT = new Stack(); + private static bool NEEDS_INDENT = true; + + static Log() { - private static readonly Stack INDENT = new Stack(); - private static bool NEEDS_INDENT = true; + INDENT.Push(""); + } - static Log() + public static void PushIndent(string indent = " ") + { + INDENT.Push(INDENT.Peek() + indent); + } + + public static void PopIndent() + { + if (INDENT.Count == 1) { - INDENT.Push(""); + throw new InvalidOperationException(); } - public static void PushIndent(string indent = " ") - { - INDENT.Push(INDENT.Peek() + indent); - } + INDENT.Pop(); + } - public static void PopIndent() + private static void EnsureIndent() + { + if (NEEDS_INDENT) { - if (INDENT.Count == 1) - { - throw new InvalidOperationException(); - } - - INDENT.Pop(); - } - - private static void EnsureIndent() - { - if (NEEDS_INDENT) - { - NEEDS_INDENT = false; - Debug.Write(INDENT.Peek()); - } - } - - public static void Write(object value) - { - EnsureIndent(); - Debug.Write(value); - } - - public static void Write(string text) - { - EnsureIndent(); - Debug.Write(text); - } - - public static void Write(string format, params object[] args) - { - EnsureIndent(); - Debug.Write(string.Format(format, args)); - } - - public static void WriteLine() - { - Debug.WriteLine(""); - NEEDS_INDENT = true; - } - - public static void WriteLine(object value) - { - EnsureIndent(); - Debug.WriteLine(value); - NEEDS_INDENT = true; - } - - public static void WriteLine(string text) - { - EnsureIndent(); - Debug.WriteLine(text); - NEEDS_INDENT = true; - } - - public static void WriteLine(string format, params object[] args) - { - EnsureIndent(); - Debug.WriteLine(string.Format(format, args)); - NEEDS_INDENT = true; + NEEDS_INDENT = false; + Debug.Write(INDENT.Peek()); } } + + public static void Write(object value) + { + EnsureIndent(); + Debug.Write(value); + } + + public static void Write(string text) + { + EnsureIndent(); + Debug.Write(text); + } + + public static void Write(string format, params object[] args) + { + EnsureIndent(); + Debug.Write(string.Format(format, args)); + } + + public static void WriteLine() + { + Debug.WriteLine(""); + NEEDS_INDENT = true; + } + + public static void WriteLine(object value) + { + EnsureIndent(); + Debug.WriteLine(value); + NEEDS_INDENT = true; + } + + public static void WriteLine(string text) + { + EnsureIndent(); + Debug.WriteLine(text); + NEEDS_INDENT = true; + } + + public static void WriteLine(string format, params object[] args) + { + EnsureIndent(); + Debug.WriteLine(string.Format(format, args)); + NEEDS_INDENT = true; + } } diff --git a/src/SharpCompress/Compressors/LZMA/LzmaBase.cs b/src/SharpCompress/Compressors/LZMA/LzmaBase.cs index 74ca3cfb..e1d98639 100644 --- a/src/SharpCompress/Compressors/LZMA/LzmaBase.cs +++ b/src/SharpCompress/Compressors/LZMA/LzmaBase.cs @@ -1,109 +1,108 @@ -namespace SharpCompress.Compressors.LZMA +namespace SharpCompress.Compressors.LZMA; + +internal abstract class Base { - internal abstract class Base + public const uint K_NUM_REP_DISTANCES = 4; + public const uint K_NUM_STATES = 12; + + // static byte []kLiteralNextStates = {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5}; + // static byte []kMatchNextStates = {7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10}; + // static byte []kRepNextStates = {8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11}; + // static byte []kShortRepNextStates = {9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11}; + + public struct State { - public const uint K_NUM_REP_DISTANCES = 4; - public const uint K_NUM_STATES = 12; + public uint _index; - // static byte []kLiteralNextStates = {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5}; - // static byte []kMatchNextStates = {7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10}; - // static byte []kRepNextStates = {8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11}; - // static byte []kShortRepNextStates = {9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11}; - - public struct State + public void Init() { - public uint _index; + _index = 0; + } - public void Init() + public void UpdateChar() + { + if (_index < 4) { _index = 0; } - - public void UpdateChar() + else if (_index < 10) { - if (_index < 4) - { - _index = 0; - } - else if (_index < 10) - { - _index -= 3; - } - else - { - _index -= 6; - } + _index -= 3; } - - public void UpdateMatch() + else { - _index = (uint)(_index < 7 ? 7 : 10); - } - - public void UpdateRep() - { - _index = (uint)(_index < 7 ? 8 : 11); - } - - public void UpdateShortRep() - { - _index = (uint)(_index < 7 ? 9 : 11); - } - - public bool IsCharState() - { - return _index < 7; + _index -= 6; } } - public const int K_NUM_POS_SLOT_BITS = 6; - public const int K_DIC_LOG_SIZE_MIN = 0; - - // public const int kDicLogSizeMax = 30; - // public const uint kDistTableSizeMax = kDicLogSizeMax * 2; - - public const int K_NUM_LEN_TO_POS_STATES_BITS = 2; // it's for speed optimization - public const uint K_NUM_LEN_TO_POS_STATES = 1 << K_NUM_LEN_TO_POS_STATES_BITS; - - public const uint K_MATCH_MIN_LEN = 2; - - public static uint GetLenToPosState(uint len) + public void UpdateMatch() { - len -= K_MATCH_MIN_LEN; - if (len < K_NUM_LEN_TO_POS_STATES) - { - return len; - } - return K_NUM_LEN_TO_POS_STATES - 1; + _index = (uint)(_index < 7 ? 7 : 10); } - public const int K_NUM_ALIGN_BITS = 4; - public const uint K_ALIGN_TABLE_SIZE = 1 << K_NUM_ALIGN_BITS; - public const uint K_ALIGN_MASK = (K_ALIGN_TABLE_SIZE - 1); + public void UpdateRep() + { + _index = (uint)(_index < 7 ? 8 : 11); + } - public const uint K_START_POS_MODEL_INDEX = 4; - public const uint K_END_POS_MODEL_INDEX = 14; - public const uint K_NUM_POS_MODELS = K_END_POS_MODEL_INDEX - K_START_POS_MODEL_INDEX; + public void UpdateShortRep() + { + _index = (uint)(_index < 7 ? 9 : 11); + } - public const uint K_NUM_FULL_DISTANCES = 1 << ((int)K_END_POS_MODEL_INDEX / 2); - - public const uint K_NUM_LIT_POS_STATES_BITS_ENCODING_MAX = 4; - public const uint K_NUM_LIT_CONTEXT_BITS_MAX = 8; - - public const int K_NUM_POS_STATES_BITS_MAX = 4; - public const uint K_NUM_POS_STATES_MAX = (1 << K_NUM_POS_STATES_BITS_MAX); - public const int K_NUM_POS_STATES_BITS_ENCODING_MAX = 4; - public const uint K_NUM_POS_STATES_ENCODING_MAX = (1 << K_NUM_POS_STATES_BITS_ENCODING_MAX); - - public const int K_NUM_LOW_LEN_BITS = 3; - public const int K_NUM_MID_LEN_BITS = 3; - public const int K_NUM_HIGH_LEN_BITS = 8; - public const uint K_NUM_LOW_LEN_SYMBOLS = 1 << K_NUM_LOW_LEN_BITS; - public const uint K_NUM_MID_LEN_SYMBOLS = 1 << K_NUM_MID_LEN_BITS; - - public const uint K_NUM_LEN_SYMBOLS = - K_NUM_LOW_LEN_SYMBOLS + K_NUM_MID_LEN_SYMBOLS + (1 << K_NUM_HIGH_LEN_BITS); - - public const uint K_MATCH_MAX_LEN = K_MATCH_MIN_LEN + K_NUM_LEN_SYMBOLS - 1; + public bool IsCharState() + { + return _index < 7; + } } + + public const int K_NUM_POS_SLOT_BITS = 6; + public const int K_DIC_LOG_SIZE_MIN = 0; + + // public const int kDicLogSizeMax = 30; + // public const uint kDistTableSizeMax = kDicLogSizeMax * 2; + + public const int K_NUM_LEN_TO_POS_STATES_BITS = 2; // it's for speed optimization + public const uint K_NUM_LEN_TO_POS_STATES = 1 << K_NUM_LEN_TO_POS_STATES_BITS; + + public const uint K_MATCH_MIN_LEN = 2; + + public static uint GetLenToPosState(uint len) + { + len -= K_MATCH_MIN_LEN; + if (len < K_NUM_LEN_TO_POS_STATES) + { + return len; + } + return K_NUM_LEN_TO_POS_STATES - 1; + } + + public const int K_NUM_ALIGN_BITS = 4; + public const uint K_ALIGN_TABLE_SIZE = 1 << K_NUM_ALIGN_BITS; + public const uint K_ALIGN_MASK = (K_ALIGN_TABLE_SIZE - 1); + + public const uint K_START_POS_MODEL_INDEX = 4; + public const uint K_END_POS_MODEL_INDEX = 14; + public const uint K_NUM_POS_MODELS = K_END_POS_MODEL_INDEX - K_START_POS_MODEL_INDEX; + + public const uint K_NUM_FULL_DISTANCES = 1 << ((int)K_END_POS_MODEL_INDEX / 2); + + public const uint K_NUM_LIT_POS_STATES_BITS_ENCODING_MAX = 4; + public const uint K_NUM_LIT_CONTEXT_BITS_MAX = 8; + + public const int K_NUM_POS_STATES_BITS_MAX = 4; + public const uint K_NUM_POS_STATES_MAX = (1 << K_NUM_POS_STATES_BITS_MAX); + public const int K_NUM_POS_STATES_BITS_ENCODING_MAX = 4; + public const uint K_NUM_POS_STATES_ENCODING_MAX = (1 << K_NUM_POS_STATES_BITS_ENCODING_MAX); + + public const int K_NUM_LOW_LEN_BITS = 3; + public const int K_NUM_MID_LEN_BITS = 3; + public const int K_NUM_HIGH_LEN_BITS = 8; + public const uint K_NUM_LOW_LEN_SYMBOLS = 1 << K_NUM_LOW_LEN_BITS; + public const uint K_NUM_MID_LEN_SYMBOLS = 1 << K_NUM_MID_LEN_BITS; + + public const uint K_NUM_LEN_SYMBOLS = + K_NUM_LOW_LEN_SYMBOLS + K_NUM_MID_LEN_SYMBOLS + (1 << K_NUM_HIGH_LEN_BITS); + + public const uint K_MATCH_MAX_LEN = K_MATCH_MIN_LEN + K_NUM_LEN_SYMBOLS - 1; } diff --git a/src/SharpCompress/Compressors/LZMA/LzmaDecoder.cs b/src/SharpCompress/Compressors/LZMA/LzmaDecoder.cs index a3841197..8889dd68 100644 --- a/src/SharpCompress/Compressors/LZMA/LzmaDecoder.cs +++ b/src/SharpCompress/Compressors/LZMA/LzmaDecoder.cs @@ -5,518 +5,517 @@ using System.IO; using SharpCompress.Compressors.LZMA.LZ; using SharpCompress.Compressors.LZMA.RangeCoder; -namespace SharpCompress.Compressors.LZMA +namespace SharpCompress.Compressors.LZMA; + +public class Decoder : ICoder, ISetDecoderProperties // ,System.IO.Stream { - public class Decoder : ICoder, ISetDecoderProperties // ,System.IO.Stream + private class LenDecoder { - private class LenDecoder - { - private BitDecoder _choice = new BitDecoder(); - private BitDecoder _choice2 = new BitDecoder(); - 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 uint _numPosStates; - - public void Create(uint numPosStates) - { - for (uint posState = _numPosStates; posState < numPosStates; posState++) - { - _lowCoder[posState] = new BitTreeDecoder(Base.K_NUM_LOW_LEN_BITS); - _midCoder[posState] = new BitTreeDecoder(Base.K_NUM_MID_LEN_BITS); - } - _numPosStates = numPosStates; - } - - public void Init() - { - _choice.Init(); - for (uint posState = 0; posState < _numPosStates; posState++) - { - _lowCoder[posState].Init(); - _midCoder[posState].Init(); - } - _choice2.Init(); - _highCoder.Init(); - } - - public uint Decode(RangeCoder.Decoder rangeDecoder, uint posState) - { - if (_choice.Decode(rangeDecoder) == 0) - { - return _lowCoder[posState].Decode(rangeDecoder); - } - uint symbol = Base.K_NUM_LOW_LEN_SYMBOLS; - if (_choice2.Decode(rangeDecoder) == 0) - { - symbol += _midCoder[posState].Decode(rangeDecoder); - } - else - { - symbol += Base.K_NUM_MID_LEN_SYMBOLS; - symbol += _highCoder.Decode(rangeDecoder); - } - return symbol; - } - } - - private class LiteralDecoder - { - private struct Decoder2 - { - private BitDecoder[] _decoders; - - public void Create() - { - _decoders = new BitDecoder[0x300]; - } - - public void Init() - { - for (int i = 0; i < 0x300; i++) - { - _decoders[i].Init(); - } - } - - public byte DecodeNormal(RangeCoder.Decoder rangeDecoder) - { - uint symbol = 1; - do - { - symbol = (symbol << 1) | _decoders[symbol].Decode(rangeDecoder); - } while (symbol < 0x100); - return (byte)symbol; - } - - public byte DecodeWithMatchByte(RangeCoder.Decoder rangeDecoder, byte matchByte) - { - uint symbol = 1; - do - { - uint matchBit = (uint)(matchByte >> 7) & 1; - matchByte <<= 1; - uint bit = _decoders[((1 + matchBit) << 8) + symbol].Decode(rangeDecoder); - symbol = (symbol << 1) | bit; - if (matchBit != bit) - { - while (symbol < 0x100) - { - symbol = (symbol << 1) | _decoders[symbol].Decode(rangeDecoder); - } - break; - } - } while (symbol < 0x100); - return (byte)symbol; - } - } - - private Decoder2[] _coders; - private int _numPrevBits; - private int _numPosBits; - private uint _posMask; - - public void Create(int numPosBits, int numPrevBits) - { - if (_coders != null && _numPrevBits == numPrevBits && _numPosBits == numPosBits) - { - return; - } - _numPosBits = numPosBits; - _posMask = ((uint)1 << numPosBits) - 1; - _numPrevBits = numPrevBits; - uint numStates = (uint)1 << (_numPrevBits + _numPosBits); - _coders = new Decoder2[numStates]; - for (uint i = 0; i < numStates; i++) - { - _coders[i].Create(); - } - } - - public void Init() - { - uint numStates = (uint)1 << (_numPrevBits + _numPosBits); - for (uint i = 0; i < numStates; i++) - { - _coders[i].Init(); - } - } - - private uint GetState(uint pos, byte prevByte) - { - return ((pos & _posMask) << _numPrevBits) + (uint)(prevByte >> (8 - _numPrevBits)); - } - - public byte DecodeNormal(RangeCoder.Decoder rangeDecoder, uint pos, byte prevByte) - { - return _coders[GetState(pos, prevByte)].DecodeNormal(rangeDecoder); - } - - public byte DecodeWithMatchByte( - RangeCoder.Decoder rangeDecoder, - uint pos, - byte prevByte, - byte matchByte - ) - { - return _coders[GetState(pos, prevByte)].DecodeWithMatchByte( - rangeDecoder, - matchByte - ); - } - } - - private OutWindow _outWindow; - - private readonly BitDecoder[] _isMatchDecoders = new BitDecoder[ - Base.K_NUM_STATES << Base.K_NUM_POS_STATES_BITS_MAX + private BitDecoder _choice = new BitDecoder(); + private BitDecoder _choice2 = new BitDecoder(); + private readonly BitTreeDecoder[] _lowCoder = new BitTreeDecoder[ + Base.K_NUM_POS_STATES_MAX ]; - private readonly BitDecoder[] _isRepDecoders = new BitDecoder[Base.K_NUM_STATES]; - private readonly BitDecoder[] _isRepG0Decoders = new BitDecoder[Base.K_NUM_STATES]; - private readonly BitDecoder[] _isRepG1Decoders = new BitDecoder[Base.K_NUM_STATES]; - private readonly BitDecoder[] _isRepG2Decoders = new BitDecoder[Base.K_NUM_STATES]; - private readonly BitDecoder[] _isRep0LongDecoders = new BitDecoder[ - Base.K_NUM_STATES << Base.K_NUM_POS_STATES_BITS_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 uint _numPosStates; - private readonly BitTreeDecoder[] _posSlotDecoder = new BitTreeDecoder[ - Base.K_NUM_LEN_TO_POS_STATES - ]; - private readonly BitDecoder[] _posDecoders = new BitDecoder[ - Base.K_NUM_FULL_DISTANCES - Base.K_END_POS_MODEL_INDEX - ]; - - private BitTreeDecoder _posAlignDecoder = new BitTreeDecoder(Base.K_NUM_ALIGN_BITS); - - private readonly LenDecoder _lenDecoder = new LenDecoder(); - private readonly LenDecoder _repLenDecoder = new LenDecoder(); - - private readonly LiteralDecoder _literalDecoder = new LiteralDecoder(); - - private int _dictionarySize; - - private uint _posStateMask; - - private Base.State _state = new Base.State(); - private uint _rep0, - _rep1, - _rep2, - _rep3; - - public Decoder() + public void Create(uint numPosStates) { - _dictionarySize = -1; - for (int i = 0; i < Base.K_NUM_LEN_TO_POS_STATES; i++) + for (var posState = _numPosStates; posState < numPosStates; posState++) { - _posSlotDecoder[i] = new BitTreeDecoder(Base.K_NUM_POS_SLOT_BITS); + _lowCoder[posState] = new BitTreeDecoder(Base.K_NUM_LOW_LEN_BITS); + _midCoder[posState] = new BitTreeDecoder(Base.K_NUM_MID_LEN_BITS); } + _numPosStates = numPosStates; } - private void CreateDictionary() + public void Init() { - if (_dictionarySize < 0) + _choice.Init(); + for (uint posState = 0; posState < _numPosStates; posState++) { - throw new InvalidParamException(); + _lowCoder[posState].Init(); + _midCoder[posState].Init(); } - _outWindow = new OutWindow(); - int blockSize = Math.Max(_dictionarySize, (1 << 12)); - _outWindow.Create(blockSize); + _choice2.Init(); + _highCoder.Init(); } - private void SetLiteralProperties(int lp, int lc) + public uint Decode(RangeCoder.Decoder rangeDecoder, uint posState) { - if (lp > 8) + if (_choice.Decode(rangeDecoder) == 0) { - throw new InvalidParamException(); + return _lowCoder[posState].Decode(rangeDecoder); } - if (lc > 8) + var symbol = Base.K_NUM_LOW_LEN_SYMBOLS; + if (_choice2.Decode(rangeDecoder) == 0) { - throw new InvalidParamException(); - } - _literalDecoder.Create(lp, lc); - } - - private void SetPosBitsProperties(int pb) - { - if (pb > Base.K_NUM_POS_STATES_BITS_MAX) - { - throw new InvalidParamException(); - } - uint numPosStates = (uint)1 << pb; - _lenDecoder.Create(numPosStates); - _repLenDecoder.Create(numPosStates); - _posStateMask = numPosStates - 1; - } - - private void Init() - { - uint i; - for (i = 0; i < Base.K_NUM_STATES; i++) - { - for (uint j = 0; j <= _posStateMask; j++) - { - uint index = (i << Base.K_NUM_POS_STATES_BITS_MAX) + j; - _isMatchDecoders[index].Init(); - _isRep0LongDecoders[index].Init(); - } - _isRepDecoders[i].Init(); - _isRepG0Decoders[i].Init(); - _isRepG1Decoders[i].Init(); - _isRepG2Decoders[i].Init(); - } - - _literalDecoder.Init(); - for (i = 0; i < Base.K_NUM_LEN_TO_POS_STATES; i++) - { - _posSlotDecoder[i].Init(); - } - - // _PosSpecDecoder.Init(); - for (i = 0; i < Base.K_NUM_FULL_DISTANCES - Base.K_END_POS_MODEL_INDEX; i++) - { - _posDecoders[i].Init(); - } - - _lenDecoder.Init(); - _repLenDecoder.Init(); - _posAlignDecoder.Init(); - - _state.Init(); - _rep0 = 0; - _rep1 = 0; - _rep2 = 0; - _rep3 = 0; - } - - public void Code( - Stream inStream, - Stream outStream, - Int64 inSize, - Int64 outSize, - ICodeProgress progress - ) - { - if (_outWindow is null) - { - CreateDictionary(); - } - _outWindow.Init(outStream); - if (outSize > 0) - { - _outWindow.SetLimit(outSize); + symbol += _midCoder[posState].Decode(rangeDecoder); } else { - _outWindow.SetLimit(Int64.MaxValue - _outWindow._total); + symbol += Base.K_NUM_MID_LEN_SYMBOLS; + symbol += _highCoder.Decode(rangeDecoder); + } + return symbol; + } + } + + private class LiteralDecoder + { + private struct Decoder2 + { + private BitDecoder[] _decoders; + + public void Create() + { + _decoders = new BitDecoder[0x300]; } - RangeCoder.Decoder rangeDecoder = new RangeCoder.Decoder(); - rangeDecoder.Init(inStream); + public void Init() + { + for (var i = 0; i < 0x300; i++) + { + _decoders[i].Init(); + } + } - Code(_dictionarySize, _outWindow, rangeDecoder); + public byte DecodeNormal(RangeCoder.Decoder rangeDecoder) + { + uint symbol = 1; + do + { + symbol = (symbol << 1) | _decoders[symbol].Decode(rangeDecoder); + } while (symbol < 0x100); + return (byte)symbol; + } - _outWindow.ReleaseStream(); - rangeDecoder.ReleaseStream(); - - _outWindow = null; + public byte DecodeWithMatchByte(RangeCoder.Decoder rangeDecoder, byte matchByte) + { + uint symbol = 1; + do + { + var matchBit = (uint)(matchByte >> 7) & 1; + matchByte <<= 1; + var bit = _decoders[((1 + matchBit) << 8) + symbol].Decode(rangeDecoder); + symbol = (symbol << 1) | bit; + if (matchBit != bit) + { + while (symbol < 0x100) + { + symbol = (symbol << 1) | _decoders[symbol].Decode(rangeDecoder); + } + break; + } + } while (symbol < 0x100); + return (byte)symbol; + } } - internal bool Code(int dictionarySize, OutWindow outWindow, RangeCoder.Decoder rangeDecoder) + private Decoder2[] _coders; + private int _numPrevBits; + private int _numPosBits; + private uint _posMask; + + public void Create(int numPosBits, int numPrevBits) { - int dictionarySizeCheck = Math.Max(dictionarySize, 1); - - outWindow.CopyPending(); - - while (outWindow.HasSpace) + if (_coders != null && _numPrevBits == numPrevBits && _numPosBits == numPosBits) { - uint posState = (uint)outWindow._total & _posStateMask; - if ( - _isMatchDecoders[ - (_state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState - ].Decode(rangeDecoder) == 0 - ) + return; + } + _numPosBits = numPosBits; + _posMask = ((uint)1 << numPosBits) - 1; + _numPrevBits = numPrevBits; + var numStates = (uint)1 << (_numPrevBits + _numPosBits); + _coders = new Decoder2[numStates]; + for (uint i = 0; i < numStates; i++) + { + _coders[i].Create(); + } + } + + public void Init() + { + var numStates = (uint)1 << (_numPrevBits + _numPosBits); + for (uint i = 0; i < numStates; i++) + { + _coders[i].Init(); + } + } + + private uint GetState(uint pos, byte prevByte) + { + return ((pos & _posMask) << _numPrevBits) + (uint)(prevByte >> (8 - _numPrevBits)); + } + + public byte DecodeNormal(RangeCoder.Decoder rangeDecoder, uint pos, byte prevByte) + { + return _coders[GetState(pos, prevByte)].DecodeNormal(rangeDecoder); + } + + public byte DecodeWithMatchByte( + RangeCoder.Decoder rangeDecoder, + uint pos, + byte prevByte, + byte matchByte + ) + { + return _coders[GetState(pos, prevByte)].DecodeWithMatchByte( + rangeDecoder, + matchByte + ); + } + } + + private OutWindow _outWindow; + + private readonly BitDecoder[] _isMatchDecoders = new BitDecoder[ + Base.K_NUM_STATES << Base.K_NUM_POS_STATES_BITS_MAX + ]; + private readonly BitDecoder[] _isRepDecoders = new BitDecoder[Base.K_NUM_STATES]; + private readonly BitDecoder[] _isRepG0Decoders = new BitDecoder[Base.K_NUM_STATES]; + private readonly BitDecoder[] _isRepG1Decoders = new BitDecoder[Base.K_NUM_STATES]; + private readonly BitDecoder[] _isRepG2Decoders = new BitDecoder[Base.K_NUM_STATES]; + private readonly BitDecoder[] _isRep0LongDecoders = new BitDecoder[ + Base.K_NUM_STATES << Base.K_NUM_POS_STATES_BITS_MAX + ]; + + private readonly BitTreeDecoder[] _posSlotDecoder = new BitTreeDecoder[ + Base.K_NUM_LEN_TO_POS_STATES + ]; + private readonly BitDecoder[] _posDecoders = new BitDecoder[ + Base.K_NUM_FULL_DISTANCES - Base.K_END_POS_MODEL_INDEX + ]; + + private BitTreeDecoder _posAlignDecoder = new BitTreeDecoder(Base.K_NUM_ALIGN_BITS); + + private readonly LenDecoder _lenDecoder = new LenDecoder(); + private readonly LenDecoder _repLenDecoder = new LenDecoder(); + + private readonly LiteralDecoder _literalDecoder = new LiteralDecoder(); + + private int _dictionarySize; + + private uint _posStateMask; + + private Base.State _state = new Base.State(); + private uint _rep0, + _rep1, + _rep2, + _rep3; + + public Decoder() + { + _dictionarySize = -1; + for (var i = 0; i < Base.K_NUM_LEN_TO_POS_STATES; i++) + { + _posSlotDecoder[i] = new BitTreeDecoder(Base.K_NUM_POS_SLOT_BITS); + } + } + + private void CreateDictionary() + { + if (_dictionarySize < 0) + { + throw new InvalidParamException(); + } + _outWindow = new OutWindow(); + var blockSize = Math.Max(_dictionarySize, (1 << 12)); + _outWindow.Create(blockSize); + } + + private void SetLiteralProperties(int lp, int lc) + { + if (lp > 8) + { + throw new InvalidParamException(); + } + if (lc > 8) + { + throw new InvalidParamException(); + } + _literalDecoder.Create(lp, lc); + } + + private void SetPosBitsProperties(int pb) + { + if (pb > Base.K_NUM_POS_STATES_BITS_MAX) + { + throw new InvalidParamException(); + } + var numPosStates = (uint)1 << pb; + _lenDecoder.Create(numPosStates); + _repLenDecoder.Create(numPosStates); + _posStateMask = numPosStates - 1; + } + + private void Init() + { + uint i; + for (i = 0; i < Base.K_NUM_STATES; i++) + { + for (uint j = 0; j <= _posStateMask; j++) + { + var index = (i << Base.K_NUM_POS_STATES_BITS_MAX) + j; + _isMatchDecoders[index].Init(); + _isRep0LongDecoders[index].Init(); + } + _isRepDecoders[i].Init(); + _isRepG0Decoders[i].Init(); + _isRepG1Decoders[i].Init(); + _isRepG2Decoders[i].Init(); + } + + _literalDecoder.Init(); + for (i = 0; i < Base.K_NUM_LEN_TO_POS_STATES; i++) + { + _posSlotDecoder[i].Init(); + } + + // _PosSpecDecoder.Init(); + for (i = 0; i < Base.K_NUM_FULL_DISTANCES - Base.K_END_POS_MODEL_INDEX; i++) + { + _posDecoders[i].Init(); + } + + _lenDecoder.Init(); + _repLenDecoder.Init(); + _posAlignDecoder.Init(); + + _state.Init(); + _rep0 = 0; + _rep1 = 0; + _rep2 = 0; + _rep3 = 0; + } + + public void Code( + Stream inStream, + Stream outStream, + long inSize, + long outSize, + ICodeProgress progress + ) + { + if (_outWindow is null) + { + CreateDictionary(); + } + _outWindow.Init(outStream); + if (outSize > 0) + { + _outWindow.SetLimit(outSize); + } + else + { + _outWindow.SetLimit(long.MaxValue - _outWindow._total); + } + + var rangeDecoder = new RangeCoder.Decoder(); + rangeDecoder.Init(inStream); + + Code(_dictionarySize, _outWindow, rangeDecoder); + + _outWindow.ReleaseStream(); + rangeDecoder.ReleaseStream(); + + _outWindow = null; + } + + internal bool Code(int dictionarySize, OutWindow outWindow, RangeCoder.Decoder rangeDecoder) + { + var dictionarySizeCheck = Math.Max(dictionarySize, 1); + + outWindow.CopyPending(); + + while (outWindow.HasSpace) + { + var posState = (uint)outWindow._total & _posStateMask; + if ( + _isMatchDecoders[ + (_state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState + ].Decode(rangeDecoder) == 0 + ) + { + byte b; + var prevByte = outWindow.GetByte(0); + if (!_state.IsCharState()) { - byte b; - byte prevByte = outWindow.GetByte(0); - if (!_state.IsCharState()) - { - b = _literalDecoder.DecodeWithMatchByte( - rangeDecoder, - (uint)outWindow._total, - prevByte, - outWindow.GetByte((int)_rep0) - ); - } - else - { - b = _literalDecoder.DecodeNormal( - rangeDecoder, - (uint)outWindow._total, - prevByte - ); - } - outWindow.PutByte(b); - _state.UpdateChar(); + b = _literalDecoder.DecodeWithMatchByte( + rangeDecoder, + (uint)outWindow._total, + prevByte, + outWindow.GetByte((int)_rep0) + ); } else { - uint len; - if (_isRepDecoders[_state._index].Decode(rangeDecoder) == 1) + b = _literalDecoder.DecodeNormal( + rangeDecoder, + (uint)outWindow._total, + prevByte + ); + } + outWindow.PutByte(b); + _state.UpdateChar(); + } + else + { + uint len; + if (_isRepDecoders[_state._index].Decode(rangeDecoder) == 1) + { + if (_isRepG0Decoders[_state._index].Decode(rangeDecoder) == 0) { - if (_isRepG0Decoders[_state._index].Decode(rangeDecoder) == 0) + if ( + _isRep0LongDecoders[ + (_state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState + ].Decode(rangeDecoder) == 0 + ) { - if ( - _isRep0LongDecoders[ - (_state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState - ].Decode(rangeDecoder) == 0 - ) - { - _state.UpdateShortRep(); - outWindow.PutByte(outWindow.GetByte((int)_rep0)); - continue; - } + _state.UpdateShortRep(); + outWindow.PutByte(outWindow.GetByte((int)_rep0)); + continue; } - else - { - UInt32 distance; - if (_isRepG1Decoders[_state._index].Decode(rangeDecoder) == 0) - { - distance = _rep1; - } - else - { - if (_isRepG2Decoders[_state._index].Decode(rangeDecoder) == 0) - { - distance = _rep2; - } - else - { - distance = _rep3; - _rep3 = _rep2; - } - _rep2 = _rep1; - } - _rep1 = _rep0; - _rep0 = distance; - } - len = _repLenDecoder.Decode(rangeDecoder, posState) + Base.K_MATCH_MIN_LEN; - _state.UpdateRep(); } else { - _rep3 = _rep2; - _rep2 = _rep1; - _rep1 = _rep0; - len = Base.K_MATCH_MIN_LEN + _lenDecoder.Decode(rangeDecoder, posState); - _state.UpdateMatch(); - uint posSlot = _posSlotDecoder[Base.GetLenToPosState(len)].Decode( - rangeDecoder - ); - if (posSlot >= Base.K_START_POS_MODEL_INDEX) + uint distance; + if (_isRepG1Decoders[_state._index].Decode(rangeDecoder) == 0) { - int numDirectBits = (int)((posSlot >> 1) - 1); - _rep0 = ((2 | (posSlot & 1)) << numDirectBits); - if (posSlot < Base.K_END_POS_MODEL_INDEX) - { - _rep0 += BitTreeDecoder.ReverseDecode( - _posDecoders, - _rep0 - posSlot - 1, - rangeDecoder, - numDirectBits - ); - } - else - { - _rep0 += ( - rangeDecoder.DecodeDirectBits( - numDirectBits - Base.K_NUM_ALIGN_BITS - ) << Base.K_NUM_ALIGN_BITS - ); - _rep0 += _posAlignDecoder.ReverseDecode(rangeDecoder); - } + distance = _rep1; } else { - _rep0 = posSlot; + if (_isRepG2Decoders[_state._index].Decode(rangeDecoder) == 0) + { + distance = _rep2; + } + else + { + distance = _rep3; + _rep3 = _rep2; + } + _rep2 = _rep1; } + _rep1 = _rep0; + _rep0 = distance; } - if (_rep0 >= outWindow._total || _rep0 >= dictionarySizeCheck) - { - if (_rep0 == 0xFFFFFFFF) - { - return true; - } - throw new DataErrorException(); - } - outWindow.CopyBlock((int)_rep0, (int)len); + len = _repLenDecoder.Decode(rangeDecoder, posState) + Base.K_MATCH_MIN_LEN; + _state.UpdateRep(); } - } - return false; - } - - public void SetDecoderProperties(byte[] properties) - { - if (properties.Length < 1) - { - throw new InvalidParamException(); - } - int lc = properties[0] % 9; - int remainder = properties[0] / 9; - int lp = remainder % 5; - int pb = remainder / 5; - if (pb > Base.K_NUM_POS_STATES_BITS_MAX) - { - throw new InvalidParamException(); - } - SetLiteralProperties(lp, lc); - SetPosBitsProperties(pb); - Init(); - if (properties.Length >= 5) - { - _dictionarySize = 0; - for (int i = 0; i < 4; i++) + else { - _dictionarySize += properties[1 + i] << (i * 8); + _rep3 = _rep2; + _rep2 = _rep1; + _rep1 = _rep0; + len = Base.K_MATCH_MIN_LEN + _lenDecoder.Decode(rangeDecoder, posState); + _state.UpdateMatch(); + var posSlot = _posSlotDecoder[Base.GetLenToPosState(len)].Decode( + rangeDecoder + ); + if (posSlot >= Base.K_START_POS_MODEL_INDEX) + { + var numDirectBits = (int)((posSlot >> 1) - 1); + _rep0 = ((2 | (posSlot & 1)) << numDirectBits); + if (posSlot < Base.K_END_POS_MODEL_INDEX) + { + _rep0 += BitTreeDecoder.ReverseDecode( + _posDecoders, + _rep0 - posSlot - 1, + rangeDecoder, + numDirectBits + ); + } + else + { + _rep0 += ( + rangeDecoder.DecodeDirectBits( + numDirectBits - Base.K_NUM_ALIGN_BITS + ) << Base.K_NUM_ALIGN_BITS + ); + _rep0 += _posAlignDecoder.ReverseDecode(rangeDecoder); + } + } + else + { + _rep0 = posSlot; + } } + if (_rep0 >= outWindow._total || _rep0 >= dictionarySizeCheck) + { + if (_rep0 == 0xFFFFFFFF) + { + return true; + } + throw new DataErrorException(); + } + outWindow.CopyBlock((int)_rep0, (int)len); } } - - public void Train(Stream stream) - { - if (_outWindow is null) - { - CreateDictionary(); - } - _outWindow.Train(stream); - } - - /* - public override bool CanRead { get { return true; }} - public override bool CanWrite { get { return true; }} - public override bool CanSeek { get { return true; }} - public override long Length { get { return 0; }} - public override long Position - { - get { return 0; } - set { } - } - public override void Flush() { } - public override int Read(byte[] buffer, int offset, int count) - { - return 0; - } - public override void Write(byte[] buffer, int offset, int count) - { - } - public override long Seek(long offset, System.IO.SeekOrigin origin) - { - return 0; - } - public override void SetLength(long value) {} - */ + return false; } + + public void SetDecoderProperties(byte[] properties) + { + if (properties.Length < 1) + { + throw new InvalidParamException(); + } + var lc = properties[0] % 9; + var remainder = properties[0] / 9; + var lp = remainder % 5; + var pb = remainder / 5; + if (pb > Base.K_NUM_POS_STATES_BITS_MAX) + { + throw new InvalidParamException(); + } + SetLiteralProperties(lp, lc); + SetPosBitsProperties(pb); + Init(); + if (properties.Length >= 5) + { + _dictionarySize = 0; + for (var i = 0; i < 4; i++) + { + _dictionarySize += properties[1 + i] << (i * 8); + } + } + } + + public void Train(Stream stream) + { + if (_outWindow is null) + { + CreateDictionary(); + } + _outWindow.Train(stream); + } + + /* + public override bool CanRead { get { return true; }} + public override bool CanWrite { get { return true; }} + public override bool CanSeek { get { return true; }} + public override long Length { get { return 0; }} + public override long Position + { + get { return 0; } + set { } + } + public override void Flush() { } + public override int Read(byte[] buffer, int offset, int count) + { + return 0; + } + public override void Write(byte[] buffer, int offset, int count) + { + } + public override long Seek(long offset, System.IO.SeekOrigin origin) + { + return 0; + } + public override void SetLength(long value) {} + */ } diff --git a/src/SharpCompress/Compressors/LZMA/LzmaEncoder.cs b/src/SharpCompress/Compressors/LZMA/LzmaEncoder.cs index c1ab3b18..be1e8a08 100644 --- a/src/SharpCompress/Compressors/LZMA/LzmaEncoder.cs +++ b/src/SharpCompress/Compressors/LZMA/LzmaEncoder.cs @@ -5,1146 +5,1258 @@ using System.IO; using SharpCompress.Compressors.LZMA.LZ; using SharpCompress.Compressors.LZMA.RangeCoder; -namespace SharpCompress.Compressors.LZMA +namespace SharpCompress.Compressors.LZMA; + +internal class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties { - internal class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties + private enum EMatchFinderType { - private enum EMatchFinderType + Bt2, + Bt4 + } + + private const uint K_IFINITY_PRICE = 0xFFFFFFF; + + private static readonly byte[] G_FAST_POS = new byte[1 << 11]; + + static Encoder() + { + const byte kFastSlots = 22; + var c = 2; + G_FAST_POS[0] = 0; + G_FAST_POS[1] = 1; + for (byte slotFast = 2; slotFast < kFastSlots; slotFast++) { - Bt2, - Bt4 - } - - private const UInt32 K_IFINITY_PRICE = 0xFFFFFFF; - - private static readonly Byte[] G_FAST_POS = new Byte[1 << 11]; - - static Encoder() - { - const Byte kFastSlots = 22; - int c = 2; - G_FAST_POS[0] = 0; - G_FAST_POS[1] = 1; - for (Byte slotFast = 2; slotFast < kFastSlots; slotFast++) + var k = ((uint)1 << ((slotFast >> 1) - 1)); + for (uint j = 0; j < k; j++, c++) { - UInt32 k = ((UInt32)1 << ((slotFast >> 1) - 1)); - for (UInt32 j = 0; j < k; j++, c++) - { - G_FAST_POS[c] = slotFast; - } + G_FAST_POS[c] = slotFast; } } + } - private static UInt32 GetPosSlot(UInt32 pos) + private static uint GetPosSlot(uint pos) + { + if (pos < (1 << 11)) { - if (pos < (1 << 11)) - { - return G_FAST_POS[pos]; - } - if (pos < (1 << 21)) - { - return (UInt32)(G_FAST_POS[pos >> 10] + 20); - } - return (UInt32)(G_FAST_POS[pos >> 20] + 40); + return G_FAST_POS[pos]; } - - private static UInt32 GetPosSlot2(UInt32 pos) + if (pos < (1 << 21)) { - if (pos < (1 << 17)) - { - return (UInt32)(G_FAST_POS[pos >> 6] + 12); - } - if (pos < (1 << 27)) - { - return (UInt32)(G_FAST_POS[pos >> 16] + 32); - } - return (UInt32)(G_FAST_POS[pos >> 26] + 52); + return (uint)(G_FAST_POS[pos >> 10] + 20); } + return (uint)(G_FAST_POS[pos >> 20] + 40); + } - private Base.State _state = new Base.State(); - private Byte _previousByte; - private readonly UInt32[] _repDistances = new UInt32[Base.K_NUM_REP_DISTANCES]; - - private void BaseInit() + private static uint GetPosSlot2(uint pos) + { + if (pos < (1 << 17)) { - _state.Init(); - _previousByte = 0; - for (UInt32 i = 0; i < Base.K_NUM_REP_DISTANCES; i++) - { - _repDistances[i] = 0; - } + return (uint)(G_FAST_POS[pos >> 6] + 12); } - - private const int K_DEFAULT_DICTIONARY_LOG_SIZE = 22; - private const UInt32 K_NUM_FAST_BYTES_DEFAULT = 0x20; - - private class LiteralEncoder + if (pos < (1 << 27)) { - public struct Encoder2 + return (uint)(G_FAST_POS[pos >> 16] + 32); + } + return (uint)(G_FAST_POS[pos >> 26] + 52); + } + + private Base.State _state = new Base.State(); + private byte _previousByte; + private readonly uint[] _repDistances = new uint[Base.K_NUM_REP_DISTANCES]; + + private void BaseInit() + { + _state.Init(); + _previousByte = 0; + for (uint i = 0; i < Base.K_NUM_REP_DISTANCES; i++) + { + _repDistances[i] = 0; + } + } + + private const int K_DEFAULT_DICTIONARY_LOG_SIZE = 22; + private const uint K_NUM_FAST_BYTES_DEFAULT = 0x20; + + private class LiteralEncoder + { + public struct Encoder2 + { + private BitEncoder[] _encoders; + + public void Create() { - private BitEncoder[] _encoders; - - public void Create() - { - _encoders = new BitEncoder[0x300]; - } - - public void Init() - { - for (int i = 0; i < 0x300; i++) - { - _encoders[i].Init(); - } - } - - public void Encode(RangeCoder.Encoder rangeEncoder, byte symbol) - { - uint context = 1; - for (int i = 7; i >= 0; i--) - { - uint bit = (uint)((symbol >> i) & 1); - _encoders[context].Encode(rangeEncoder, bit); - context = (context << 1) | bit; - } - } - - public void EncodeMatched( - RangeCoder.Encoder rangeEncoder, - byte matchByte, - byte symbol - ) - { - uint context = 1; - bool same = true; - for (int i = 7; i >= 0; i--) - { - uint bit = (uint)((symbol >> i) & 1); - uint state = context; - if (same) - { - uint matchBit = (uint)((matchByte >> i) & 1); - state += ((1 + matchBit) << 8); - same = (matchBit == bit); - } - _encoders[state].Encode(rangeEncoder, bit); - context = (context << 1) | bit; - } - } - - public uint GetPrice(bool matchMode, byte matchByte, byte symbol) - { - uint price = 0; - uint context = 1; - int i = 7; - if (matchMode) - { - for (; i >= 0; i--) - { - uint matchBit = (uint)(matchByte >> i) & 1; - uint bit = (uint)(symbol >> i) & 1; - price += _encoders[((1 + matchBit) << 8) + context].GetPrice(bit); - context = (context << 1) | bit; - if (matchBit != bit) - { - i--; - break; - } - } - } - for (; i >= 0; i--) - { - uint bit = (uint)(symbol >> i) & 1; - price += _encoders[context].GetPrice(bit); - context = (context << 1) | bit; - } - return price; - } - } - - private Encoder2[] _coders; - private int _numPrevBits; - private int _numPosBits; - private uint _posMask; - - public void Create(int numPosBits, int numPrevBits) - { - if (_coders != null && _numPrevBits == numPrevBits && _numPosBits == numPosBits) - { - return; - } - _numPosBits = numPosBits; - _posMask = ((uint)1 << numPosBits) - 1; - _numPrevBits = numPrevBits; - uint numStates = (uint)1 << (_numPrevBits + _numPosBits); - _coders = new Encoder2[numStates]; - for (uint i = 0; i < numStates; i++) - { - _coders[i].Create(); - } + _encoders = new BitEncoder[0x300]; } public void Init() { - uint numStates = (uint)1 << (_numPrevBits + _numPosBits); - for (uint i = 0; i < numStates; i++) + for (var i = 0; i < 0x300; i++) { - _coders[i].Init(); + _encoders[i].Init(); } } - public Encoder2 GetSubCoder(UInt32 pos, Byte prevByte) + public void Encode(RangeCoder.Encoder rangeEncoder, byte symbol) { - return _coders[ - ((pos & _posMask) << _numPrevBits) + (uint)(prevByte >> (8 - _numPrevBits)) - ]; - } - } - - private class LenEncoder - { - private BitEncoder _choice = new BitEncoder(); - private BitEncoder _choice2 = new BitEncoder(); - 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); - - public LenEncoder() - { - for (UInt32 posState = 0; posState < Base.K_NUM_POS_STATES_ENCODING_MAX; posState++) + uint context = 1; + for (var i = 7; i >= 0; i--) { - _lowCoder[posState] = new BitTreeEncoder(Base.K_NUM_LOW_LEN_BITS); - _midCoder[posState] = new BitTreeEncoder(Base.K_NUM_MID_LEN_BITS); + var bit = (uint)((symbol >> i) & 1); + _encoders[context].Encode(rangeEncoder, bit); + context = (context << 1) | bit; } } - public void Init(UInt32 numPosStates) + public void EncodeMatched( + RangeCoder.Encoder rangeEncoder, + byte matchByte, + byte symbol + ) { - _choice.Init(); - _choice2.Init(); - for (UInt32 posState = 0; posState < numPosStates; posState++) + uint context = 1; + var same = true; + for (var i = 7; i >= 0; i--) { - _lowCoder[posState].Init(); - _midCoder[posState].Init(); - } - _highCoder.Init(); - } - - public void Encode(RangeCoder.Encoder rangeEncoder, UInt32 symbol, UInt32 posState) - { - if (symbol < Base.K_NUM_LOW_LEN_SYMBOLS) - { - _choice.Encode(rangeEncoder, 0); - _lowCoder[posState].Encode(rangeEncoder, symbol); - } - else - { - symbol -= Base.K_NUM_LOW_LEN_SYMBOLS; - _choice.Encode(rangeEncoder, 1); - if (symbol < Base.K_NUM_MID_LEN_SYMBOLS) + var bit = (uint)((symbol >> i) & 1); + var state = context; + if (same) { - _choice2.Encode(rangeEncoder, 0); - _midCoder[posState].Encode(rangeEncoder, symbol); + var matchBit = (uint)((matchByte >> i) & 1); + state += ((1 + matchBit) << 8); + same = (matchBit == bit); } - else + _encoders[state].Encode(rangeEncoder, bit); + context = (context << 1) | bit; + } + } + + public uint GetPrice(bool matchMode, byte matchByte, byte symbol) + { + uint price = 0; + uint context = 1; + var i = 7; + if (matchMode) + { + for (; i >= 0; i--) { - _choice2.Encode(rangeEncoder, 1); - _highCoder.Encode(rangeEncoder, symbol - Base.K_NUM_MID_LEN_SYMBOLS); - } - } - } - - public void SetPrices(UInt32 posState, UInt32 numSymbols, UInt32[] prices, UInt32 st) - { - UInt32 a0 = _choice.GetPrice0(); - UInt32 a1 = _choice.GetPrice1(); - UInt32 b0 = a1 + _choice2.GetPrice0(); - UInt32 b1 = a1 + _choice2.GetPrice1(); - UInt32 i = 0; - for (i = 0; i < Base.K_NUM_LOW_LEN_SYMBOLS; i++) - { - if (i >= numSymbols) - { - return; - } - prices[st + i] = a0 + _lowCoder[posState].GetPrice(i); - } - for (; i < Base.K_NUM_LOW_LEN_SYMBOLS + Base.K_NUM_MID_LEN_SYMBOLS; i++) - { - if (i >= numSymbols) - { - return; - } - prices[st + i] = - b0 + _midCoder[posState].GetPrice(i - Base.K_NUM_LOW_LEN_SYMBOLS); - } - for (; i < numSymbols; i++) - { - prices[st + i] = - b1 - + _highCoder.GetPrice( - i - Base.K_NUM_LOW_LEN_SYMBOLS - Base.K_NUM_MID_LEN_SYMBOLS - ); - } - } - } - - private const UInt32 K_NUM_LEN_SPEC_SYMBOLS = - Base.K_NUM_LOW_LEN_SYMBOLS + Base.K_NUM_MID_LEN_SYMBOLS; - - private class LenPriceTableEncoder : LenEncoder - { - private readonly UInt32[] _prices = new UInt32[ - Base.K_NUM_LEN_SYMBOLS << Base.K_NUM_POS_STATES_BITS_ENCODING_MAX - ]; - private UInt32 _tableSize; - private readonly UInt32[] _counters = new UInt32[Base.K_NUM_POS_STATES_ENCODING_MAX]; - - public void SetTableSize(UInt32 tableSize) - { - _tableSize = tableSize; - } - - public UInt32 GetPrice(UInt32 symbol, UInt32 posState) - { - return _prices[posState * Base.K_NUM_LEN_SYMBOLS + symbol]; - } - - private void UpdateTable(UInt32 posState) - { - SetPrices(posState, _tableSize, _prices, posState * Base.K_NUM_LEN_SYMBOLS); - _counters[posState] = _tableSize; - } - - public void UpdateTables(UInt32 numPosStates) - { - for (UInt32 posState = 0; posState < numPosStates; posState++) - { - UpdateTable(posState); - } - } - - public new void Encode(RangeCoder.Encoder rangeEncoder, UInt32 symbol, UInt32 posState) - { - base.Encode(rangeEncoder, symbol, posState); - if (--_counters[posState] == 0) - { - UpdateTable(posState); - } - } - } - - private const UInt32 K_NUM_OPTS = 1 << 12; - - private class Optimal - { - public Base.State _state; - - public bool _prev1IsChar; - public bool _prev2; - - public UInt32 _posPrev2; - public UInt32 _backPrev2; - - public UInt32 _price; - public UInt32 _posPrev; - public UInt32 _backPrev; - - public UInt32 _backs0; - public UInt32 _backs1; - public UInt32 _backs2; - public UInt32 _backs3; - - public void MakeAsChar() - { - _backPrev = 0xFFFFFFFF; - _prev1IsChar = false; - } - - public void MakeAsShortRep() - { - _backPrev = 0; - ; - _prev1IsChar = false; - } - - public bool IsShortRep() - { - return (_backPrev == 0); - } - } - - private readonly Optimal[] _optimum = new Optimal[K_NUM_OPTS]; - private BinTree _matchFinder; - private readonly RangeCoder.Encoder _rangeEncoder = new RangeCoder.Encoder(); - - private readonly BitEncoder[] _isMatch = new BitEncoder[ - Base.K_NUM_STATES << Base.K_NUM_POS_STATES_BITS_MAX - ]; - - private readonly BitEncoder[] _isRep = new BitEncoder[Base.K_NUM_STATES]; - private readonly BitEncoder[] _isRepG0 = new BitEncoder[Base.K_NUM_STATES]; - private readonly BitEncoder[] _isRepG1 = new BitEncoder[Base.K_NUM_STATES]; - private readonly BitEncoder[] _isRepG2 = new BitEncoder[Base.K_NUM_STATES]; - - private readonly BitEncoder[] _isRep0Long = new BitEncoder[ - Base.K_NUM_STATES << Base.K_NUM_POS_STATES_BITS_MAX - ]; - - private readonly BitTreeEncoder[] _posSlotEncoder = new BitTreeEncoder[ - Base.K_NUM_LEN_TO_POS_STATES - ]; - - private readonly BitEncoder[] _posEncoders = new BitEncoder[ - Base.K_NUM_FULL_DISTANCES - Base.K_END_POS_MODEL_INDEX - ]; - - private BitTreeEncoder _posAlignEncoder = new BitTreeEncoder(Base.K_NUM_ALIGN_BITS); - - private readonly LenPriceTableEncoder _lenEncoder = new LenPriceTableEncoder(); - private readonly LenPriceTableEncoder _repMatchLenEncoder = new LenPriceTableEncoder(); - - private readonly LiteralEncoder _literalEncoder = new LiteralEncoder(); - - private readonly UInt32[] _matchDistances = new UInt32[Base.K_MATCH_MAX_LEN * 2 + 2]; - - private UInt32 _numFastBytes = K_NUM_FAST_BYTES_DEFAULT; - private UInt32 _longestMatchLength; - private UInt32 _numDistancePairs; - - private UInt32 _additionalOffset; - - private UInt32 _optimumEndIndex; - private UInt32 _optimumCurrentIndex; - - private bool _longestMatchWasFound; - - private readonly UInt32[] _posSlotPrices = new UInt32[ - 1 << (Base.K_NUM_POS_SLOT_BITS + Base.K_NUM_LEN_TO_POS_STATES_BITS) - ]; - private readonly UInt32[] _distancesPrices = new UInt32[ - Base.K_NUM_FULL_DISTANCES << Base.K_NUM_LEN_TO_POS_STATES_BITS - ]; - private readonly UInt32[] _alignPrices = new UInt32[Base.K_ALIGN_TABLE_SIZE]; - private UInt32 _alignPriceCount; - - private UInt32 _distTableSize = (K_DEFAULT_DICTIONARY_LOG_SIZE * 2); - - private int _posStateBits = 2; - private UInt32 _posStateMask = (4 - 1); - private int _numLiteralPosStateBits; - private int _numLiteralContextBits = 3; - - private UInt32 _dictionarySize = (1 << K_DEFAULT_DICTIONARY_LOG_SIZE); - private UInt32 _dictionarySizePrev = 0xFFFFFFFF; - private UInt32 _numFastBytesPrev = 0xFFFFFFFF; - - private Int64 _nowPos64; - private bool _finished; - private Stream _inStream; - - private EMatchFinderType _matchFinderType = EMatchFinderType.Bt4; - private bool _writeEndMark; - - private bool _needReleaseMfStream; - private bool _processingMode; - - private void Create() - { - if (_matchFinder is null) - { - var bt = new BinTree(); - int numHashBytes = 4; - if (_matchFinderType == EMatchFinderType.Bt2) - { - numHashBytes = 2; - } - bt.SetType(numHashBytes); - _matchFinder = bt; - } - _literalEncoder.Create(_numLiteralPosStateBits, _numLiteralContextBits); - - if (_dictionarySize == _dictionarySizePrev && _numFastBytesPrev == _numFastBytes) - { - return; - } - _matchFinder.Create( - _dictionarySize, - K_NUM_OPTS, - _numFastBytes, - Base.K_MATCH_MAX_LEN + 1 + K_NUM_OPTS - ); - _dictionarySizePrev = _dictionarySize; - _numFastBytesPrev = _numFastBytes; - } - - public Encoder() - { - for (int i = 0; i < K_NUM_OPTS; i++) - { - _optimum[i] = new Optimal(); - } - for (int i = 0; i < Base.K_NUM_LEN_TO_POS_STATES; i++) - { - _posSlotEncoder[i] = new BitTreeEncoder(Base.K_NUM_POS_SLOT_BITS); - } - } - - private void SetWriteEndMarkerMode(bool writeEndMarker) - { - _writeEndMark = writeEndMarker; - } - - private void Init() - { - BaseInit(); - _rangeEncoder.Init(); - - uint i; - for (i = 0; i < Base.K_NUM_STATES; i++) - { - for (uint j = 0; j <= _posStateMask; j++) - { - uint complexState = (i << Base.K_NUM_POS_STATES_BITS_MAX) + j; - _isMatch[complexState].Init(); - _isRep0Long[complexState].Init(); - } - _isRep[i].Init(); - _isRepG0[i].Init(); - _isRepG1[i].Init(); - _isRepG2[i].Init(); - } - _literalEncoder.Init(); - for (i = 0; i < Base.K_NUM_LEN_TO_POS_STATES; i++) - { - _posSlotEncoder[i].Init(); - } - for (i = 0; i < Base.K_NUM_FULL_DISTANCES - Base.K_END_POS_MODEL_INDEX; i++) - { - _posEncoders[i].Init(); - } - - _lenEncoder.Init((UInt32)1 << _posStateBits); - _repMatchLenEncoder.Init((UInt32)1 << _posStateBits); - - _posAlignEncoder.Init(); - - _longestMatchWasFound = false; - _optimumEndIndex = 0; - _optimumCurrentIndex = 0; - _additionalOffset = 0; - } - - private void ReadMatchDistances(out UInt32 lenRes, out UInt32 numDistancePairs) - { - lenRes = 0; - numDistancePairs = _matchFinder.GetMatches(_matchDistances); - if (numDistancePairs > 0) - { - lenRes = _matchDistances[numDistancePairs - 2]; - if (lenRes == _numFastBytes) - { - lenRes += _matchFinder.GetMatchLen( - (int)lenRes - 1, - _matchDistances[numDistancePairs - 1], - Base.K_MATCH_MAX_LEN - lenRes - ); - } - } - _additionalOffset++; - } - - private void MovePos(UInt32 num) - { - if (num > 0) - { - _matchFinder.Skip(num); - _additionalOffset += num; - } - } - - private UInt32 GetRepLen1Price(Base.State state, UInt32 posState) - { - return _isRepG0[state._index].GetPrice0() - + _isRep0Long[ - (state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState - ].GetPrice0(); - } - - private UInt32 GetPureRepPrice(UInt32 repIndex, Base.State state, UInt32 posState) - { - UInt32 price; - if (repIndex == 0) - { - price = _isRepG0[state._index].GetPrice0(); - price += _isRep0Long[ - (state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState - ].GetPrice1(); - } - else - { - price = _isRepG0[state._index].GetPrice1(); - if (repIndex == 1) - { - price += _isRepG1[state._index].GetPrice0(); - } - else - { - price += _isRepG1[state._index].GetPrice1(); - price += _isRepG2[state._index].GetPrice(repIndex - 2); - } - } - return price; - } - - private UInt32 GetRepPrice(UInt32 repIndex, UInt32 len, Base.State state, UInt32 posState) - { - UInt32 price = _repMatchLenEncoder.GetPrice(len - Base.K_MATCH_MIN_LEN, posState); - return price + GetPureRepPrice(repIndex, state, posState); - } - - private UInt32 GetPosLenPrice(UInt32 pos, UInt32 len, UInt32 posState) - { - UInt32 price; - UInt32 lenToPosState = Base.GetLenToPosState(len); - if (pos < Base.K_NUM_FULL_DISTANCES) - { - price = _distancesPrices[(lenToPosState * Base.K_NUM_FULL_DISTANCES) + pos]; - } - else - { - price = - _posSlotPrices[(lenToPosState << Base.K_NUM_POS_SLOT_BITS) + GetPosSlot2(pos)] - + _alignPrices[pos & Base.K_ALIGN_MASK]; - } - return price + _lenEncoder.GetPrice(len - Base.K_MATCH_MIN_LEN, posState); - } - - private UInt32 Backward(out UInt32 backRes, UInt32 cur) - { - _optimumEndIndex = cur; - UInt32 posMem = _optimum[cur]._posPrev; - UInt32 backMem = _optimum[cur]._backPrev; - do - { - if (_optimum[cur]._prev1IsChar) - { - _optimum[posMem].MakeAsChar(); - _optimum[posMem]._posPrev = posMem - 1; - if (_optimum[cur]._prev2) - { - _optimum[posMem - 1]._prev1IsChar = false; - _optimum[posMem - 1]._posPrev = _optimum[cur]._posPrev2; - _optimum[posMem - 1]._backPrev = _optimum[cur]._backPrev2; - } - } - UInt32 posPrev = posMem; - UInt32 backCur = backMem; - - backMem = _optimum[posPrev]._backPrev; - posMem = _optimum[posPrev]._posPrev; - - _optimum[posPrev]._backPrev = backCur; - _optimum[posPrev]._posPrev = cur; - cur = posPrev; - } while (cur > 0); - backRes = _optimum[0]._backPrev; - _optimumCurrentIndex = _optimum[0]._posPrev; - return _optimumCurrentIndex; - } - - private readonly UInt32[] _reps = new UInt32[Base.K_NUM_REP_DISTANCES]; - private readonly UInt32[] _repLens = new UInt32[Base.K_NUM_REP_DISTANCES]; - - private UInt32 GetOptimum(UInt32 position, out UInt32 backRes) - { - if (_optimumEndIndex != _optimumCurrentIndex) - { - UInt32 lenRes = _optimum[_optimumCurrentIndex]._posPrev - _optimumCurrentIndex; - backRes = _optimum[_optimumCurrentIndex]._backPrev; - _optimumCurrentIndex = _optimum[_optimumCurrentIndex]._posPrev; - return lenRes; - } - _optimumCurrentIndex = _optimumEndIndex = 0; - - UInt32 lenMain, - numDistancePairs; - if (!_longestMatchWasFound) - { - ReadMatchDistances(out lenMain, out numDistancePairs); - } - else - { - lenMain = _longestMatchLength; - numDistancePairs = _numDistancePairs; - _longestMatchWasFound = false; - } - - UInt32 numAvailableBytes = _matchFinder.GetNumAvailableBytes() + 1; - if (numAvailableBytes < 2) - { - backRes = 0xFFFFFFFF; - return 1; - } - if (numAvailableBytes > Base.K_MATCH_MAX_LEN) - { - numAvailableBytes = Base.K_MATCH_MAX_LEN; - } - - UInt32 repMaxIndex = 0; - UInt32 i; - for (i = 0; i < Base.K_NUM_REP_DISTANCES; i++) - { - _reps[i] = _repDistances[i]; - _repLens[i] = _matchFinder.GetMatchLen(0 - 1, _reps[i], Base.K_MATCH_MAX_LEN); - if (_repLens[i] > _repLens[repMaxIndex]) - { - repMaxIndex = i; - } - } - if (_repLens[repMaxIndex] >= _numFastBytes) - { - backRes = repMaxIndex; - UInt32 lenRes = _repLens[repMaxIndex]; - MovePos(lenRes - 1); - return lenRes; - } - - if (lenMain >= _numFastBytes) - { - backRes = _matchDistances[numDistancePairs - 1] + Base.K_NUM_REP_DISTANCES; - MovePos(lenMain - 1); - return lenMain; - } - - Byte currentByte = _matchFinder.GetIndexByte(0 - 1); - Byte matchByte = _matchFinder.GetIndexByte((Int32)(0 - _repDistances[0] - 1 - 1)); - - if (lenMain < 2 && currentByte != matchByte && _repLens[repMaxIndex] < 2) - { - backRes = 0xFFFFFFFF; - return 1; - } - - _optimum[0]._state = _state; - - UInt32 posState = (position & _posStateMask); - - _optimum[1]._price = - _isMatch[(_state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState].GetPrice0() - + _literalEncoder - .GetSubCoder(position, _previousByte) - .GetPrice(!_state.IsCharState(), matchByte, currentByte); - _optimum[1].MakeAsChar(); - - UInt32 matchPrice = _isMatch[ - (_state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState - ].GetPrice1(); - UInt32 repMatchPrice = matchPrice + _isRep[_state._index].GetPrice1(); - - if (matchByte == currentByte) - { - UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(_state, posState); - if (shortRepPrice < _optimum[1]._price) - { - _optimum[1]._price = shortRepPrice; - _optimum[1].MakeAsShortRep(); - } - } - - UInt32 lenEnd = ((lenMain >= _repLens[repMaxIndex]) ? lenMain : _repLens[repMaxIndex]); - - if (lenEnd < 2) - { - backRes = _optimum[1]._backPrev; - return 1; - } - - _optimum[1]._posPrev = 0; - - _optimum[0]._backs0 = _reps[0]; - _optimum[0]._backs1 = _reps[1]; - _optimum[0]._backs2 = _reps[2]; - _optimum[0]._backs3 = _reps[3]; - - UInt32 len = lenEnd; - do - { - _optimum[len--]._price = K_IFINITY_PRICE; - } while (len >= 2); - - for (i = 0; i < Base.K_NUM_REP_DISTANCES; i++) - { - UInt32 repLen = _repLens[i]; - if (repLen < 2) - { - continue; - } - UInt32 price = repMatchPrice + GetPureRepPrice(i, _state, posState); - do - { - UInt32 curAndLenPrice = - price + _repMatchLenEncoder.GetPrice(repLen - 2, posState); - Optimal optimum = _optimum[repLen]; - if (curAndLenPrice < optimum._price) - { - optimum._price = curAndLenPrice; - optimum._posPrev = 0; - optimum._backPrev = i; - optimum._prev1IsChar = false; - } - } while (--repLen >= 2); - } - - UInt32 normalMatchPrice = matchPrice + _isRep[_state._index].GetPrice0(); - - len = ((_repLens[0] >= 2) ? _repLens[0] + 1 : 2); - if (len <= lenMain) - { - UInt32 offs = 0; - while (len > _matchDistances[offs]) - { - offs += 2; - } - for (; ; len++) - { - UInt32 distance = _matchDistances[offs + 1]; - UInt32 curAndLenPrice = - normalMatchPrice + GetPosLenPrice(distance, len, posState); - Optimal optimum = _optimum[len]; - if (curAndLenPrice < optimum._price) - { - optimum._price = curAndLenPrice; - optimum._posPrev = 0; - optimum._backPrev = distance + Base.K_NUM_REP_DISTANCES; - optimum._prev1IsChar = false; - } - if (len == _matchDistances[offs]) - { - offs += 2; - if (offs == numDistancePairs) + var matchBit = (uint)(matchByte >> i) & 1; + var bit = (uint)(symbol >> i) & 1; + price += _encoders[((1 + matchBit) << 8) + context].GetPrice(bit); + context = (context << 1) | bit; + if (matchBit != bit) { + i--; break; } } } + for (; i >= 0; i--) + { + var bit = (uint)(symbol >> i) & 1; + price += _encoders[context].GetPrice(bit); + context = (context << 1) | bit; + } + return price; } + } - UInt32 cur = 0; + private Encoder2[] _coders; + private int _numPrevBits; + private int _numPosBits; + private uint _posMask; - while (true) + public void Create(int numPosBits, int numPrevBits) + { + if (_coders != null && _numPrevBits == numPrevBits && _numPosBits == numPosBits) { - cur++; - if (cur == lenEnd) + return; + } + _numPosBits = numPosBits; + _posMask = ((uint)1 << numPosBits) - 1; + _numPrevBits = numPrevBits; + var numStates = (uint)1 << (_numPrevBits + _numPosBits); + _coders = new Encoder2[numStates]; + for (uint i = 0; i < numStates; i++) + { + _coders[i].Create(); + } + } + + public void Init() + { + var numStates = (uint)1 << (_numPrevBits + _numPosBits); + for (uint i = 0; i < numStates; i++) + { + _coders[i].Init(); + } + } + + public Encoder2 GetSubCoder(uint pos, byte prevByte) + { + return _coders[ + ((pos & _posMask) << _numPrevBits) + (uint)(prevByte >> (8 - _numPrevBits)) + ]; + } + } + + private class LenEncoder + { + private BitEncoder _choice = new BitEncoder(); + private BitEncoder _choice2 = new BitEncoder(); + 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); + + public LenEncoder() + { + for (uint posState = 0; posState < Base.K_NUM_POS_STATES_ENCODING_MAX; posState++) + { + _lowCoder[posState] = new BitTreeEncoder(Base.K_NUM_LOW_LEN_BITS); + _midCoder[posState] = new BitTreeEncoder(Base.K_NUM_MID_LEN_BITS); + } + } + + public void Init(uint numPosStates) + { + _choice.Init(); + _choice2.Init(); + for (uint posState = 0; posState < numPosStates; posState++) + { + _lowCoder[posState].Init(); + _midCoder[posState].Init(); + } + _highCoder.Init(); + } + + public void Encode(RangeCoder.Encoder rangeEncoder, uint symbol, uint posState) + { + if (symbol < Base.K_NUM_LOW_LEN_SYMBOLS) + { + _choice.Encode(rangeEncoder, 0); + _lowCoder[posState].Encode(rangeEncoder, symbol); + } + else + { + symbol -= Base.K_NUM_LOW_LEN_SYMBOLS; + _choice.Encode(rangeEncoder, 1); + if (symbol < Base.K_NUM_MID_LEN_SYMBOLS) { - return Backward(out backRes, cur); + _choice2.Encode(rangeEncoder, 0); + _midCoder[posState].Encode(rangeEncoder, symbol); } - UInt32 newLen; - ReadMatchDistances(out newLen, out numDistancePairs); - if (newLen >= _numFastBytes) + else { - _numDistancePairs = numDistancePairs; - _longestMatchLength = newLen; - _longestMatchWasFound = true; - return Backward(out backRes, cur); + _choice2.Encode(rangeEncoder, 1); + _highCoder.Encode(rangeEncoder, symbol - Base.K_NUM_MID_LEN_SYMBOLS); } - position++; - UInt32 posPrev = _optimum[cur]._posPrev; - Base.State state; - if (_optimum[cur]._prev1IsChar) + } + } + + public void SetPrices(uint posState, uint numSymbols, uint[] prices, uint st) + { + var a0 = _choice.GetPrice0(); + var a1 = _choice.GetPrice1(); + var b0 = a1 + _choice2.GetPrice0(); + var b1 = a1 + _choice2.GetPrice1(); + uint i = 0; + for (i = 0; i < Base.K_NUM_LOW_LEN_SYMBOLS; i++) + { + if (i >= numSymbols) { - posPrev--; - if (_optimum[cur]._prev2) + return; + } + prices[st + i] = a0 + _lowCoder[posState].GetPrice(i); + } + for (; i < Base.K_NUM_LOW_LEN_SYMBOLS + Base.K_NUM_MID_LEN_SYMBOLS; i++) + { + if (i >= numSymbols) + { + return; + } + prices[st + i] = + b0 + _midCoder[posState].GetPrice(i - Base.K_NUM_LOW_LEN_SYMBOLS); + } + for (; i < numSymbols; i++) + { + prices[st + i] = + b1 + + _highCoder.GetPrice( + i - Base.K_NUM_LOW_LEN_SYMBOLS - Base.K_NUM_MID_LEN_SYMBOLS + ); + } + } + } + + private const uint K_NUM_LEN_SPEC_SYMBOLS = + Base.K_NUM_LOW_LEN_SYMBOLS + Base.K_NUM_MID_LEN_SYMBOLS; + + private class LenPriceTableEncoder : LenEncoder + { + private readonly uint[] _prices = new uint[ + Base.K_NUM_LEN_SYMBOLS << Base.K_NUM_POS_STATES_BITS_ENCODING_MAX + ]; + private uint _tableSize; + private readonly uint[] _counters = new uint[Base.K_NUM_POS_STATES_ENCODING_MAX]; + + public void SetTableSize(uint tableSize) + { + _tableSize = tableSize; + } + + public uint GetPrice(uint symbol, uint posState) + { + return _prices[(posState * Base.K_NUM_LEN_SYMBOLS) + symbol]; + } + + private void UpdateTable(uint posState) + { + SetPrices(posState, _tableSize, _prices, posState * Base.K_NUM_LEN_SYMBOLS); + _counters[posState] = _tableSize; + } + + public void UpdateTables(uint numPosStates) + { + for (uint posState = 0; posState < numPosStates; posState++) + { + UpdateTable(posState); + } + } + + public new void Encode(RangeCoder.Encoder rangeEncoder, uint symbol, uint posState) + { + base.Encode(rangeEncoder, symbol, posState); + if (--_counters[posState] == 0) + { + UpdateTable(posState); + } + } + } + + private const uint K_NUM_OPTS = 1 << 12; + + private class Optimal + { + public Base.State _state; + + public bool _prev1IsChar; + public bool _prev2; + + public uint _posPrev2; + public uint _backPrev2; + + public uint _price; + public uint _posPrev; + public uint _backPrev; + + public uint _backs0; + public uint _backs1; + public uint _backs2; + public uint _backs3; + + public void MakeAsChar() + { + _backPrev = 0xFFFFFFFF; + _prev1IsChar = false; + } + + public void MakeAsShortRep() + { + _backPrev = 0; + ; + _prev1IsChar = false; + } + + public bool IsShortRep() + { + return (_backPrev == 0); + } + } + + private readonly Optimal[] _optimum = new Optimal[K_NUM_OPTS]; + private BinTree _matchFinder; + private readonly RangeCoder.Encoder _rangeEncoder = new RangeCoder.Encoder(); + + private readonly BitEncoder[] _isMatch = new BitEncoder[ + Base.K_NUM_STATES << Base.K_NUM_POS_STATES_BITS_MAX + ]; + + private readonly BitEncoder[] _isRep = new BitEncoder[Base.K_NUM_STATES]; + private readonly BitEncoder[] _isRepG0 = new BitEncoder[Base.K_NUM_STATES]; + private readonly BitEncoder[] _isRepG1 = new BitEncoder[Base.K_NUM_STATES]; + private readonly BitEncoder[] _isRepG2 = new BitEncoder[Base.K_NUM_STATES]; + + private readonly BitEncoder[] _isRep0Long = new BitEncoder[ + Base.K_NUM_STATES << Base.K_NUM_POS_STATES_BITS_MAX + ]; + + private readonly BitTreeEncoder[] _posSlotEncoder = new BitTreeEncoder[ + Base.K_NUM_LEN_TO_POS_STATES + ]; + + private readonly BitEncoder[] _posEncoders = new BitEncoder[ + Base.K_NUM_FULL_DISTANCES - Base.K_END_POS_MODEL_INDEX + ]; + + private BitTreeEncoder _posAlignEncoder = new BitTreeEncoder(Base.K_NUM_ALIGN_BITS); + + private readonly LenPriceTableEncoder _lenEncoder = new LenPriceTableEncoder(); + private readonly LenPriceTableEncoder _repMatchLenEncoder = new LenPriceTableEncoder(); + + private readonly LiteralEncoder _literalEncoder = new LiteralEncoder(); + + private readonly uint[] _matchDistances = new uint[(Base.K_MATCH_MAX_LEN * 2) + 2]; + + private uint _numFastBytes = K_NUM_FAST_BYTES_DEFAULT; + private uint _longestMatchLength; + private uint _numDistancePairs; + + private uint _additionalOffset; + + private uint _optimumEndIndex; + private uint _optimumCurrentIndex; + + private bool _longestMatchWasFound; + + private readonly uint[] _posSlotPrices = new uint[ + 1 << (Base.K_NUM_POS_SLOT_BITS + Base.K_NUM_LEN_TO_POS_STATES_BITS) + ]; + private readonly uint[] _distancesPrices = new uint[ + Base.K_NUM_FULL_DISTANCES << Base.K_NUM_LEN_TO_POS_STATES_BITS + ]; + private readonly uint[] _alignPrices = new uint[Base.K_ALIGN_TABLE_SIZE]; + private uint _alignPriceCount; + + private uint _distTableSize = (K_DEFAULT_DICTIONARY_LOG_SIZE * 2); + + private int _posStateBits = 2; + private uint _posStateMask = (4 - 1); + private int _numLiteralPosStateBits; + private int _numLiteralContextBits = 3; + + private uint _dictionarySize = (1 << K_DEFAULT_DICTIONARY_LOG_SIZE); + private uint _dictionarySizePrev = 0xFFFFFFFF; + private uint _numFastBytesPrev = 0xFFFFFFFF; + + private long _nowPos64; + private bool _finished; + private Stream _inStream; + + private EMatchFinderType _matchFinderType = EMatchFinderType.Bt4; + private bool _writeEndMark; + + private bool _needReleaseMfStream; + private bool _processingMode; + + private void Create() + { + if (_matchFinder is null) + { + var bt = new BinTree(); + var numHashBytes = 4; + if (_matchFinderType == EMatchFinderType.Bt2) + { + numHashBytes = 2; + } + bt.SetType(numHashBytes); + _matchFinder = bt; + } + _literalEncoder.Create(_numLiteralPosStateBits, _numLiteralContextBits); + + if (_dictionarySize == _dictionarySizePrev && _numFastBytesPrev == _numFastBytes) + { + return; + } + _matchFinder.Create( + _dictionarySize, + K_NUM_OPTS, + _numFastBytes, + Base.K_MATCH_MAX_LEN + 1 + K_NUM_OPTS + ); + _dictionarySizePrev = _dictionarySize; + _numFastBytesPrev = _numFastBytes; + } + + public Encoder() + { + for (var i = 0; i < K_NUM_OPTS; i++) + { + _optimum[i] = new Optimal(); + } + for (var i = 0; i < Base.K_NUM_LEN_TO_POS_STATES; i++) + { + _posSlotEncoder[i] = new BitTreeEncoder(Base.K_NUM_POS_SLOT_BITS); + } + } + + private void SetWriteEndMarkerMode(bool writeEndMarker) + { + _writeEndMark = writeEndMarker; + } + + private void Init() + { + BaseInit(); + _rangeEncoder.Init(); + + uint i; + for (i = 0; i < Base.K_NUM_STATES; i++) + { + for (uint j = 0; j <= _posStateMask; j++) + { + var complexState = (i << Base.K_NUM_POS_STATES_BITS_MAX) + j; + _isMatch[complexState].Init(); + _isRep0Long[complexState].Init(); + } + _isRep[i].Init(); + _isRepG0[i].Init(); + _isRepG1[i].Init(); + _isRepG2[i].Init(); + } + _literalEncoder.Init(); + for (i = 0; i < Base.K_NUM_LEN_TO_POS_STATES; i++) + { + _posSlotEncoder[i].Init(); + } + for (i = 0; i < Base.K_NUM_FULL_DISTANCES - Base.K_END_POS_MODEL_INDEX; i++) + { + _posEncoders[i].Init(); + } + + _lenEncoder.Init((uint)1 << _posStateBits); + _repMatchLenEncoder.Init((uint)1 << _posStateBits); + + _posAlignEncoder.Init(); + + _longestMatchWasFound = false; + _optimumEndIndex = 0; + _optimumCurrentIndex = 0; + _additionalOffset = 0; + } + + private void ReadMatchDistances(out uint lenRes, out uint numDistancePairs) + { + lenRes = 0; + numDistancePairs = _matchFinder.GetMatches(_matchDistances); + if (numDistancePairs > 0) + { + lenRes = _matchDistances[numDistancePairs - 2]; + if (lenRes == _numFastBytes) + { + lenRes += _matchFinder.GetMatchLen( + (int)lenRes - 1, + _matchDistances[numDistancePairs - 1], + Base.K_MATCH_MAX_LEN - lenRes + ); + } + } + _additionalOffset++; + } + + private void MovePos(uint num) + { + if (num > 0) + { + _matchFinder.Skip(num); + _additionalOffset += num; + } + } + + private uint GetRepLen1Price(Base.State state, uint posState) + { + return _isRepG0[state._index].GetPrice0() + + _isRep0Long[ + (state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState + ].GetPrice0(); + } + + private uint GetPureRepPrice(uint repIndex, Base.State state, uint posState) + { + uint price; + if (repIndex == 0) + { + price = _isRepG0[state._index].GetPrice0(); + price += _isRep0Long[ + (state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState + ].GetPrice1(); + } + else + { + price = _isRepG0[state._index].GetPrice1(); + if (repIndex == 1) + { + price += _isRepG1[state._index].GetPrice0(); + } + else + { + price += _isRepG1[state._index].GetPrice1(); + price += _isRepG2[state._index].GetPrice(repIndex - 2); + } + } + return price; + } + + private uint GetRepPrice(uint repIndex, uint len, Base.State state, uint posState) + { + var price = _repMatchLenEncoder.GetPrice(len - Base.K_MATCH_MIN_LEN, posState); + return price + GetPureRepPrice(repIndex, state, posState); + } + + private uint GetPosLenPrice(uint pos, uint len, uint posState) + { + uint price; + var lenToPosState = Base.GetLenToPosState(len); + if (pos < Base.K_NUM_FULL_DISTANCES) + { + price = _distancesPrices[(lenToPosState * Base.K_NUM_FULL_DISTANCES) + pos]; + } + else + { + price = + _posSlotPrices[(lenToPosState << Base.K_NUM_POS_SLOT_BITS) + GetPosSlot2(pos)] + + _alignPrices[pos & Base.K_ALIGN_MASK]; + } + return price + _lenEncoder.GetPrice(len - Base.K_MATCH_MIN_LEN, posState); + } + + private uint Backward(out uint backRes, uint cur) + { + _optimumEndIndex = cur; + var posMem = _optimum[cur]._posPrev; + var backMem = _optimum[cur]._backPrev; + do + { + if (_optimum[cur]._prev1IsChar) + { + _optimum[posMem].MakeAsChar(); + _optimum[posMem]._posPrev = posMem - 1; + if (_optimum[cur]._prev2) + { + _optimum[posMem - 1]._prev1IsChar = false; + _optimum[posMem - 1]._posPrev = _optimum[cur]._posPrev2; + _optimum[posMem - 1]._backPrev = _optimum[cur]._backPrev2; + } + } + var posPrev = posMem; + var backCur = backMem; + + backMem = _optimum[posPrev]._backPrev; + posMem = _optimum[posPrev]._posPrev; + + _optimum[posPrev]._backPrev = backCur; + _optimum[posPrev]._posPrev = cur; + cur = posPrev; + } while (cur > 0); + backRes = _optimum[0]._backPrev; + _optimumCurrentIndex = _optimum[0]._posPrev; + return _optimumCurrentIndex; + } + + private readonly uint[] _reps = new uint[Base.K_NUM_REP_DISTANCES]; + private readonly uint[] _repLens = new uint[Base.K_NUM_REP_DISTANCES]; + + private uint GetOptimum(uint position, out uint backRes) + { + if (_optimumEndIndex != _optimumCurrentIndex) + { + var lenRes = _optimum[_optimumCurrentIndex]._posPrev - _optimumCurrentIndex; + backRes = _optimum[_optimumCurrentIndex]._backPrev; + _optimumCurrentIndex = _optimum[_optimumCurrentIndex]._posPrev; + return lenRes; + } + _optimumCurrentIndex = _optimumEndIndex = 0; + + uint lenMain, + numDistancePairs; + if (!_longestMatchWasFound) + { + ReadMatchDistances(out lenMain, out numDistancePairs); + } + else + { + lenMain = _longestMatchLength; + numDistancePairs = _numDistancePairs; + _longestMatchWasFound = false; + } + + var numAvailableBytes = _matchFinder.GetNumAvailableBytes() + 1; + if (numAvailableBytes < 2) + { + backRes = 0xFFFFFFFF; + return 1; + } + if (numAvailableBytes > Base.K_MATCH_MAX_LEN) + { + numAvailableBytes = Base.K_MATCH_MAX_LEN; + } + + uint repMaxIndex = 0; + uint i; + for (i = 0; i < Base.K_NUM_REP_DISTANCES; i++) + { + _reps[i] = _repDistances[i]; + _repLens[i] = _matchFinder.GetMatchLen(0 - 1, _reps[i], Base.K_MATCH_MAX_LEN); + if (_repLens[i] > _repLens[repMaxIndex]) + { + repMaxIndex = i; + } + } + if (_repLens[repMaxIndex] >= _numFastBytes) + { + backRes = repMaxIndex; + var lenRes = _repLens[repMaxIndex]; + MovePos(lenRes - 1); + return lenRes; + } + + if (lenMain >= _numFastBytes) + { + backRes = _matchDistances[numDistancePairs - 1] + Base.K_NUM_REP_DISTANCES; + MovePos(lenMain - 1); + return lenMain; + } + + var currentByte = _matchFinder.GetIndexByte(0 - 1); + var matchByte = _matchFinder.GetIndexByte((int)(0 - _repDistances[0] - 1 - 1)); + + if (lenMain < 2 && currentByte != matchByte && _repLens[repMaxIndex] < 2) + { + backRes = 0xFFFFFFFF; + return 1; + } + + _optimum[0]._state = _state; + + var posState = (position & _posStateMask); + + _optimum[1]._price = + _isMatch[(_state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState].GetPrice0() + + _literalEncoder + .GetSubCoder(position, _previousByte) + .GetPrice(!_state.IsCharState(), matchByte, currentByte); + _optimum[1].MakeAsChar(); + + var matchPrice = _isMatch[ + (_state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState + ].GetPrice1(); + var repMatchPrice = matchPrice + _isRep[_state._index].GetPrice1(); + + if (matchByte == currentByte) + { + var shortRepPrice = repMatchPrice + GetRepLen1Price(_state, posState); + if (shortRepPrice < _optimum[1]._price) + { + _optimum[1]._price = shortRepPrice; + _optimum[1].MakeAsShortRep(); + } + } + + var lenEnd = ((lenMain >= _repLens[repMaxIndex]) ? lenMain : _repLens[repMaxIndex]); + + if (lenEnd < 2) + { + backRes = _optimum[1]._backPrev; + return 1; + } + + _optimum[1]._posPrev = 0; + + _optimum[0]._backs0 = _reps[0]; + _optimum[0]._backs1 = _reps[1]; + _optimum[0]._backs2 = _reps[2]; + _optimum[0]._backs3 = _reps[3]; + + var len = lenEnd; + do + { + _optimum[len--]._price = K_IFINITY_PRICE; + } while (len >= 2); + + for (i = 0; i < Base.K_NUM_REP_DISTANCES; i++) + { + var repLen = _repLens[i]; + if (repLen < 2) + { + continue; + } + var price = repMatchPrice + GetPureRepPrice(i, _state, posState); + do + { + var curAndLenPrice = + price + _repMatchLenEncoder.GetPrice(repLen - 2, posState); + var optimum = _optimum[repLen]; + if (curAndLenPrice < optimum._price) + { + optimum._price = curAndLenPrice; + optimum._posPrev = 0; + optimum._backPrev = i; + optimum._prev1IsChar = false; + } + } while (--repLen >= 2); + } + + var normalMatchPrice = matchPrice + _isRep[_state._index].GetPrice0(); + + len = ((_repLens[0] >= 2) ? _repLens[0] + 1 : 2); + if (len <= lenMain) + { + uint offs = 0; + while (len > _matchDistances[offs]) + { + offs += 2; + } + for (; ; len++) + { + var distance = _matchDistances[offs + 1]; + var curAndLenPrice = + normalMatchPrice + GetPosLenPrice(distance, len, posState); + var optimum = _optimum[len]; + if (curAndLenPrice < optimum._price) + { + optimum._price = curAndLenPrice; + optimum._posPrev = 0; + optimum._backPrev = distance + Base.K_NUM_REP_DISTANCES; + optimum._prev1IsChar = false; + } + if (len == _matchDistances[offs]) + { + offs += 2; + if (offs == numDistancePairs) { - state = _optimum[_optimum[cur]._posPrev2]._state; - if (_optimum[cur]._backPrev2 < Base.K_NUM_REP_DISTANCES) - { - state.UpdateRep(); - } - else - { - state.UpdateMatch(); - } + break; + } + } + } + } + + uint cur = 0; + + while (true) + { + cur++; + if (cur == lenEnd) + { + return Backward(out backRes, cur); + } + ReadMatchDistances(out var newLen, out numDistancePairs); + if (newLen >= _numFastBytes) + { + _numDistancePairs = numDistancePairs; + _longestMatchLength = newLen; + _longestMatchWasFound = true; + return Backward(out backRes, cur); + } + position++; + var posPrev = _optimum[cur]._posPrev; + Base.State state; + if (_optimum[cur]._prev1IsChar) + { + posPrev--; + if (_optimum[cur]._prev2) + { + state = _optimum[_optimum[cur]._posPrev2]._state; + if (_optimum[cur]._backPrev2 < Base.K_NUM_REP_DISTANCES) + { + state.UpdateRep(); } else { - state = _optimum[posPrev]._state; + state.UpdateMatch(); } - state.UpdateChar(); } else { state = _optimum[posPrev]._state; } - if (posPrev == cur - 1) + state.UpdateChar(); + } + else + { + state = _optimum[posPrev]._state; + } + if (posPrev == cur - 1) + { + if (_optimum[cur].IsShortRep()) { - if (_optimum[cur].IsShortRep()) - { - state.UpdateShortRep(); - } - else - { - state.UpdateChar(); - } + state.UpdateShortRep(); } else { - UInt32 pos; - if (_optimum[cur]._prev1IsChar && _optimum[cur]._prev2) + state.UpdateChar(); + } + } + else + { + uint pos; + if (_optimum[cur]._prev1IsChar && _optimum[cur]._prev2) + { + posPrev = _optimum[cur]._posPrev2; + pos = _optimum[cur]._backPrev2; + state.UpdateRep(); + } + else + { + pos = _optimum[cur]._backPrev; + if (pos < Base.K_NUM_REP_DISTANCES) { - posPrev = _optimum[cur]._posPrev2; - pos = _optimum[cur]._backPrev2; state.UpdateRep(); } else { - pos = _optimum[cur]._backPrev; - if (pos < Base.K_NUM_REP_DISTANCES) - { - state.UpdateRep(); - } - else - { - state.UpdateMatch(); - } + state.UpdateMatch(); } - Optimal opt = _optimum[posPrev]; - if (pos < Base.K_NUM_REP_DISTANCES) + } + var opt = _optimum[posPrev]; + if (pos < Base.K_NUM_REP_DISTANCES) + { + if (pos == 0) { - if (pos == 0) - { - _reps[0] = opt._backs0; - _reps[1] = opt._backs1; - _reps[2] = opt._backs2; - _reps[3] = opt._backs3; - } - else if (pos == 1) - { - _reps[0] = opt._backs1; - _reps[1] = opt._backs0; - _reps[2] = opt._backs2; - _reps[3] = opt._backs3; - } - else if (pos == 2) - { - _reps[0] = opt._backs2; - _reps[1] = opt._backs0; - _reps[2] = opt._backs1; - _reps[3] = opt._backs3; - } - else - { - _reps[0] = opt._backs3; - _reps[1] = opt._backs0; - _reps[2] = opt._backs1; - _reps[3] = opt._backs2; - } + _reps[0] = opt._backs0; + _reps[1] = opt._backs1; + _reps[2] = opt._backs2; + _reps[3] = opt._backs3; + } + else if (pos == 1) + { + _reps[0] = opt._backs1; + _reps[1] = opt._backs0; + _reps[2] = opt._backs2; + _reps[3] = opt._backs3; + } + else if (pos == 2) + { + _reps[0] = opt._backs2; + _reps[1] = opt._backs0; + _reps[2] = opt._backs1; + _reps[3] = opt._backs3; } else { - _reps[0] = (pos - Base.K_NUM_REP_DISTANCES); + _reps[0] = opt._backs3; _reps[1] = opt._backs0; _reps[2] = opt._backs1; _reps[3] = opt._backs2; } } - _optimum[cur]._state = state; - _optimum[cur]._backs0 = _reps[0]; - _optimum[cur]._backs1 = _reps[1]; - _optimum[cur]._backs2 = _reps[2]; - _optimum[cur]._backs3 = _reps[3]; - UInt32 curPrice = _optimum[cur]._price; - - currentByte = _matchFinder.GetIndexByte(0 - 1); - matchByte = _matchFinder.GetIndexByte((Int32)(0 - _reps[0] - 1 - 1)); - - posState = (position & _posStateMask); - - UInt32 curAnd1Price = - curPrice - + _isMatch[ - (state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState - ].GetPrice0() - + _literalEncoder - .GetSubCoder(position, _matchFinder.GetIndexByte(0 - 2)) - .GetPrice(!state.IsCharState(), matchByte, currentByte); - - Optimal nextOptimum = _optimum[cur + 1]; - - bool nextIsChar = false; - if (curAnd1Price < nextOptimum._price) + else { - nextOptimum._price = curAnd1Price; + _reps[0] = (pos - Base.K_NUM_REP_DISTANCES); + _reps[1] = opt._backs0; + _reps[2] = opt._backs1; + _reps[3] = opt._backs2; + } + } + _optimum[cur]._state = state; + _optimum[cur]._backs0 = _reps[0]; + _optimum[cur]._backs1 = _reps[1]; + _optimum[cur]._backs2 = _reps[2]; + _optimum[cur]._backs3 = _reps[3]; + var curPrice = _optimum[cur]._price; + + currentByte = _matchFinder.GetIndexByte(0 - 1); + matchByte = _matchFinder.GetIndexByte((int)(0 - _reps[0] - 1 - 1)); + + posState = (position & _posStateMask); + + var curAnd1Price = + curPrice + + _isMatch[ + (state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState + ].GetPrice0() + + _literalEncoder + .GetSubCoder(position, _matchFinder.GetIndexByte(0 - 2)) + .GetPrice(!state.IsCharState(), matchByte, currentByte); + + var nextOptimum = _optimum[cur + 1]; + + var nextIsChar = false; + if (curAnd1Price < nextOptimum._price) + { + nextOptimum._price = curAnd1Price; + nextOptimum._posPrev = cur; + nextOptimum.MakeAsChar(); + nextIsChar = true; + } + + matchPrice = + curPrice + + _isMatch[ + (state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState + ].GetPrice1(); + repMatchPrice = matchPrice + _isRep[state._index].GetPrice1(); + + if ( + matchByte == currentByte + && !(nextOptimum._posPrev < cur && nextOptimum._backPrev == 0) + ) + { + var shortRepPrice = repMatchPrice + GetRepLen1Price(state, posState); + if (shortRepPrice <= nextOptimum._price) + { + nextOptimum._price = shortRepPrice; nextOptimum._posPrev = cur; - nextOptimum.MakeAsChar(); + nextOptimum.MakeAsShortRep(); nextIsChar = true; } + } - matchPrice = - curPrice - + _isMatch[ - (state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState - ].GetPrice1(); - repMatchPrice = matchPrice + _isRep[state._index].GetPrice1(); + var numAvailableBytesFull = _matchFinder.GetNumAvailableBytes() + 1; + numAvailableBytesFull = Math.Min(K_NUM_OPTS - 1 - cur, numAvailableBytesFull); + numAvailableBytes = numAvailableBytesFull; - if ( - matchByte == currentByte - && !(nextOptimum._posPrev < cur && nextOptimum._backPrev == 0) - ) + if (numAvailableBytes < 2) + { + continue; + } + if (numAvailableBytes > _numFastBytes) + { + numAvailableBytes = _numFastBytes; + } + if (!nextIsChar && matchByte != currentByte) + { + // try Literal + rep0 + var t = Math.Min(numAvailableBytesFull - 1, _numFastBytes); + var lenTest2 = _matchFinder.GetMatchLen(0, _reps[0], t); + if (lenTest2 >= 2) { - UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(state, posState); - if (shortRepPrice <= nextOptimum._price) + var state2 = state; + state2.UpdateChar(); + var posStateNext = (position + 1) & _posStateMask; + var nextRepMatchPrice = + curAnd1Price + + _isMatch[ + (state2._index << Base.K_NUM_POS_STATES_BITS_MAX) + posStateNext + ].GetPrice1() + + _isRep[state2._index].GetPrice1(); { - nextOptimum._price = shortRepPrice; - nextOptimum._posPrev = cur; - nextOptimum.MakeAsShortRep(); - nextIsChar = true; - } - } - - UInt32 numAvailableBytesFull = _matchFinder.GetNumAvailableBytes() + 1; - numAvailableBytesFull = Math.Min(K_NUM_OPTS - 1 - cur, numAvailableBytesFull); - numAvailableBytes = numAvailableBytesFull; - - if (numAvailableBytes < 2) - { - continue; - } - if (numAvailableBytes > _numFastBytes) - { - numAvailableBytes = _numFastBytes; - } - if (!nextIsChar && matchByte != currentByte) - { - // try Literal + rep0 - UInt32 t = Math.Min(numAvailableBytesFull - 1, _numFastBytes); - UInt32 lenTest2 = _matchFinder.GetMatchLen(0, _reps[0], t); - if (lenTest2 >= 2) - { - Base.State state2 = state; - state2.UpdateChar(); - UInt32 posStateNext = (position + 1) & _posStateMask; - UInt32 nextRepMatchPrice = - curAnd1Price - + _isMatch[ - (state2._index << Base.K_NUM_POS_STATES_BITS_MAX) + posStateNext - ].GetPrice1() - + _isRep[state2._index].GetPrice1(); - { - UInt32 offset = cur + 1 + lenTest2; - while (lenEnd < offset) - { - _optimum[++lenEnd]._price = K_IFINITY_PRICE; - } - UInt32 curAndLenPrice = - nextRepMatchPrice + GetRepPrice(0, lenTest2, state2, posStateNext); - Optimal optimum = _optimum[offset]; - if (curAndLenPrice < optimum._price) - { - optimum._price = curAndLenPrice; - optimum._posPrev = cur + 1; - optimum._backPrev = 0; - optimum._prev1IsChar = true; - optimum._prev2 = false; - } - } - } - } - - UInt32 startLen = 2; // speed optimization - - for (UInt32 repIndex = 0; repIndex < Base.K_NUM_REP_DISTANCES; repIndex++) - { - UInt32 lenTest = _matchFinder.GetMatchLen( - 0 - 1, - _reps[repIndex], - numAvailableBytes - ); - if (lenTest < 2) - { - continue; - } - UInt32 lenTestTemp = lenTest; - do - { - while (lenEnd < cur + lenTest) + var offset = cur + 1 + lenTest2; + while (lenEnd < offset) { _optimum[++lenEnd]._price = K_IFINITY_PRICE; } - UInt32 curAndLenPrice = - repMatchPrice + GetRepPrice(repIndex, lenTest, state, posState); - Optimal optimum = _optimum[cur + lenTest]; + var curAndLenPrice = + nextRepMatchPrice + GetRepPrice(0, lenTest2, state2, posStateNext); + var optimum = _optimum[offset]; if (curAndLenPrice < optimum._price) { optimum._price = curAndLenPrice; - optimum._posPrev = cur; - optimum._backPrev = repIndex; - optimum._prev1IsChar = false; + optimum._posPrev = cur + 1; + optimum._backPrev = 0; + optimum._prev1IsChar = true; + optimum._prev2 = false; } - } while (--lenTest >= 2); - lenTest = lenTestTemp; + } + } + } - if (repIndex == 0) + uint startLen = 2; // speed optimization + + for (uint repIndex = 0; repIndex < Base.K_NUM_REP_DISTANCES; repIndex++) + { + var lenTest = _matchFinder.GetMatchLen( + 0 - 1, + _reps[repIndex], + numAvailableBytes + ); + if (lenTest < 2) + { + continue; + } + var lenTestTemp = lenTest; + do + { + while (lenEnd < cur + lenTest) { - startLen = lenTest + 1; + _optimum[++lenEnd]._price = K_IFINITY_PRICE; + } + var curAndLenPrice = + repMatchPrice + GetRepPrice(repIndex, lenTest, state, posState); + var optimum = _optimum[cur + lenTest]; + if (curAndLenPrice < optimum._price) + { + optimum._price = curAndLenPrice; + optimum._posPrev = cur; + optimum._backPrev = repIndex; + optimum._prev1IsChar = false; + } + } while (--lenTest >= 2); + lenTest = lenTestTemp; + + if (repIndex == 0) + { + startLen = lenTest + 1; + } + + // if (_maxMode) + if (lenTest < numAvailableBytesFull) + { + var t = Math.Min(numAvailableBytesFull - 1 - lenTest, _numFastBytes); + var lenTest2 = _matchFinder.GetMatchLen( + (int)lenTest, + _reps[repIndex], + t + ); + if (lenTest2 >= 2) + { + var state2 = state; + state2.UpdateRep(); + var posStateNext = (position + lenTest) & _posStateMask; + var curAndLenCharPrice = + repMatchPrice + + GetRepPrice(repIndex, lenTest, state, posState) + + _isMatch[ + (state2._index << Base.K_NUM_POS_STATES_BITS_MAX) + posStateNext + ].GetPrice0() + + _literalEncoder + .GetSubCoder( + position + lenTest, + _matchFinder.GetIndexByte((int)lenTest - 1 - 1) + ) + .GetPrice( + true, + _matchFinder.GetIndexByte( + (int)lenTest - 1 - (int)(_reps[repIndex] + 1) + ), + _matchFinder.GetIndexByte((int)lenTest - 1) + ); + state2.UpdateChar(); + posStateNext = (position + lenTest + 1) & _posStateMask; + var nextMatchPrice = + curAndLenCharPrice + + _isMatch[ + (state2._index << Base.K_NUM_POS_STATES_BITS_MAX) + posStateNext + ].GetPrice1(); + var nextRepMatchPrice = + nextMatchPrice + _isRep[state2._index].GetPrice1(); + + // for(; lenTest2 >= 2; lenTest2--) + { + var offset = lenTest + 1 + lenTest2; + while (lenEnd < cur + offset) + { + _optimum[++lenEnd]._price = K_IFINITY_PRICE; + } + var curAndLenPrice = + nextRepMatchPrice + + GetRepPrice(0, lenTest2, state2, posStateNext); + var optimum = _optimum[cur + offset]; + if (curAndLenPrice < optimum._price) + { + optimum._price = curAndLenPrice; + optimum._posPrev = cur + lenTest + 1; + optimum._backPrev = 0; + optimum._prev1IsChar = true; + optimum._prev2 = true; + optimum._posPrev2 = cur; + optimum._backPrev2 = repIndex; + } + } + } + } + } + + if (newLen > numAvailableBytes) + { + newLen = numAvailableBytes; + for ( + numDistancePairs = 0; + newLen > _matchDistances[numDistancePairs]; + numDistancePairs += 2 + ) + { + ; + } + _matchDistances[numDistancePairs] = newLen; + numDistancePairs += 2; + } + if (newLen >= startLen) + { + normalMatchPrice = matchPrice + _isRep[state._index].GetPrice0(); + while (lenEnd < cur + newLen) + { + _optimum[++lenEnd]._price = K_IFINITY_PRICE; + } + + uint offs = 0; + while (startLen > _matchDistances[offs]) + { + offs += 2; + } + + for (var lenTest = startLen; ; lenTest++) + { + var curBack = _matchDistances[offs + 1]; + var curAndLenPrice = + normalMatchPrice + GetPosLenPrice(curBack, lenTest, posState); + var optimum = _optimum[cur + lenTest]; + if (curAndLenPrice < optimum._price) + { + optimum._price = curAndLenPrice; + optimum._posPrev = cur; + optimum._backPrev = curBack + Base.K_NUM_REP_DISTANCES; + optimum._prev1IsChar = false; } - // if (_maxMode) - if (lenTest < numAvailableBytesFull) + if (lenTest == _matchDistances[offs]) { - UInt32 t = Math.Min(numAvailableBytesFull - 1 - lenTest, _numFastBytes); - UInt32 lenTest2 = _matchFinder.GetMatchLen( - (Int32)lenTest, - _reps[repIndex], - t - ); - if (lenTest2 >= 2) + if (lenTest < numAvailableBytesFull) { - Base.State state2 = state; - state2.UpdateRep(); - UInt32 posStateNext = (position + lenTest) & _posStateMask; - UInt32 curAndLenCharPrice = - repMatchPrice - + GetRepPrice(repIndex, lenTest, state, posState) - + _isMatch[ - (state2._index << Base.K_NUM_POS_STATES_BITS_MAX) + posStateNext - ].GetPrice0() - + _literalEncoder - .GetSubCoder( - position + lenTest, - _matchFinder.GetIndexByte((Int32)lenTest - 1 - 1) - ) - .GetPrice( - true, - _matchFinder.GetIndexByte( - (Int32)lenTest - 1 - (Int32)(_reps[repIndex] + 1) - ), - _matchFinder.GetIndexByte((Int32)lenTest - 1) - ); - state2.UpdateChar(); - posStateNext = (position + lenTest + 1) & _posStateMask; - UInt32 nextMatchPrice = - curAndLenCharPrice - + _isMatch[ - (state2._index << Base.K_NUM_POS_STATES_BITS_MAX) + posStateNext - ].GetPrice1(); - UInt32 nextRepMatchPrice = - nextMatchPrice + _isRep[state2._index].GetPrice1(); - - // for(; lenTest2 >= 2; lenTest2--) + var t = Math.Min( + numAvailableBytesFull - 1 - lenTest, + _numFastBytes + ); + var lenTest2 = _matchFinder.GetMatchLen( + (int)lenTest, + curBack, + t + ); + if (lenTest2 >= 2) { - UInt32 offset = lenTest + 1 + lenTest2; + var state2 = state; + state2.UpdateMatch(); + var posStateNext = (position + lenTest) & _posStateMask; + var curAndLenCharPrice = + curAndLenPrice + + _isMatch[ + (state2._index << Base.K_NUM_POS_STATES_BITS_MAX) + + posStateNext + ].GetPrice0() + + _literalEncoder + .GetSubCoder( + position + lenTest, + _matchFinder.GetIndexByte((int)lenTest - 1 - 1) + ) + .GetPrice( + true, + _matchFinder.GetIndexByte( + (int)lenTest - (int)(curBack + 1) - 1 + ), + _matchFinder.GetIndexByte((int)lenTest - 1) + ); + state2.UpdateChar(); + posStateNext = (position + lenTest + 1) & _posStateMask; + var nextMatchPrice = + curAndLenCharPrice + + _isMatch[ + (state2._index << Base.K_NUM_POS_STATES_BITS_MAX) + + posStateNext + ].GetPrice1(); + var nextRepMatchPrice = + nextMatchPrice + _isRep[state2._index].GetPrice1(); + + var offset = lenTest + 1 + lenTest2; while (lenEnd < cur + offset) { _optimum[++lenEnd]._price = K_IFINITY_PRICE; } - UInt32 curAndLenPrice = + curAndLenPrice = nextRepMatchPrice + GetRepPrice(0, lenTest2, state2, posStateNext); - Optimal optimum = _optimum[cur + offset]; + optimum = _optimum[cur + offset]; if (curAndLenPrice < optimum._price) { optimum._price = curAndLenPrice; @@ -1153,238 +1265,98 @@ namespace SharpCompress.Compressors.LZMA optimum._prev1IsChar = true; optimum._prev2 = true; optimum._posPrev2 = cur; - optimum._backPrev2 = repIndex; + optimum._backPrev2 = curBack + Base.K_NUM_REP_DISTANCES; } } } - } - } - - if (newLen > numAvailableBytes) - { - newLen = numAvailableBytes; - for ( - numDistancePairs = 0; - newLen > _matchDistances[numDistancePairs]; - numDistancePairs += 2 - ) - { - ; - } - _matchDistances[numDistancePairs] = newLen; - numDistancePairs += 2; - } - if (newLen >= startLen) - { - normalMatchPrice = matchPrice + _isRep[state._index].GetPrice0(); - while (lenEnd < cur + newLen) - { - _optimum[++lenEnd]._price = K_IFINITY_PRICE; - } - - UInt32 offs = 0; - while (startLen > _matchDistances[offs]) - { offs += 2; - } - - for (UInt32 lenTest = startLen; ; lenTest++) - { - UInt32 curBack = _matchDistances[offs + 1]; - UInt32 curAndLenPrice = - normalMatchPrice + GetPosLenPrice(curBack, lenTest, posState); - Optimal optimum = _optimum[cur + lenTest]; - if (curAndLenPrice < optimum._price) + if (offs == numDistancePairs) { - optimum._price = curAndLenPrice; - optimum._posPrev = cur; - optimum._backPrev = curBack + Base.K_NUM_REP_DISTANCES; - optimum._prev1IsChar = false; - } - - if (lenTest == _matchDistances[offs]) - { - if (lenTest < numAvailableBytesFull) - { - UInt32 t = Math.Min( - numAvailableBytesFull - 1 - lenTest, - _numFastBytes - ); - UInt32 lenTest2 = _matchFinder.GetMatchLen( - (Int32)lenTest, - curBack, - t - ); - if (lenTest2 >= 2) - { - Base.State state2 = state; - state2.UpdateMatch(); - UInt32 posStateNext = (position + lenTest) & _posStateMask; - UInt32 curAndLenCharPrice = - curAndLenPrice - + _isMatch[ - (state2._index << Base.K_NUM_POS_STATES_BITS_MAX) - + posStateNext - ].GetPrice0() - + _literalEncoder - .GetSubCoder( - position + lenTest, - _matchFinder.GetIndexByte((Int32)lenTest - 1 - 1) - ) - .GetPrice( - true, - _matchFinder.GetIndexByte( - (Int32)lenTest - (Int32)(curBack + 1) - 1 - ), - _matchFinder.GetIndexByte((Int32)lenTest - 1) - ); - state2.UpdateChar(); - posStateNext = (position + lenTest + 1) & _posStateMask; - UInt32 nextMatchPrice = - curAndLenCharPrice - + _isMatch[ - (state2._index << Base.K_NUM_POS_STATES_BITS_MAX) - + posStateNext - ].GetPrice1(); - UInt32 nextRepMatchPrice = - nextMatchPrice + _isRep[state2._index].GetPrice1(); - - UInt32 offset = lenTest + 1 + lenTest2; - while (lenEnd < cur + offset) - { - _optimum[++lenEnd]._price = K_IFINITY_PRICE; - } - curAndLenPrice = - nextRepMatchPrice - + GetRepPrice(0, lenTest2, state2, posStateNext); - optimum = _optimum[cur + offset]; - if (curAndLenPrice < optimum._price) - { - optimum._price = curAndLenPrice; - optimum._posPrev = cur + lenTest + 1; - optimum._backPrev = 0; - optimum._prev1IsChar = true; - optimum._prev2 = true; - optimum._posPrev2 = cur; - optimum._backPrev2 = curBack + Base.K_NUM_REP_DISTANCES; - } - } - } - offs += 2; - if (offs == numDistancePairs) - { - break; - } + break; } } } } } + } - private bool ChangePair(UInt32 smallDist, UInt32 bigDist) + private bool ChangePair(uint smallDist, uint bigDist) + { + const int kDif = 7; + return (smallDist < ((uint)(1) << (32 - kDif)) && bigDist >= (smallDist << kDif)); + } + + private void WriteEndMarker(uint posState) + { + if (!_writeEndMark) { - const int kDif = 7; - return (smallDist < ((UInt32)(1) << (32 - kDif)) && bigDist >= (smallDist << kDif)); + return; } - private void WriteEndMarker(UInt32 posState) - { - if (!_writeEndMark) - { - return; - } + _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; + _lenEncoder.Encode(_rangeEncoder, len - Base.K_MATCH_MIN_LEN, posState); + uint posSlot = (1 << Base.K_NUM_POS_SLOT_BITS) - 1; + var lenToPosState = Base.GetLenToPosState(len); + _posSlotEncoder[lenToPosState].Encode(_rangeEncoder, posSlot); + var footerBits = 30; + var posReduced = (((uint)1) << footerBits) - 1; + _rangeEncoder.EncodeDirectBits( + posReduced >> Base.K_NUM_ALIGN_BITS, + footerBits - Base.K_NUM_ALIGN_BITS + ); + _posAlignEncoder.ReverseEncode(_rangeEncoder, posReduced & Base.K_ALIGN_MASK); + } - _isMatch[(_state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState].Encode( - _rangeEncoder, - 1 - ); - _isRep[_state._index].Encode(_rangeEncoder, 0); - _state.UpdateMatch(); - UInt32 len = Base.K_MATCH_MIN_LEN; - _lenEncoder.Encode(_rangeEncoder, len - Base.K_MATCH_MIN_LEN, posState); - UInt32 posSlot = (1 << Base.K_NUM_POS_SLOT_BITS) - 1; - UInt32 lenToPosState = Base.GetLenToPosState(len); - _posSlotEncoder[lenToPosState].Encode(_rangeEncoder, posSlot); - int footerBits = 30; - UInt32 posReduced = (((UInt32)1) << footerBits) - 1; - _rangeEncoder.EncodeDirectBits( - posReduced >> Base.K_NUM_ALIGN_BITS, - footerBits - Base.K_NUM_ALIGN_BITS - ); - _posAlignEncoder.ReverseEncode(_rangeEncoder, posReduced & Base.K_ALIGN_MASK); + private void Flush(uint nowPos) + { + ReleaseMfStream(); + WriteEndMarker(nowPos & _posStateMask); + _rangeEncoder.FlushData(); + _rangeEncoder.FlushStream(); + } + + public void CodeOneBlock(out long inSize, out long outSize, out bool finished) + { + inSize = 0; + outSize = 0; + finished = true; + + if (_inStream != null) + { + _matchFinder.SetStream(_inStream); + _needReleaseMfStream = true; + _inStream = null; } - private void Flush(UInt32 nowPos) + if (_finished) { - ReleaseMfStream(); - WriteEndMarker(nowPos & _posStateMask); - _rangeEncoder.FlushData(); - _rangeEncoder.FlushStream(); + return; } + _finished = true; - public void CodeOneBlock(out Int64 inSize, out Int64 outSize, out bool finished) + var progressPosValuePrev = _nowPos64; + if (_nowPos64 == 0) { - inSize = 0; - outSize = 0; - finished = true; - - if (_inStream != null) + if (_trainSize > 0) { - _matchFinder.SetStream(_inStream); - _needReleaseMfStream = true; - _inStream = null; - } - - if (_finished) - { - return; - } - _finished = true; - - Int64 progressPosValuePrev = _nowPos64; - if (_nowPos64 == 0) - { - if (_trainSize > 0) + for ( + ; + _trainSize > 0 && (!_processingMode || !_matchFinder.IsDataStarved); + _trainSize-- + ) { - for ( - ; - _trainSize > 0 && (!_processingMode || !_matchFinder.IsDataStarved); - _trainSize-- - ) - { - _matchFinder.Skip(1); - } - if (_trainSize == 0) - { - _previousByte = _matchFinder.GetIndexByte(-1); - } + _matchFinder.Skip(1); } - if (_processingMode && _matchFinder.IsDataStarved) + if (_trainSize == 0) { - _finished = false; - return; + _previousByte = _matchFinder.GetIndexByte(-1); } - if (_matchFinder.GetNumAvailableBytes() == 0) - { - Flush((UInt32)_nowPos64); - return; - } - UInt32 len, - numDistancePairs; // it's not used - ReadMatchDistances(out len, out numDistancePairs); - UInt32 posState = (UInt32)(_nowPos64) & _posStateMask; - _isMatch[(_state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState].Encode( - _rangeEncoder, - 0 - ); - _state.UpdateChar(); - Byte curByte = _matchFinder.GetIndexByte((Int32)(0 - _additionalOffset)); - _literalEncoder - .GetSubCoder((UInt32)(_nowPos64), _previousByte) - .Encode(_rangeEncoder, curByte); - _previousByte = curByte; - _additionalOffset--; - _nowPos64++; } if (_processingMode && _matchFinder.IsDataStarved) { @@ -1393,561 +1365,576 @@ namespace SharpCompress.Compressors.LZMA } if (_matchFinder.GetNumAvailableBytes() == 0) { - Flush((UInt32)_nowPos64); + Flush((uint)_nowPos64); return; } - while (true) + // 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 + ); + _state.UpdateChar(); + var curByte = _matchFinder.GetIndexByte((int)(0 - _additionalOffset)); + _literalEncoder + .GetSubCoder((uint)(_nowPos64), _previousByte) + .Encode(_rangeEncoder, curByte); + _previousByte = curByte; + _additionalOffset--; + _nowPos64++; + } + if (_processingMode && _matchFinder.IsDataStarved) + { + _finished = false; + return; + } + if (_matchFinder.GetNumAvailableBytes() == 0) + { + Flush((uint)_nowPos64); + return; + } + while (true) + { + if (_processingMode && _matchFinder.IsDataStarved) { + _finished = false; + return; + } + + var len = GetOptimum((uint)_nowPos64, out var pos); + + var posState = ((uint)_nowPos64) & _posStateMask; + var complexState = (_state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState; + if (len == 1 && pos == 0xFFFFFFFF) + { + _isMatch[complexState].Encode(_rangeEncoder, 0); + var curByte = _matchFinder.GetIndexByte((int)(0 - _additionalOffset)); + var subCoder = _literalEncoder.GetSubCoder( + (uint)_nowPos64, + _previousByte + ); + if (!_state.IsCharState()) + { + var matchByte = _matchFinder.GetIndexByte( + (int)(0 - _repDistances[0] - 1 - _additionalOffset) + ); + subCoder.EncodeMatched(_rangeEncoder, matchByte, curByte); + } + else + { + subCoder.Encode(_rangeEncoder, curByte); + } + _previousByte = curByte; + _state.UpdateChar(); + } + else + { + _isMatch[complexState].Encode(_rangeEncoder, 1); + if (pos < Base.K_NUM_REP_DISTANCES) + { + _isRep[_state._index].Encode(_rangeEncoder, 1); + if (pos == 0) + { + _isRepG0[_state._index].Encode(_rangeEncoder, 0); + if (len == 1) + { + _isRep0Long[complexState].Encode(_rangeEncoder, 0); + } + else + { + _isRep0Long[complexState].Encode(_rangeEncoder, 1); + } + } + else + { + _isRepG0[_state._index].Encode(_rangeEncoder, 1); + if (pos == 1) + { + _isRepG1[_state._index].Encode(_rangeEncoder, 0); + } + else + { + _isRepG1[_state._index].Encode(_rangeEncoder, 1); + _isRepG2[_state._index].Encode(_rangeEncoder, pos - 2); + } + } + if (len == 1) + { + _state.UpdateShortRep(); + } + else + { + _repMatchLenEncoder.Encode( + _rangeEncoder, + len - Base.K_MATCH_MIN_LEN, + posState + ); + _state.UpdateRep(); + } + var distance = _repDistances[pos]; + if (pos != 0) + { + for (var i = pos; i >= 1; i--) + { + _repDistances[i] = _repDistances[i - 1]; + } + _repDistances[0] = distance; + } + } + else + { + _isRep[_state._index].Encode(_rangeEncoder, 0); + _state.UpdateMatch(); + _lenEncoder.Encode(_rangeEncoder, len - Base.K_MATCH_MIN_LEN, posState); + pos -= Base.K_NUM_REP_DISTANCES; + var posSlot = GetPosSlot(pos); + var lenToPosState = Base.GetLenToPosState(len); + _posSlotEncoder[lenToPosState].Encode(_rangeEncoder, posSlot); + + if (posSlot >= Base.K_START_POS_MODEL_INDEX) + { + var footerBits = (int)((posSlot >> 1) - 1); + var baseVal = ((2 | (posSlot & 1)) << footerBits); + var posReduced = pos - baseVal; + + if (posSlot < Base.K_END_POS_MODEL_INDEX) + { + BitTreeEncoder.ReverseEncode( + _posEncoders, + baseVal - posSlot - 1, + _rangeEncoder, + footerBits, + posReduced + ); + } + else + { + _rangeEncoder.EncodeDirectBits( + posReduced >> Base.K_NUM_ALIGN_BITS, + footerBits - Base.K_NUM_ALIGN_BITS + ); + _posAlignEncoder.ReverseEncode( + _rangeEncoder, + posReduced & Base.K_ALIGN_MASK + ); + _alignPriceCount++; + } + } + var distance = pos; + for (var i = Base.K_NUM_REP_DISTANCES - 1; i >= 1; i--) + { + _repDistances[i] = _repDistances[i - 1]; + } + _repDistances[0] = distance; + _matchPriceCount++; + } + _previousByte = _matchFinder.GetIndexByte((int)(len - 1 - _additionalOffset)); + } + _additionalOffset -= len; + _nowPos64 += len; + if (_additionalOffset == 0) + { + // if (!_fastMode) + if (_matchPriceCount >= (1 << 7)) + { + FillDistancesPrices(); + } + if (_alignPriceCount >= Base.K_ALIGN_TABLE_SIZE) + { + FillAlignPrices(); + } + inSize = _nowPos64; + outSize = _rangeEncoder.GetProcessedSizeAdd(); if (_processingMode && _matchFinder.IsDataStarved) { _finished = false; return; } - - UInt32 pos; - UInt32 len = GetOptimum((UInt32)_nowPos64, out pos); - - UInt32 posState = ((UInt32)_nowPos64) & _posStateMask; - UInt32 complexState = (_state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState; - if (len == 1 && pos == 0xFFFFFFFF) + if (_matchFinder.GetNumAvailableBytes() == 0) { - _isMatch[complexState].Encode(_rangeEncoder, 0); - Byte curByte = _matchFinder.GetIndexByte((Int32)(0 - _additionalOffset)); - LiteralEncoder.Encoder2 subCoder = _literalEncoder.GetSubCoder( - (UInt32)_nowPos64, - _previousByte - ); - if (!_state.IsCharState()) - { - Byte matchByte = _matchFinder.GetIndexByte( - (Int32)(0 - _repDistances[0] - 1 - _additionalOffset) - ); - subCoder.EncodeMatched(_rangeEncoder, matchByte, curByte); - } - else - { - subCoder.Encode(_rangeEncoder, curByte); - } - _previousByte = curByte; - _state.UpdateChar(); + Flush((uint)_nowPos64); + return; } - else + + if (_nowPos64 - progressPosValuePrev >= (1 << 12)) { - _isMatch[complexState].Encode(_rangeEncoder, 1); - if (pos < Base.K_NUM_REP_DISTANCES) - { - _isRep[_state._index].Encode(_rangeEncoder, 1); - if (pos == 0) - { - _isRepG0[_state._index].Encode(_rangeEncoder, 0); - if (len == 1) - { - _isRep0Long[complexState].Encode(_rangeEncoder, 0); - } - else - { - _isRep0Long[complexState].Encode(_rangeEncoder, 1); - } - } - else - { - _isRepG0[_state._index].Encode(_rangeEncoder, 1); - if (pos == 1) - { - _isRepG1[_state._index].Encode(_rangeEncoder, 0); - } - else - { - _isRepG1[_state._index].Encode(_rangeEncoder, 1); - _isRepG2[_state._index].Encode(_rangeEncoder, pos - 2); - } - } - if (len == 1) - { - _state.UpdateShortRep(); - } - else - { - _repMatchLenEncoder.Encode( - _rangeEncoder, - len - Base.K_MATCH_MIN_LEN, - posState - ); - _state.UpdateRep(); - } - UInt32 distance = _repDistances[pos]; - if (pos != 0) - { - for (UInt32 i = pos; i >= 1; i--) - { - _repDistances[i] = _repDistances[i - 1]; - } - _repDistances[0] = distance; - } - } - else - { - _isRep[_state._index].Encode(_rangeEncoder, 0); - _state.UpdateMatch(); - _lenEncoder.Encode(_rangeEncoder, len - Base.K_MATCH_MIN_LEN, posState); - pos -= Base.K_NUM_REP_DISTANCES; - UInt32 posSlot = GetPosSlot(pos); - UInt32 lenToPosState = Base.GetLenToPosState(len); - _posSlotEncoder[lenToPosState].Encode(_rangeEncoder, posSlot); - - if (posSlot >= Base.K_START_POS_MODEL_INDEX) - { - int footerBits = (int)((posSlot >> 1) - 1); - UInt32 baseVal = ((2 | (posSlot & 1)) << footerBits); - UInt32 posReduced = pos - baseVal; - - if (posSlot < Base.K_END_POS_MODEL_INDEX) - { - BitTreeEncoder.ReverseEncode( - _posEncoders, - baseVal - posSlot - 1, - _rangeEncoder, - footerBits, - posReduced - ); - } - else - { - _rangeEncoder.EncodeDirectBits( - posReduced >> Base.K_NUM_ALIGN_BITS, - footerBits - Base.K_NUM_ALIGN_BITS - ); - _posAlignEncoder.ReverseEncode( - _rangeEncoder, - posReduced & Base.K_ALIGN_MASK - ); - _alignPriceCount++; - } - } - UInt32 distance = pos; - for (UInt32 i = Base.K_NUM_REP_DISTANCES - 1; i >= 1; i--) - { - _repDistances[i] = _repDistances[i - 1]; - } - _repDistances[0] = distance; - _matchPriceCount++; - } - _previousByte = _matchFinder.GetIndexByte((Int32)(len - 1 - _additionalOffset)); - } - _additionalOffset -= len; - _nowPos64 += len; - if (_additionalOffset == 0) - { - // if (!_fastMode) - if (_matchPriceCount >= (1 << 7)) - { - FillDistancesPrices(); - } - if (_alignPriceCount >= Base.K_ALIGN_TABLE_SIZE) - { - FillAlignPrices(); - } - inSize = _nowPos64; - outSize = _rangeEncoder.GetProcessedSizeAdd(); - if (_processingMode && _matchFinder.IsDataStarved) - { - _finished = false; - return; - } - if (_matchFinder.GetNumAvailableBytes() == 0) - { - Flush((UInt32)_nowPos64); - return; - } - - if (_nowPos64 - progressPosValuePrev >= (1 << 12)) - { - _finished = false; - finished = false; - return; - } + _finished = false; + finished = false; + return; } } } + } - private void ReleaseMfStream() - { - if (_matchFinder != null && _needReleaseMfStream) - { - _matchFinder.ReleaseStream(); - _needReleaseMfStream = false; - } - } - - private void SetOutStream(Stream outStream) - { - _rangeEncoder.SetStream(outStream); - } - - private void ReleaseOutStream() - { - _rangeEncoder.ReleaseStream(); - } - - private void ReleaseStreams() - { - ReleaseMfStream(); - ReleaseOutStream(); - } - - public void SetStreams(Stream inStream, Stream outStream, Int64 inSize, Int64 outSize) - { - _inStream = inStream; - _finished = false; - Create(); - SetOutStream(outStream); - Init(); - _matchFinder.Init(); - - // if (!_fastMode) - { - FillDistancesPrices(); - FillAlignPrices(); - } - - _lenEncoder.SetTableSize(_numFastBytes + 1 - Base.K_MATCH_MIN_LEN); - _lenEncoder.UpdateTables((UInt32)1 << _posStateBits); - _repMatchLenEncoder.SetTableSize(_numFastBytes + 1 - Base.K_MATCH_MIN_LEN); - _repMatchLenEncoder.UpdateTables((UInt32)1 << _posStateBits); - - _nowPos64 = 0; - } - - public void Code( - Stream inStream, - Stream outStream, - Int64 inSize, - Int64 outSize, - ICodeProgress progress - ) + private void ReleaseMfStream() + { + if (_matchFinder != null && _needReleaseMfStream) { + _matchFinder.ReleaseStream(); _needReleaseMfStream = false; - _processingMode = false; - try + } + } + + private void SetOutStream(Stream outStream) + { + _rangeEncoder.SetStream(outStream); + } + + private void ReleaseOutStream() + { + _rangeEncoder.ReleaseStream(); + } + + private void ReleaseStreams() + { + ReleaseMfStream(); + ReleaseOutStream(); + } + + public void SetStreams(Stream inStream, Stream outStream, long inSize, long outSize) + { + _inStream = inStream; + _finished = false; + Create(); + SetOutStream(outStream); + Init(); + _matchFinder.Init(); + + // if (!_fastMode) + { + FillDistancesPrices(); + FillAlignPrices(); + } + + _lenEncoder.SetTableSize(_numFastBytes + 1 - Base.K_MATCH_MIN_LEN); + _lenEncoder.UpdateTables((uint)1 << _posStateBits); + _repMatchLenEncoder.SetTableSize(_numFastBytes + 1 - Base.K_MATCH_MIN_LEN); + _repMatchLenEncoder.UpdateTables((uint)1 << _posStateBits); + + _nowPos64 = 0; + } + + public void Code( + Stream inStream, + Stream outStream, + long inSize, + long outSize, + ICodeProgress progress + ) + { + _needReleaseMfStream = false; + _processingMode = false; + try + { + SetStreams(inStream, outStream, inSize, outSize); + while (true) { - SetStreams(inStream, outStream, inSize, outSize); - while (true) + CodeOneBlock(out var processedInSize, out var processedOutSize, out var finished); + if (finished) { - Int64 processedInSize; - Int64 processedOutSize; - bool finished; - CodeOneBlock(out processedInSize, out processedOutSize, out finished); - if (finished) - { - return; - } - if (progress != null) - { - progress.SetProgress(processedInSize, processedOutSize); - } + return; + } + progress?.SetProgress(processedInSize, processedOutSize); + } + } + finally + { + ReleaseStreams(); + } + } + + public long Code(Stream inStream, bool final) + { + _matchFinder.SetStream(inStream); + _processingMode = !final; + try + { + while (true) + { + CodeOneBlock(out var processedInSize, out var processedOutSize, out var finished); + if (finished) + { + return processedInSize; } } - finally + } + finally + { + _matchFinder.ReleaseStream(); + if (final) { ReleaseStreams(); } } + } - public long Code(Stream inStream, bool final) + public void Train(Stream trainStream) + { + if (_nowPos64 > 0) { - _matchFinder.SetStream(inStream); - _processingMode = !final; - try - { - while (true) - { - Int64 processedInSize; - Int64 processedOutSize; - bool finished; - CodeOneBlock(out processedInSize, out processedOutSize, out finished); - if (finished) - { - return processedInSize; - } - } - } - finally - { - _matchFinder.ReleaseStream(); - if (final) - { - ReleaseStreams(); - } - } + throw new InvalidOperationException(); } - - public void Train(Stream trainStream) + _trainSize = (uint)trainStream.Length; + if (_trainSize > 0) { - if (_nowPos64 > 0) + _matchFinder.SetStream(trainStream); + for (; _trainSize > 0 && !_matchFinder.IsDataStarved; _trainSize--) { - throw new InvalidOperationException(); + _matchFinder.Skip(1); } - _trainSize = (uint)trainStream.Length; - if (_trainSize > 0) + if (_trainSize == 0) { - _matchFinder.SetStream(trainStream); - for (; _trainSize > 0 && !_matchFinder.IsDataStarved; _trainSize--) - { - _matchFinder.Skip(1); - } - if (_trainSize == 0) - { - _previousByte = _matchFinder.GetIndexByte(-1); - } - _matchFinder.ReleaseStream(); + _previousByte = _matchFinder.GetIndexByte(-1); } + _matchFinder.ReleaseStream(); } + } - private const int K_PROP_SIZE = 5; - private readonly Byte[] _properties = new Byte[K_PROP_SIZE]; + private const int K_PROP_SIZE = 5; + private readonly byte[] _properties = new byte[K_PROP_SIZE]; - public void WriteCoderProperties(Stream outStream) + public void WriteCoderProperties(Stream outStream) + { + WriteCoderProperties(_properties); + outStream.Write(_properties, 0, K_PROP_SIZE); + } + + public void WriteCoderProperties(Span span) + { + span[0] = (byte)( + (((_posStateBits * 5) + _numLiteralPosStateBits) * 9) + _numLiteralContextBits + ); + for (var i = 0; i < 4; i++) { - WriteCoderProperties(_properties); - outStream.Write(_properties, 0, K_PROP_SIZE); + span[1 + i] = (byte)((_dictionarySize >> (8 * i)) & 0xFF); } + } - public void WriteCoderProperties(Span span) + private readonly uint[] _tempPrices = new uint[Base.K_NUM_FULL_DISTANCES]; + private uint _matchPriceCount; + + private void FillDistancesPrices() + { + for (var i = Base.K_START_POS_MODEL_INDEX; i < Base.K_NUM_FULL_DISTANCES; i++) { - span[0] = (byte)( - (_posStateBits * 5 + _numLiteralPosStateBits) * 9 + _numLiteralContextBits + var posSlot = GetPosSlot(i); + var footerBits = (int)((posSlot >> 1) - 1); + var baseVal = ((2 | (posSlot & 1)) << footerBits); + _tempPrices[i] = BitTreeEncoder.ReverseGetPrice( + _posEncoders, + baseVal - posSlot - 1, + footerBits, + i - baseVal ); - for (int i = 0; i < 4; i++) - { - span[1 + i] = (byte)((_dictionarySize >> (8 * i)) & 0xFF); - } } - private readonly UInt32[] _tempPrices = new UInt32[Base.K_NUM_FULL_DISTANCES]; - private UInt32 _matchPriceCount; - - private void FillDistancesPrices() + for ( + uint lenToPosState = 0; + lenToPosState < Base.K_NUM_LEN_TO_POS_STATES; + lenToPosState++ + ) { - for (UInt32 i = Base.K_START_POS_MODEL_INDEX; i < Base.K_NUM_FULL_DISTANCES; i++) + uint posSlot; + var encoder = _posSlotEncoder[lenToPosState]; + + var st = (lenToPosState << Base.K_NUM_POS_SLOT_BITS); + for (posSlot = 0; posSlot < _distTableSize; posSlot++) { - UInt32 posSlot = GetPosSlot(i); - int footerBits = (int)((posSlot >> 1) - 1); - UInt32 baseVal = ((2 | (posSlot & 1)) << footerBits); - _tempPrices[i] = BitTreeEncoder.ReverseGetPrice( - _posEncoders, - baseVal - posSlot - 1, - footerBits, - i - baseVal + _posSlotPrices[st + posSlot] = encoder.GetPrice(posSlot); + } + for (posSlot = Base.K_END_POS_MODEL_INDEX; posSlot < _distTableSize; posSlot++) + { + _posSlotPrices[st + posSlot] += ( + (((posSlot >> 1) - 1) - Base.K_NUM_ALIGN_BITS) + << BitEncoder.K_NUM_BIT_PRICE_SHIFT_BITS ); } - for ( - UInt32 lenToPosState = 0; - lenToPosState < Base.K_NUM_LEN_TO_POS_STATES; - lenToPosState++ - ) + var st2 = lenToPosState * Base.K_NUM_FULL_DISTANCES; + uint i; + for (i = 0; i < Base.K_START_POS_MODEL_INDEX; i++) { - UInt32 posSlot; - BitTreeEncoder encoder = _posSlotEncoder[lenToPosState]; - - UInt32 st = (lenToPosState << Base.K_NUM_POS_SLOT_BITS); - for (posSlot = 0; posSlot < _distTableSize; posSlot++) - { - _posSlotPrices[st + posSlot] = encoder.GetPrice(posSlot); - } - for (posSlot = Base.K_END_POS_MODEL_INDEX; posSlot < _distTableSize; posSlot++) - { - _posSlotPrices[st + posSlot] += ( - (((posSlot >> 1) - 1) - Base.K_NUM_ALIGN_BITS) - << BitEncoder.K_NUM_BIT_PRICE_SHIFT_BITS - ); - } - - UInt32 st2 = lenToPosState * Base.K_NUM_FULL_DISTANCES; - UInt32 i; - for (i = 0; i < Base.K_START_POS_MODEL_INDEX; i++) - { - _distancesPrices[st2 + i] = _posSlotPrices[st + i]; - } - for (; i < Base.K_NUM_FULL_DISTANCES; i++) - { - _distancesPrices[st2 + i] = _posSlotPrices[st + GetPosSlot(i)] + _tempPrices[i]; - } + _distancesPrices[st2 + i] = _posSlotPrices[st + i]; } - _matchPriceCount = 0; - } - - private void FillAlignPrices() - { - for (UInt32 i = 0; i < Base.K_ALIGN_TABLE_SIZE; i++) + for (; i < Base.K_NUM_FULL_DISTANCES; i++) { - _alignPrices[i] = _posAlignEncoder.ReverseGetPrice(i); + _distancesPrices[st2 + i] = _posSlotPrices[st + GetPosSlot(i)] + _tempPrices[i]; } - _alignPriceCount = 0; } + _matchPriceCount = 0; + } - private static readonly string[] K_MATCH_FINDER_I_DS = { "BT2", "BT4" }; - - private static int FindMatchFinder(string s) + private void FillAlignPrices() + { + for (uint i = 0; i < Base.K_ALIGN_TABLE_SIZE; i++) { - for (int m = 0; m < K_MATCH_FINDER_I_DS.Length; m++) + _alignPrices[i] = _posAlignEncoder.ReverseGetPrice(i); + } + _alignPriceCount = 0; + } + + private static readonly string[] K_MATCH_FINDER_I_DS = { "BT2", "BT4" }; + + private static int FindMatchFinder(string s) + { + for (var m = 0; m < K_MATCH_FINDER_I_DS.Length; m++) + { + if (string.Equals(s, K_MATCH_FINDER_I_DS[m], StringComparison.OrdinalIgnoreCase)) { - if (string.Equals(s, K_MATCH_FINDER_I_DS[m], StringComparison.OrdinalIgnoreCase)) - { - return m; - } + return m; } - return -1; } + return -1; + } - public void SetCoderProperties(CoderPropId[] propIDs, object[] properties) + public void SetCoderProperties(CoderPropId[] propIDs, object[] properties) + { + for (uint i = 0; i < properties.Length; i++) { - for (UInt32 i = 0; i < properties.Length; i++) + var prop = properties[i]; + switch (propIDs[i]) { - object prop = properties[i]; - switch (propIDs[i]) + case CoderPropId.NumFastBytes: { - case CoderPropId.NumFastBytes: + if (prop is not int) { - if (!(prop is Int32)) - { - throw new InvalidParamException(); - } - Int32 numFastBytes = (Int32)prop; - if (numFastBytes < 5 || numFastBytes > Base.K_MATCH_MAX_LEN) - { - throw new InvalidParamException(); - } - _numFastBytes = (UInt32)numFastBytes; - break; - } - case CoderPropId.Algorithm: - { - /* - if (!(prop is Int32)) - throw new InvalidParamException(); - Int32 maximize = (Int32)prop; - _fastMode = (maximize == 0); - _maxMode = (maximize >= 2); - */ - break; - } - case CoderPropId.MatchFinder: - { - if (!(prop is String)) - { - throw new InvalidParamException(); - } - EMatchFinderType matchFinderIndexPrev = _matchFinderType; - int m = FindMatchFinder(((string)prop)); - if (m < 0) - { - throw new InvalidParamException(); - } - _matchFinderType = (EMatchFinderType)m; - if (_matchFinder != null && matchFinderIndexPrev != _matchFinderType) - { - _dictionarySizePrev = 0xFFFFFFFF; - _matchFinder = null; - } - break; - } - case CoderPropId.DictionarySize: - { - const int kDicLogSizeMaxCompress = 30; - if (!(prop is Int32)) - { - throw new InvalidParamException(); - } - ; - Int32 dictionarySize = (Int32)prop; - if ( - dictionarySize < (UInt32)(1 << Base.K_DIC_LOG_SIZE_MIN) - || dictionarySize > (UInt32)(1 << kDicLogSizeMaxCompress) - ) - { - throw new InvalidParamException(); - } - _dictionarySize = (UInt32)dictionarySize; - int dicLogSize; - for ( - dicLogSize = 0; - dicLogSize < (UInt32)kDicLogSizeMaxCompress; - dicLogSize++ - ) - { - if (dictionarySize <= ((UInt32)(1) << dicLogSize)) - { - break; - } - } - _distTableSize = (UInt32)dicLogSize * 2; - break; - } - case CoderPropId.PosStateBits: - { - if (!(prop is Int32)) - { - throw new InvalidParamException(); - } - Int32 v = (Int32)prop; - if (v < 0 || v > (UInt32)Base.K_NUM_POS_STATES_BITS_ENCODING_MAX) - { - throw new InvalidParamException(); - } - _posStateBits = v; - _posStateMask = (((UInt32)1) << _posStateBits) - 1; - break; - } - case CoderPropId.LitPosBits: - { - if (!(prop is Int32)) - { - throw new InvalidParamException(); - } - Int32 v = (Int32)prop; - if (v < 0 || v > Base.K_NUM_LIT_POS_STATES_BITS_ENCODING_MAX) - { - throw new InvalidParamException(); - } - _numLiteralPosStateBits = v; - break; - } - case CoderPropId.LitContextBits: - { - if (!(prop is Int32)) - { - throw new InvalidParamException(); - } - Int32 v = (Int32)prop; - if (v < 0 || v > Base.K_NUM_LIT_CONTEXT_BITS_MAX) - { - throw new InvalidParamException(); - } - ; - _numLiteralContextBits = v; - break; - } - case CoderPropId.EndMarker: - { - if (!(prop is Boolean)) - { - throw new InvalidParamException(); - } - SetWriteEndMarkerMode((Boolean)prop); - break; - } - default: throw new InvalidParamException(); + } + var numFastBytes = (int)prop; + if (numFastBytes < 5 || numFastBytes > Base.K_MATCH_MAX_LEN) + { + throw new InvalidParamException(); + } + _numFastBytes = (uint)numFastBytes; + break; } + case CoderPropId.Algorithm: + { + /* + if (!(prop is Int32)) + throw new InvalidParamException(); + Int32 maximize = (Int32)prop; + _fastMode = (maximize == 0); + _maxMode = (maximize >= 2); + */ + break; + } + case CoderPropId.MatchFinder: + { + if (prop is not string) + { + throw new InvalidParamException(); + } + var matchFinderIndexPrev = _matchFinderType; + var m = FindMatchFinder(((string)prop)); + if (m < 0) + { + throw new InvalidParamException(); + } + _matchFinderType = (EMatchFinderType)m; + if (_matchFinder != null && matchFinderIndexPrev != _matchFinderType) + { + _dictionarySizePrev = 0xFFFFFFFF; + _matchFinder = null; + } + break; + } + case CoderPropId.DictionarySize: + { + const int kDicLogSizeMaxCompress = 30; + if (prop is not int) + { + throw new InvalidParamException(); + } + ; + var dictionarySize = (int)prop; + if ( + dictionarySize < (uint)(1 << Base.K_DIC_LOG_SIZE_MIN) + || dictionarySize > (uint)(1 << kDicLogSizeMaxCompress) + ) + { + throw new InvalidParamException(); + } + _dictionarySize = (uint)dictionarySize; + int dicLogSize; + for ( + dicLogSize = 0; + dicLogSize < (uint)kDicLogSizeMaxCompress; + dicLogSize++ + ) + { + if (dictionarySize <= ((uint)(1) << dicLogSize)) + { + break; + } + } + _distTableSize = (uint)dicLogSize * 2; + break; + } + case CoderPropId.PosStateBits: + { + if (prop is not int) + { + throw new InvalidParamException(); + } + var v = (int)prop; + if (v < 0 || v > (uint)Base.K_NUM_POS_STATES_BITS_ENCODING_MAX) + { + throw new InvalidParamException(); + } + _posStateBits = v; + _posStateMask = (((uint)1) << _posStateBits) - 1; + break; + } + case CoderPropId.LitPosBits: + { + if (prop is not int) + { + throw new InvalidParamException(); + } + var v = (int)prop; + if (v < 0 || v > Base.K_NUM_LIT_POS_STATES_BITS_ENCODING_MAX) + { + throw new InvalidParamException(); + } + _numLiteralPosStateBits = v; + break; + } + case CoderPropId.LitContextBits: + { + if (prop is not int) + { + throw new InvalidParamException(); + } + var v = (int)prop; + if (v < 0 || v > Base.K_NUM_LIT_CONTEXT_BITS_MAX) + { + throw new InvalidParamException(); + } + ; + _numLiteralContextBits = v; + break; + } + case CoderPropId.EndMarker: + { + if (prop is not bool) + { + throw new InvalidParamException(); + } + SetWriteEndMarkerMode((bool)prop); + break; + } + default: + throw new InvalidParamException(); } } - - private uint _trainSize; - - public void SetTrainSize(uint trainSize) - { - _trainSize = trainSize; - } + } + + private uint _trainSize; + + public void SetTrainSize(uint trainSize) + { + _trainSize = trainSize; } } diff --git a/src/SharpCompress/Compressors/LZMA/LzmaEncoderProperties.cs b/src/SharpCompress/Compressors/LZMA/LzmaEncoderProperties.cs index 395b2492..17c43ed6 100644 --- a/src/SharpCompress/Compressors/LZMA/LzmaEncoderProperties.cs +++ b/src/SharpCompress/Compressors/LZMA/LzmaEncoderProperties.cs @@ -1,46 +1,45 @@ -namespace SharpCompress.Compressors.LZMA +namespace SharpCompress.Compressors.LZMA; + +public class LzmaEncoderProperties { - public class LzmaEncoderProperties + internal CoderPropId[] _propIDs; + internal object[] _properties; + + public LzmaEncoderProperties() : this(false) { } + + public LzmaEncoderProperties(bool eos) : this(eos, 1 << 20) { } + + public LzmaEncoderProperties(bool eos, int dictionary) : this(eos, dictionary, 32) { } + + public LzmaEncoderProperties(bool eos, int dictionary, int numFastBytes) { - internal CoderPropId[] _propIDs; - internal object[] _properties; + var posStateBits = 2; + var litContextBits = 3; + var litPosBits = 0; + var algorithm = 2; + var mf = "bt4"; - public LzmaEncoderProperties() : this(false) { } - - public LzmaEncoderProperties(bool eos) : this(eos, 1 << 20) { } - - public LzmaEncoderProperties(bool eos, int dictionary) : this(eos, dictionary, 32) { } - - public LzmaEncoderProperties(bool eos, int dictionary, int numFastBytes) + _propIDs = new[] { - int posStateBits = 2; - int litContextBits = 3; - int litPosBits = 0; - int algorithm = 2; - string mf = "bt4"; - - _propIDs = new[] - { - CoderPropId.DictionarySize, - CoderPropId.PosStateBits, - CoderPropId.LitContextBits, - CoderPropId.LitPosBits, - CoderPropId.Algorithm, - CoderPropId.NumFastBytes, - CoderPropId.MatchFinder, - CoderPropId.EndMarker - }; - _properties = new object[] - { - dictionary, - posStateBits, - litContextBits, - litPosBits, - algorithm, - numFastBytes, - mf, - eos - }; - } + CoderPropId.DictionarySize, + CoderPropId.PosStateBits, + CoderPropId.LitContextBits, + CoderPropId.LitPosBits, + CoderPropId.Algorithm, + CoderPropId.NumFastBytes, + CoderPropId.MatchFinder, + CoderPropId.EndMarker + }; + _properties = new object[] + { + dictionary, + posStateBits, + litContextBits, + litPosBits, + algorithm, + numFastBytes, + mf, + eos + }; } } diff --git a/src/SharpCompress/Compressors/LZMA/LzmaStream.cs b/src/SharpCompress/Compressors/LZMA/LzmaStream.cs index 80238cdf..108381e5 100644 --- a/src/SharpCompress/Compressors/LZMA/LzmaStream.cs +++ b/src/SharpCompress/Compressors/LZMA/LzmaStream.cs @@ -1,329 +1,328 @@ -#nullable disable +#nullable disable using System; using System.Buffers.Binary; using System.IO; using SharpCompress.Compressors.LZMA.LZ; -namespace SharpCompress.Compressors.LZMA +namespace SharpCompress.Compressors.LZMA; + +public class LzmaStream : Stream { - public class LzmaStream : Stream + private readonly Stream _inputStream; + private readonly long _inputSize; + private readonly long _outputSize; + + private readonly int _dictionarySize; + private readonly OutWindow _outWindow = new OutWindow(); + private readonly RangeCoder.Decoder _rangeDecoder = new RangeCoder.Decoder(); + private Decoder _decoder; + + private long _position; + private bool _endReached; + private long _availableBytes; + private long _rangeDecoderLimit; + private long _inputPosition; + + // LZMA2 + private readonly bool _isLzma2; + private bool _uncompressedChunk; + private bool _needDictReset = true; + private bool _needProps = true; + + private readonly Encoder _encoder; + private bool _isDisposed; + + public LzmaStream(byte[] properties, Stream inputStream) + : this(properties, inputStream, -1, -1, null, properties.Length < 5) { } + + public LzmaStream(byte[] properties, Stream inputStream, long inputSize) + : this(properties, inputStream, inputSize, -1, null, properties.Length < 5) { } + + public LzmaStream(byte[] properties, Stream inputStream, long inputSize, long outputSize) + : this(properties, inputStream, inputSize, outputSize, null, properties.Length < 5) { } + + public LzmaStream( + byte[] properties, + Stream inputStream, + long inputSize, + long outputSize, + Stream presetDictionary, + bool isLzma2 + ) { - private readonly Stream _inputStream; - private readonly long _inputSize; - private readonly long _outputSize; + _inputStream = inputStream; + _inputSize = inputSize; + _outputSize = outputSize; + _isLzma2 = isLzma2; - private readonly int _dictionarySize; - private readonly OutWindow _outWindow = new OutWindow(); - private readonly RangeCoder.Decoder _rangeDecoder = new RangeCoder.Decoder(); - private Decoder _decoder; - - private long _position; - private bool _endReached; - private long _availableBytes; - private long _rangeDecoderLimit; - private long _inputPosition; - - // LZMA2 - private readonly bool _isLzma2; - private bool _uncompressedChunk; - private bool _needDictReset = true; - private bool _needProps = true; - - private readonly Encoder _encoder; - private bool _isDisposed; - - public LzmaStream(byte[] properties, Stream inputStream) - : this(properties, inputStream, -1, -1, null, properties.Length < 5) { } - - public LzmaStream(byte[] properties, Stream inputStream, long inputSize) - : this(properties, inputStream, inputSize, -1, null, properties.Length < 5) { } - - public LzmaStream(byte[] properties, Stream inputStream, long inputSize, long outputSize) - : this(properties, inputStream, inputSize, outputSize, null, properties.Length < 5) { } - - public LzmaStream( - byte[] properties, - Stream inputStream, - long inputSize, - long outputSize, - Stream presetDictionary, - bool isLzma2 - ) + if (!isLzma2) { - _inputStream = inputStream; - _inputSize = inputSize; - _outputSize = outputSize; - _isLzma2 = isLzma2; - - if (!isLzma2) - { - _dictionarySize = BinaryPrimitives.ReadInt32LittleEndian(properties.AsSpan(1)); - _outWindow.Create(_dictionarySize); - if (presetDictionary != null) - { - _outWindow.Train(presetDictionary); - } - - _rangeDecoder.Init(inputStream); - - _decoder = new Decoder(); - _decoder.SetDecoderProperties(properties); - Properties = properties; - - _availableBytes = outputSize < 0 ? long.MaxValue : outputSize; - _rangeDecoderLimit = inputSize; - } - else - { - _dictionarySize = 2 | (properties[0] & 1); - _dictionarySize <<= (properties[0] >> 1) + 11; - - _outWindow.Create(_dictionarySize); - if (presetDictionary != null) - { - _outWindow.Train(presetDictionary); - _needDictReset = false; - } - - Properties = new byte[1]; - _availableBytes = 0; - } - } - - public LzmaStream(LzmaEncoderProperties properties, bool isLzma2, Stream outputStream) - : this(properties, isLzma2, null, outputStream) { } - - public LzmaStream( - LzmaEncoderProperties properties, - bool isLzma2, - Stream presetDictionary, - Stream outputStream - ) - { - _isLzma2 = isLzma2; - _availableBytes = 0; - _endReached = true; - - if (isLzma2) - { - throw new NotImplementedException(); - } - - _encoder = new Encoder(); - _encoder.SetCoderProperties(properties._propIDs, properties._properties); - byte[] prop = new byte[5]; - _encoder.WriteCoderProperties(prop); - Properties = prop; - - _encoder.SetStreams(null, outputStream, -1, -1); + _dictionarySize = BinaryPrimitives.ReadInt32LittleEndian(properties.AsSpan(1)); + _outWindow.Create(_dictionarySize); if (presetDictionary != null) { - _encoder.Train(presetDictionary); + _outWindow.Train(presetDictionary); } + + _rangeDecoder.Init(inputStream); + + _decoder = new Decoder(); + _decoder.SetDecoderProperties(properties); + Properties = properties; + + _availableBytes = outputSize < 0 ? long.MaxValue : outputSize; + _rangeDecoderLimit = inputSize; } - - public override bool CanRead => _encoder == null; - - public override bool CanSeek => false; - - public override bool CanWrite => _encoder != null; - - public override void Flush() { } - - protected override void Dispose(bool disposing) + else { - if (_isDisposed) + _dictionarySize = 2 | (properties[0] & 1); + _dictionarySize <<= (properties[0] >> 1) + 11; + + _outWindow.Create(_dictionarySize); + if (presetDictionary != null) { - return; - } - _isDisposed = true; - if (disposing) - { - if (_encoder != null) - { - _position = _encoder.Code(null, true); - } - _inputStream?.Dispose(); - } - base.Dispose(disposing); - } - - public override long Length => _position + _availableBytes; - - public override long Position - { - get => _position; - set => throw new NotSupportedException(); - } - - public override int Read(byte[] buffer, int offset, int count) - { - if (_endReached) - { - return 0; - } - - int total = 0; - while (total < count) - { - if (_availableBytes == 0) - { - if (_isLzma2) - { - DecodeChunkHeader(); - } - else - { - _endReached = true; - } - if (_endReached) - { - break; - } - } - - int toProcess = count - total; - if (toProcess > _availableBytes) - { - toProcess = (int)_availableBytes; - } - - _outWindow.SetLimit(toProcess); - if (_uncompressedChunk) - { - _inputPosition += _outWindow.CopyStream(_inputStream, toProcess); - } - else if ( - _decoder.Code(_dictionarySize, _outWindow, _rangeDecoder) && _outputSize < 0 - ) - { - _availableBytes = _outWindow.AvailableBytes; - } - - int read = _outWindow.Read(buffer, offset, toProcess); - total += read; - offset += read; - _position += read; - _availableBytes -= read; - - if (_availableBytes == 0 && !_uncompressedChunk) - { - _rangeDecoder.ReleaseStream(); - if ( - !_rangeDecoder.IsFinished - || (_rangeDecoderLimit >= 0 && _rangeDecoder._total != _rangeDecoderLimit) - ) - { - throw new DataErrorException(); - } - _inputPosition += _rangeDecoder._total; - if (_outWindow.HasPending) - { - throw new DataErrorException(); - } - } - } - - if (_endReached) - { - if (_inputSize >= 0 && _inputPosition != _inputSize) - { - throw new DataErrorException(); - } - if (_outputSize >= 0 && _position != _outputSize) - { - throw new DataErrorException(); - } - } - - return total; - } - - private void DecodeChunkHeader() - { - int control = _inputStream.ReadByte(); - _inputPosition++; - - if (control == 0x00) - { - _endReached = true; - return; - } - - if (control >= 0xE0 || control == 0x01) - { - _needProps = true; + _outWindow.Train(presetDictionary); _needDictReset = false; - _outWindow.Reset(); - } - else if (_needDictReset) - { - throw new DataErrorException(); } - if (control >= 0x80) - { - _uncompressedChunk = false; - - _availableBytes = (control & 0x1F) << 16; - _availableBytes += (_inputStream.ReadByte() << 8) + _inputStream.ReadByte() + 1; - _inputPosition += 2; - - _rangeDecoderLimit = (_inputStream.ReadByte() << 8) + _inputStream.ReadByte() + 1; - _inputPosition += 2; - - if (control >= 0xC0) - { - _needProps = false; - Properties[0] = (byte)_inputStream.ReadByte(); - _inputPosition++; - - _decoder = new Decoder(); - _decoder.SetDecoderProperties(Properties); - } - else if (_needProps) - { - throw new DataErrorException(); - } - else if (control >= 0xA0) - { - _decoder = new Decoder(); - _decoder.SetDecoderProperties(Properties); - } - - _rangeDecoder.Init(_inputStream); - } - else if (control > 0x02) - { - throw new DataErrorException(); - } - else - { - _uncompressedChunk = true; - _availableBytes = (_inputStream.ReadByte() << 8) + _inputStream.ReadByte() + 1; - _inputPosition += 2; - } + Properties = new byte[1]; + _availableBytes = 0; } + } - public override long Seek(long offset, SeekOrigin origin) + public LzmaStream(LzmaEncoderProperties properties, bool isLzma2, Stream outputStream) + : this(properties, isLzma2, null, outputStream) { } + + public LzmaStream( + LzmaEncoderProperties properties, + bool isLzma2, + Stream presetDictionary, + Stream outputStream + ) + { + _isLzma2 = isLzma2; + _availableBytes = 0; + _endReached = true; + + if (isLzma2) { - throw new NotSupportedException(); + throw new NotImplementedException(); } - public override void SetLength(long value) + _encoder = new Encoder(); + _encoder.SetCoderProperties(properties._propIDs, properties._properties); + var prop = new byte[5]; + _encoder.WriteCoderProperties(prop); + Properties = prop; + + _encoder.SetStreams(null, outputStream, -1, -1); + if (presetDictionary != null) { - throw new NotSupportedException(); + _encoder.Train(presetDictionary); } + } - public override void Write(byte[] buffer, int offset, int count) + public override bool CanRead => _encoder == null; + + public override bool CanSeek => false; + + public override bool CanWrite => _encoder != null; + + public override void Flush() { } + + protected override void Dispose(bool disposing) + { + if (_isDisposed) + { + return; + } + _isDisposed = true; + if (disposing) { if (_encoder != null) { - _position = _encoder.Code(new MemoryStream(buffer, offset, count), false); + _position = _encoder.Code(null, true); + } + _inputStream?.Dispose(); + } + base.Dispose(disposing); + } + + public override long Length => _position + _availableBytes; + + public override long Position + { + get => _position; + set => throw new NotSupportedException(); + } + + public override int Read(byte[] buffer, int offset, int count) + { + if (_endReached) + { + return 0; + } + + var total = 0; + while (total < count) + { + if (_availableBytes == 0) + { + if (_isLzma2) + { + DecodeChunkHeader(); + } + else + { + _endReached = true; + } + if (_endReached) + { + break; + } + } + + var toProcess = count - total; + if (toProcess > _availableBytes) + { + toProcess = (int)_availableBytes; + } + + _outWindow.SetLimit(toProcess); + if (_uncompressedChunk) + { + _inputPosition += _outWindow.CopyStream(_inputStream, toProcess); + } + else if ( + _decoder.Code(_dictionarySize, _outWindow, _rangeDecoder) && _outputSize < 0 + ) + { + _availableBytes = _outWindow.AvailableBytes; + } + + var read = _outWindow.Read(buffer, offset, toProcess); + total += read; + offset += read; + _position += read; + _availableBytes -= read; + + if (_availableBytes == 0 && !_uncompressedChunk) + { + _rangeDecoder.ReleaseStream(); + if ( + !_rangeDecoder.IsFinished + || (_rangeDecoderLimit >= 0 && _rangeDecoder._total != _rangeDecoderLimit) + ) + { + throw new DataErrorException(); + } + _inputPosition += _rangeDecoder._total; + if (_outWindow.HasPending) + { + throw new DataErrorException(); + } } } - public byte[] Properties { get; } = new byte[5]; + if (_endReached) + { + if (_inputSize >= 0 && _inputPosition != _inputSize) + { + throw new DataErrorException(); + } + if (_outputSize >= 0 && _position != _outputSize) + { + throw new DataErrorException(); + } + } + + return total; } + + private void DecodeChunkHeader() + { + var control = _inputStream.ReadByte(); + _inputPosition++; + + if (control == 0x00) + { + _endReached = true; + return; + } + + if (control >= 0xE0 || control == 0x01) + { + _needProps = true; + _needDictReset = false; + _outWindow.Reset(); + } + else if (_needDictReset) + { + throw new DataErrorException(); + } + + if (control >= 0x80) + { + _uncompressedChunk = false; + + _availableBytes = (control & 0x1F) << 16; + _availableBytes += (_inputStream.ReadByte() << 8) + _inputStream.ReadByte() + 1; + _inputPosition += 2; + + _rangeDecoderLimit = (_inputStream.ReadByte() << 8) + _inputStream.ReadByte() + 1; + _inputPosition += 2; + + if (control >= 0xC0) + { + _needProps = false; + Properties[0] = (byte)_inputStream.ReadByte(); + _inputPosition++; + + _decoder = new Decoder(); + _decoder.SetDecoderProperties(Properties); + } + else if (_needProps) + { + throw new DataErrorException(); + } + else if (control >= 0xA0) + { + _decoder = new Decoder(); + _decoder.SetDecoderProperties(Properties); + } + + _rangeDecoder.Init(_inputStream); + } + else if (control > 0x02) + { + throw new DataErrorException(); + } + else + { + _uncompressedChunk = true; + _availableBytes = (_inputStream.ReadByte() << 8) + _inputStream.ReadByte() + 1; + _inputPosition += 2; + } + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } + + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + public override void Write(byte[] buffer, int offset, int count) + { + if (_encoder != null) + { + _position = _encoder.Code(new MemoryStream(buffer, offset, count), false); + } + } + + public byte[] Properties { get; } = new byte[5]; } diff --git a/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoder.cs b/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoder.cs index 36ba6842..3694286c 100644 --- a/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoder.cs +++ b/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoder.cs @@ -1,253 +1,251 @@ #nullable disable -using System; using System.IO; -namespace SharpCompress.Compressors.LZMA.RangeCoder +namespace SharpCompress.Compressors.LZMA.RangeCoder; + +internal class Encoder { - internal class Encoder + public const uint K_TOP_VALUE = (1 << 24); + + private Stream _stream; + + public ulong _low; + public uint _range; + private uint _cacheSize; + private byte _cache; + + //long StartPosition; + + public void SetStream(Stream stream) { - public const uint K_TOP_VALUE = (1 << 24); + _stream = stream; + } - private Stream _stream; + public void ReleaseStream() + { + _stream = null; + } - public UInt64 _low; - public uint _range; - private uint _cacheSize; - private byte _cache; + public void Init() + { + //StartPosition = Stream.Position; - //long StartPosition; + _low = 0; + _range = 0xFFFFFFFF; + _cacheSize = 1; + _cache = 0; + } - public void SetStream(Stream stream) + public void FlushData() + { + for (var i = 0; i < 5; i++) { - _stream = stream; - } - - public void ReleaseStream() - { - _stream = null; - } - - public void Init() - { - //StartPosition = Stream.Position; - - _low = 0; - _range = 0xFFFFFFFF; - _cacheSize = 1; - _cache = 0; - } - - public void FlushData() - { - for (int i = 0; i < 5; i++) - { - ShiftLow(); - } - } - - public void FlushStream() - { - _stream.Flush(); - } - - public void CloseStream() - { - _stream.Dispose(); - } - - public void Encode(uint start, uint size, uint total) - { - _low += start * (_range /= total); - _range *= size; - while (_range < K_TOP_VALUE) - { - _range <<= 8; - ShiftLow(); - } - } - - public void ShiftLow() - { - if ((uint)_low < 0xFF000000 || (uint)(_low >> 32) == 1) - { - byte temp = _cache; - do - { - _stream.WriteByte((byte)(temp + (_low >> 32))); - temp = 0xFF; - } while (--_cacheSize != 0); - _cache = (byte)(((uint)_low) >> 24); - } - _cacheSize++; - _low = ((uint)_low) << 8; - } - - public void EncodeDirectBits(uint v, int numTotalBits) - { - for (int i = numTotalBits - 1; i >= 0; i--) - { - _range >>= 1; - if (((v >> i) & 1) == 1) - { - _low += _range; - } - if (_range < K_TOP_VALUE) - { - _range <<= 8; - ShiftLow(); - } - } - } - - public void EncodeBit(uint size0, int numTotalBits, uint symbol) - { - uint newBound = (_range >> numTotalBits) * size0; - if (symbol == 0) - { - _range = newBound; - } - else - { - _low += newBound; - _range -= newBound; - } - while (_range < K_TOP_VALUE) - { - _range <<= 8; - ShiftLow(); - } - } - - public long GetProcessedSizeAdd() - { - return -1; - - //return _cacheSize + Stream.Position - StartPosition + 4; - // (long)Stream.GetProcessedSize(); + ShiftLow(); } } - internal class Decoder + public void FlushStream() { - public const uint K_TOP_VALUE = (1 << 24); - public uint _range; - public uint _code; + _stream.Flush(); + } - // public Buffer.InBuffer Stream = new Buffer.InBuffer(1 << 16); - public Stream _stream; - public long _total; + public void CloseStream() + { + _stream.Dispose(); + } - public void Init(Stream stream) + public void Encode(uint start, uint size, uint total) + { + _low += start * (_range /= total); + _range *= size; + while (_range < K_TOP_VALUE) { - // Stream.Init(stream); - _stream = stream; + _range <<= 8; + ShiftLow(); + } + } - _code = 0; - _range = 0xFFFFFFFF; - for (int i = 0; i < 5; i++) + public void ShiftLow() + { + if ((uint)_low < 0xFF000000 || (uint)(_low >> 32) == 1) + { + var temp = _cache; + do { - _code = (_code << 8) | (byte)_stream.ReadByte(); - } - _total = 5; + _stream.WriteByte((byte)(temp + (_low >> 32))); + temp = 0xFF; + } while (--_cacheSize != 0); + _cache = (byte)(((uint)_low) >> 24); } + _cacheSize++; + _low = ((uint)_low) << 8; + } - public void ReleaseStream() + public void EncodeDirectBits(uint v, int numTotalBits) + { + for (var i = numTotalBits - 1; i >= 0; i--) { - // Stream.ReleaseStream(); - _stream = null; - } - - public void CloseStream() - { - _stream.Dispose(); - } - - public void Normalize() - { - while (_range < K_TOP_VALUE) + _range >>= 1; + if (((v >> i) & 1) == 1) { - _code = (_code << 8) | (byte)_stream.ReadByte(); - _range <<= 8; - _total++; + _low += _range; } - } - - public void Normalize2() - { if (_range < K_TOP_VALUE) { - _code = (_code << 8) | (byte)_stream.ReadByte(); _range <<= 8; + ShiftLow(); + } + } + } + + public void EncodeBit(uint size0, int numTotalBits, uint symbol) + { + var newBound = (_range >> numTotalBits) * size0; + if (symbol == 0) + { + _range = newBound; + } + else + { + _low += newBound; + _range -= newBound; + } + while (_range < K_TOP_VALUE) + { + _range <<= 8; + ShiftLow(); + } + } + + public long GetProcessedSizeAdd() + { + return -1; + + //return _cacheSize + Stream.Position - StartPosition + 4; + // (long)Stream.GetProcessedSize(); + } +} + +internal class Decoder +{ + public const uint K_TOP_VALUE = (1 << 24); + public uint _range; + public uint _code; + + // public Buffer.InBuffer Stream = new Buffer.InBuffer(1 << 16); + public Stream _stream; + public long _total; + + public void Init(Stream stream) + { + // Stream.Init(stream); + _stream = stream; + + _code = 0; + _range = 0xFFFFFFFF; + for (var i = 0; i < 5; i++) + { + _code = (_code << 8) | (byte)_stream.ReadByte(); + } + _total = 5; + } + + public void ReleaseStream() + { + // Stream.ReleaseStream(); + _stream = null; + } + + public void CloseStream() + { + _stream.Dispose(); + } + + public void Normalize() + { + while (_range < K_TOP_VALUE) + { + _code = (_code << 8) | (byte)_stream.ReadByte(); + _range <<= 8; + _total++; + } + } + + public void Normalize2() + { + if (_range < K_TOP_VALUE) + { + _code = (_code << 8) | (byte)_stream.ReadByte(); + _range <<= 8; + _total++; + } + } + + public uint GetThreshold(uint total) + { + return _code / (_range /= total); + } + + public void Decode(uint start, uint size) + { + _code -= start * _range; + _range *= size; + Normalize(); + } + + public uint DecodeDirectBits(int numTotalBits) + { + var range = _range; + var code = _code; + uint result = 0; + for (var i = numTotalBits; i > 0; i--) + { + range >>= 1; + /* + result <<= 1; + if (code >= range) + { + code -= range; + result |= 1; + } + */ + var t = (code - range) >> 31; + code -= range & (t - 1); + result = (result << 1) | (1 - t); + + if (range < K_TOP_VALUE) + { + code = (code << 8) | (byte)_stream.ReadByte(); + range <<= 8; _total++; } } - - public uint GetThreshold(uint total) - { - return _code / (_range /= total); - } - - public void Decode(uint start, uint size) - { - _code -= start * _range; - _range *= size; - Normalize(); - } - - public uint DecodeDirectBits(int numTotalBits) - { - uint range = _range; - uint code = _code; - uint result = 0; - for (int i = numTotalBits; i > 0; i--) - { - range >>= 1; - /* - result <<= 1; - if (code >= range) - { - code -= range; - result |= 1; - } - */ - uint t = (code - range) >> 31; - code -= range & (t - 1); - result = (result << 1) | (1 - t); - - if (range < K_TOP_VALUE) - { - code = (code << 8) | (byte)_stream.ReadByte(); - range <<= 8; - _total++; - } - } - _range = range; - _code = code; - return result; - } - - public uint DecodeBit(uint size0, int numTotalBits) - { - uint newBound = (_range >> numTotalBits) * size0; - uint symbol; - if (_code < newBound) - { - symbol = 0; - _range = newBound; - } - else - { - symbol = 1; - _code -= newBound; - _range -= newBound; - } - Normalize(); - return symbol; - } - - public bool IsFinished => _code == 0; - - // ulong GetProcessedSize() {return Stream.GetProcessedSize(); } + _range = range; + _code = code; + return result; } + + public uint DecodeBit(uint size0, int numTotalBits) + { + var newBound = (_range >> numTotalBits) * size0; + uint symbol; + if (_code < newBound) + { + symbol = 0; + _range = newBound; + } + else + { + symbol = 1; + _code -= newBound; + _range -= newBound; + } + Normalize(); + return symbol; + } + + public bool IsFinished => _code == 0; + + // ulong GetProcessedSize() {return Stream.GetProcessedSize(); } } diff --git a/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoderBit.cs b/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoderBit.cs index 80b30bd8..15827a54 100644 --- a/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoderBit.cs +++ b/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoderBit.cs @@ -1,140 +1,126 @@ -using System; +namespace SharpCompress.Compressors.LZMA.RangeCoder; -namespace SharpCompress.Compressors.LZMA.RangeCoder +internal struct BitEncoder { - internal struct BitEncoder + public const int K_NUM_BIT_MODEL_TOTAL_BITS = 11; + public const uint K_BIT_MODEL_TOTAL = (1 << K_NUM_BIT_MODEL_TOTAL_BITS); + private const int K_NUM_MOVE_BITS = 5; + private const int K_NUM_MOVE_REDUCING_BITS = 2; + public const int K_NUM_BIT_PRICE_SHIFT_BITS = 6; + + private uint _prob; + + public void Init() { - public const int K_NUM_BIT_MODEL_TOTAL_BITS = 11; - public const uint K_BIT_MODEL_TOTAL = (1 << K_NUM_BIT_MODEL_TOTAL_BITS); - private const int K_NUM_MOVE_BITS = 5; - private const int K_NUM_MOVE_REDUCING_BITS = 2; - public const int K_NUM_BIT_PRICE_SHIFT_BITS = 6; + _prob = K_BIT_MODEL_TOTAL >> 1; + } - private uint _prob; - - public void Init() + public void UpdateModel(uint symbol) + { + if (symbol == 0) { - _prob = K_BIT_MODEL_TOTAL >> 1; + _prob += (K_BIT_MODEL_TOTAL - _prob) >> K_NUM_MOVE_BITS; } - - public void UpdateModel(uint symbol) + else { - if (symbol == 0) - { - _prob += (K_BIT_MODEL_TOTAL - _prob) >> K_NUM_MOVE_BITS; - } - else - { - _prob -= (_prob) >> K_NUM_MOVE_BITS; - } - } - - public void Encode(Encoder encoder, uint symbol) - { - // encoder.EncodeBit(Prob, kNumBitModelTotalBits, symbol); - // UpdateModel(symbol); - uint newBound = (encoder._range >> K_NUM_BIT_MODEL_TOTAL_BITS) * _prob; - if (symbol == 0) - { - encoder._range = newBound; - _prob += (K_BIT_MODEL_TOTAL - _prob) >> K_NUM_MOVE_BITS; - } - else - { - encoder._low += newBound; - encoder._range -= newBound; - _prob -= (_prob) >> K_NUM_MOVE_BITS; - } - if (encoder._range < Encoder.K_TOP_VALUE) - { - encoder._range <<= 8; - encoder.ShiftLow(); - } - } - - private static readonly UInt32[] PROB_PRICES = new UInt32[ - K_BIT_MODEL_TOTAL >> K_NUM_MOVE_REDUCING_BITS - ]; - - static BitEncoder() - { - const int kNumBits = (K_NUM_BIT_MODEL_TOTAL_BITS - K_NUM_MOVE_REDUCING_BITS); - for (int i = kNumBits - 1; i >= 0; i--) - { - UInt32 start = (UInt32)1 << (kNumBits - i - 1); - UInt32 end = (UInt32)1 << (kNumBits - i); - for (UInt32 j = start; j < end; j++) - { - PROB_PRICES[j] = - ((UInt32)i << K_NUM_BIT_PRICE_SHIFT_BITS) - + (((end - j) << K_NUM_BIT_PRICE_SHIFT_BITS) >> (kNumBits - i - 1)); - } - } - } - - public uint GetPrice(uint symbol) - { - return PROB_PRICES[ - (((_prob - symbol) ^ ((-(int)symbol))) & (K_BIT_MODEL_TOTAL - 1)) - >> K_NUM_MOVE_REDUCING_BITS - ]; - } - - public uint GetPrice0() - { - return PROB_PRICES[_prob >> K_NUM_MOVE_REDUCING_BITS]; - } - - public uint GetPrice1() - { - return PROB_PRICES[(K_BIT_MODEL_TOTAL - _prob) >> K_NUM_MOVE_REDUCING_BITS]; + _prob -= (_prob) >> K_NUM_MOVE_BITS; } } - internal struct BitDecoder + public void Encode(Encoder encoder, uint symbol) { - public const int K_NUM_BIT_MODEL_TOTAL_BITS = 11; - public const uint K_BIT_MODEL_TOTAL = (1 << K_NUM_BIT_MODEL_TOTAL_BITS); - private const int K_NUM_MOVE_BITS = 5; - - private uint _prob; - - public void UpdateModel(int numMoveBits, uint symbol) + // encoder.EncodeBit(Prob, kNumBitModelTotalBits, symbol); + // UpdateModel(symbol); + var newBound = (encoder._range >> K_NUM_BIT_MODEL_TOTAL_BITS) * _prob; + if (symbol == 0) { - if (symbol == 0) - { - _prob += (K_BIT_MODEL_TOTAL - _prob) >> numMoveBits; - } - else - { - _prob -= (_prob) >> numMoveBits; - } + encoder._range = newBound; + _prob += (K_BIT_MODEL_TOTAL - _prob) >> K_NUM_MOVE_BITS; } - - public void Init() + else { - _prob = K_BIT_MODEL_TOTAL >> 1; - } - - public uint Decode(Decoder rangeDecoder) - { - uint newBound = (rangeDecoder._range >> K_NUM_BIT_MODEL_TOTAL_BITS) * _prob; - if (rangeDecoder._code < newBound) - { - rangeDecoder._range = newBound; - _prob += (K_BIT_MODEL_TOTAL - _prob) >> K_NUM_MOVE_BITS; - if (rangeDecoder._range < Decoder.K_TOP_VALUE) - { - rangeDecoder._code = - (rangeDecoder._code << 8) | (byte)rangeDecoder._stream.ReadByte(); - rangeDecoder._range <<= 8; - rangeDecoder._total++; - } - return 0; - } - rangeDecoder._range -= newBound; - rangeDecoder._code -= newBound; + encoder._low += newBound; + encoder._range -= newBound; _prob -= (_prob) >> K_NUM_MOVE_BITS; + } + if (encoder._range < Encoder.K_TOP_VALUE) + { + encoder._range <<= 8; + encoder.ShiftLow(); + } + } + + private static readonly uint[] PROB_PRICES = new uint[ + K_BIT_MODEL_TOTAL >> K_NUM_MOVE_REDUCING_BITS + ]; + + static BitEncoder() + { + const int kNumBits = (K_NUM_BIT_MODEL_TOTAL_BITS - K_NUM_MOVE_REDUCING_BITS); + for (var i = kNumBits - 1; i >= 0; i--) + { + var start = (uint)1 << (kNumBits - i - 1); + var end = (uint)1 << (kNumBits - i); + for (var j = start; j < end; j++) + { + PROB_PRICES[j] = + ((uint)i << K_NUM_BIT_PRICE_SHIFT_BITS) + + (((end - j) << K_NUM_BIT_PRICE_SHIFT_BITS) >> (kNumBits - i - 1)); + } + } + } + + public uint GetPrice(uint symbol) + { + return PROB_PRICES[ + (((_prob - symbol) ^ ((-(int)symbol))) & (K_BIT_MODEL_TOTAL - 1)) + >> K_NUM_MOVE_REDUCING_BITS + ]; + } + + public uint GetPrice0() + { + return PROB_PRICES[_prob >> K_NUM_MOVE_REDUCING_BITS]; + } + + public uint GetPrice1() + { + return PROB_PRICES[(K_BIT_MODEL_TOTAL - _prob) >> K_NUM_MOVE_REDUCING_BITS]; + } +} + +internal struct BitDecoder +{ + public const int K_NUM_BIT_MODEL_TOTAL_BITS = 11; + public const uint K_BIT_MODEL_TOTAL = (1 << K_NUM_BIT_MODEL_TOTAL_BITS); + private const int K_NUM_MOVE_BITS = 5; + + private uint _prob; + + public void UpdateModel(int numMoveBits, uint symbol) + { + if (symbol == 0) + { + _prob += (K_BIT_MODEL_TOTAL - _prob) >> numMoveBits; + } + else + { + _prob -= (_prob) >> numMoveBits; + } + } + + public void Init() + { + _prob = K_BIT_MODEL_TOTAL >> 1; + } + + public uint Decode(Decoder rangeDecoder) + { + var newBound = (rangeDecoder._range >> K_NUM_BIT_MODEL_TOTAL_BITS) * _prob; + if (rangeDecoder._code < newBound) + { + rangeDecoder._range = newBound; + _prob += (K_BIT_MODEL_TOTAL - _prob) >> K_NUM_MOVE_BITS; if (rangeDecoder._range < Decoder.K_TOP_VALUE) { rangeDecoder._code = @@ -142,7 +128,18 @@ namespace SharpCompress.Compressors.LZMA.RangeCoder rangeDecoder._range <<= 8; rangeDecoder._total++; } - return 1; + return 0; } + rangeDecoder._range -= newBound; + rangeDecoder._code -= newBound; + _prob -= (_prob) >> K_NUM_MOVE_BITS; + if (rangeDecoder._range < Decoder.K_TOP_VALUE) + { + rangeDecoder._code = + (rangeDecoder._code << 8) | (byte)rangeDecoder._stream.ReadByte(); + rangeDecoder._range <<= 8; + rangeDecoder._total++; + } + return 1; } } diff --git a/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoderBitTree.cs b/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoderBitTree.cs index a00a5135..cef8872c 100644 --- a/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoderBitTree.cs +++ b/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoderBitTree.cs @@ -1,176 +1,173 @@ -using System; +namespace SharpCompress.Compressors.LZMA.RangeCoder; -namespace SharpCompress.Compressors.LZMA.RangeCoder +internal readonly struct BitTreeEncoder { - internal struct BitTreeEncoder + private readonly BitEncoder[] _models; + private readonly int _numBitLevels; + + public BitTreeEncoder(int numBitLevels) { - private readonly BitEncoder[] _models; - private readonly int _numBitLevels; + _numBitLevels = numBitLevels; + _models = new BitEncoder[1 << numBitLevels]; + } - public BitTreeEncoder(int numBitLevels) + public void Init() + { + for (uint i = 1; i < (1 << _numBitLevels); i++) { - _numBitLevels = numBitLevels; - _models = new BitEncoder[1 << numBitLevels]; - } - - public void Init() - { - for (uint i = 1; i < (1 << _numBitLevels); i++) - { - _models[i].Init(); - } - } - - public void Encode(Encoder rangeEncoder, UInt32 symbol) - { - UInt32 m = 1; - for (int bitIndex = _numBitLevels; bitIndex > 0; ) - { - bitIndex--; - UInt32 bit = (symbol >> bitIndex) & 1; - _models[m].Encode(rangeEncoder, bit); - m = (m << 1) | bit; - } - } - - public void ReverseEncode(Encoder rangeEncoder, UInt32 symbol) - { - UInt32 m = 1; - for (UInt32 i = 0; i < _numBitLevels; i++) - { - UInt32 bit = symbol & 1; - _models[m].Encode(rangeEncoder, bit); - m = (m << 1) | bit; - symbol >>= 1; - } - } - - public UInt32 GetPrice(UInt32 symbol) - { - UInt32 price = 0; - UInt32 m = 1; - for (int bitIndex = _numBitLevels; bitIndex > 0; ) - { - bitIndex--; - UInt32 bit = (symbol >> bitIndex) & 1; - price += _models[m].GetPrice(bit); - m = (m << 1) + bit; - } - return price; - } - - public UInt32 ReverseGetPrice(UInt32 symbol) - { - UInt32 price = 0; - UInt32 m = 1; - for (int i = _numBitLevels; i > 0; i--) - { - UInt32 bit = symbol & 1; - symbol >>= 1; - price += _models[m].GetPrice(bit); - m = (m << 1) | bit; - } - return price; - } - - public static UInt32 ReverseGetPrice( - BitEncoder[] models, - UInt32 startIndex, - int numBitLevels, - UInt32 symbol - ) - { - UInt32 price = 0; - UInt32 m = 1; - for (int i = numBitLevels; i > 0; i--) - { - UInt32 bit = symbol & 1; - symbol >>= 1; - price += models[startIndex + m].GetPrice(bit); - m = (m << 1) | bit; - } - return price; - } - - public static void ReverseEncode( - BitEncoder[] models, - UInt32 startIndex, - Encoder rangeEncoder, - int numBitLevels, - UInt32 symbol - ) - { - UInt32 m = 1; - for (int i = 0; i < numBitLevels; i++) - { - UInt32 bit = symbol & 1; - models[startIndex + m].Encode(rangeEncoder, bit); - m = (m << 1) | bit; - symbol >>= 1; - } + _models[i].Init(); } } - internal struct BitTreeDecoder + public void Encode(Encoder rangeEncoder, uint symbol) { - private readonly BitDecoder[] _models; - private readonly int _numBitLevels; - - public BitTreeDecoder(int numBitLevels) + uint m = 1; + for (var bitIndex = _numBitLevels; bitIndex > 0;) { - _numBitLevels = numBitLevels; - _models = new BitDecoder[1 << numBitLevels]; + bitIndex--; + var bit = (symbol >> bitIndex) & 1; + _models[m].Encode(rangeEncoder, bit); + m = (m << 1) | bit; } + } - public void Init() + public void ReverseEncode(Encoder rangeEncoder, uint symbol) + { + uint m = 1; + for (uint i = 0; i < _numBitLevels; i++) { - for (uint i = 1; i < (1 << _numBitLevels); i++) - { - _models[i].Init(); - } + var bit = symbol & 1; + _models[m].Encode(rangeEncoder, bit); + m = (m << 1) | bit; + symbol >>= 1; } + } - public uint Decode(Decoder rangeDecoder) + public uint GetPrice(uint symbol) + { + uint price = 0; + uint m = 1; + for (var bitIndex = _numBitLevels; bitIndex > 0;) { - uint m = 1; - for (int bitIndex = _numBitLevels; bitIndex > 0; bitIndex--) - { - m = (m << 1) + _models[m].Decode(rangeDecoder); - } - return m - ((uint)1 << _numBitLevels); + bitIndex--; + var bit = (symbol >> bitIndex) & 1; + price += _models[m].GetPrice(bit); + m = (m << 1) + bit; } + return price; + } - public uint ReverseDecode(Decoder rangeDecoder) + public uint ReverseGetPrice(uint symbol) + { + uint price = 0; + uint m = 1; + for (var i = _numBitLevels; i > 0; i--) { - uint m = 1; - uint symbol = 0; - for (int bitIndex = 0; bitIndex < _numBitLevels; bitIndex++) - { - uint bit = _models[m].Decode(rangeDecoder); - m <<= 1; - m += bit; - symbol |= (bit << bitIndex); - } - return symbol; + var bit = symbol & 1; + symbol >>= 1; + price += _models[m].GetPrice(bit); + m = (m << 1) | bit; } + return price; + } - public static uint ReverseDecode( - BitDecoder[] models, - UInt32 startIndex, - Decoder rangeDecoder, - int numBitLevels - ) + public static uint ReverseGetPrice( + BitEncoder[] models, + uint startIndex, + int numBitLevels, + uint symbol + ) + { + uint price = 0; + uint m = 1; + for (var i = numBitLevels; i > 0; i--) { - uint m = 1; - uint symbol = 0; - for (int bitIndex = 0; bitIndex < numBitLevels; bitIndex++) - { - uint bit = models[startIndex + m].Decode(rangeDecoder); - m <<= 1; - m += bit; - symbol |= (bit << bitIndex); - } - return symbol; + var bit = symbol & 1; + symbol >>= 1; + price += models[startIndex + m].GetPrice(bit); + m = (m << 1) | bit; + } + return price; + } + + public static void ReverseEncode( + BitEncoder[] models, + uint startIndex, + Encoder rangeEncoder, + int numBitLevels, + uint symbol + ) + { + uint m = 1; + for (var i = 0; i < numBitLevels; i++) + { + var bit = symbol & 1; + models[startIndex + m].Encode(rangeEncoder, bit); + m = (m << 1) | bit; + symbol >>= 1; } } } + +internal readonly struct BitTreeDecoder +{ + private readonly BitDecoder[] _models; + private readonly int _numBitLevels; + + public BitTreeDecoder(int numBitLevels) + { + _numBitLevels = numBitLevels; + _models = new BitDecoder[1 << numBitLevels]; + } + + public void Init() + { + for (uint i = 1; i < (1 << _numBitLevels); i++) + { + _models[i].Init(); + } + } + + public uint Decode(Decoder rangeDecoder) + { + uint m = 1; + for (var bitIndex = _numBitLevels; bitIndex > 0; bitIndex--) + { + m = (m << 1) + _models[m].Decode(rangeDecoder); + } + return m - ((uint)1 << _numBitLevels); + } + + public uint ReverseDecode(Decoder rangeDecoder) + { + uint m = 1; + uint symbol = 0; + for (var bitIndex = 0; bitIndex < _numBitLevels; bitIndex++) + { + var bit = _models[m].Decode(rangeDecoder); + m <<= 1; + m += bit; + symbol |= (bit << bitIndex); + } + return symbol; + } + + public static uint ReverseDecode( + BitDecoder[] models, + uint startIndex, + Decoder rangeDecoder, + int numBitLevels + ) + { + uint m = 1; + uint symbol = 0; + for (var bitIndex = 0; bitIndex < numBitLevels; bitIndex++) + { + var bit = models[startIndex + m].Decode(rangeDecoder); + m <<= 1; + m += bit; + symbol |= (bit << bitIndex); + } + return symbol; + } +} diff --git a/src/SharpCompress/Compressors/LZMA/Registry.cs b/src/SharpCompress/Compressors/LZMA/Registry.cs index 967d1fe7..6aba0c5d 100644 --- a/src/SharpCompress/Compressors/LZMA/Registry.cs +++ b/src/SharpCompress/Compressors/LZMA/Registry.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; using System.Linq; using SharpCompress.Common.SevenZip; @@ -8,54 +8,52 @@ using SharpCompress.Compressors.Filters; using SharpCompress.Compressors.LZMA.Utilites; using SharpCompress.Compressors.PPMd; -namespace SharpCompress.Compressors.LZMA -{ - internal static class DecoderRegistry - { - private const uint K_COPY = 0x0; - private const uint K_DELTA = 3; - private const uint K_LZMA2 = 0x21; - private const uint K_LZMA = 0x030101; - private const uint K_PPMD = 0x030401; - private const uint K_BCJ = 0x03030103; - private const uint K_BCJ2 = 0x0303011B; - private const uint K_DEFLATE = 0x040108; - private const uint K_B_ZIP2 = 0x040202; +namespace SharpCompress.Compressors.LZMA; - internal static Stream CreateDecoderStream( - CMethodId id, - Stream[] inStreams, - byte[] info, - IPasswordProvider pass, - long limit - ) +internal static class DecoderRegistry +{ + private const uint K_COPY = 0x0; + private const uint K_LZMA2 = 0x21; + private const uint K_LZMA = 0x030101; + private const uint K_PPMD = 0x030401; + private const uint K_BCJ = 0x03030103; + private const uint K_BCJ2 = 0x0303011B; + private const uint K_DEFLATE = 0x040108; + private const uint K_B_ZIP2 = 0x040202; + + internal static Stream CreateDecoderStream( + CMethodId id, + Stream[] inStreams, + byte[] info, + IPasswordProvider pass, + long limit + ) + { + switch (id._id) { - switch (id._id) - { - case K_COPY: - if (info != null) - { - throw new NotSupportedException(); - } - return inStreams.Single(); - case K_LZMA: - case K_LZMA2: - return new LzmaStream(info, inStreams.Single(), -1, limit); - case CMethodId.K_AES_ID: - return new AesDecoderStream(inStreams.Single(), info, pass, limit); - case K_BCJ: - return new BCJFilter(false, inStreams.Single()); - case K_BCJ2: - return new Bcj2DecoderStream(inStreams, info, limit); - case K_B_ZIP2: - return new BZip2Stream(inStreams.Single(), CompressionMode.Decompress, true); - case K_PPMD: - return new PpmdStream(new PpmdProperties(info), inStreams.Single(), false); - case K_DEFLATE: - return new DeflateStream(inStreams.Single(), CompressionMode.Decompress); - default: + case K_COPY: + if (info != null) + { throw new NotSupportedException(); - } + } + return inStreams.Single(); + case K_LZMA: + case K_LZMA2: + return new LzmaStream(info, inStreams.Single(), -1, limit); + case CMethodId.K_AES_ID: + return new AesDecoderStream(inStreams.Single(), info, pass, limit); + case K_BCJ: + return new BCJFilter(false, inStreams.Single()); + case K_BCJ2: + return new Bcj2DecoderStream(inStreams, info, limit); + case K_B_ZIP2: + return new BZip2Stream(inStreams.Single(), CompressionMode.Decompress, true); + case K_PPMD: + return new PpmdStream(new PpmdProperties(info), inStreams.Single(), false); + case K_DEFLATE: + return new DeflateStream(inStreams.Single(), CompressionMode.Decompress); + default: + throw new NotSupportedException(); } } } diff --git a/src/SharpCompress/Compressors/LZMA/Utilites/CrcBuilderStream.cs b/src/SharpCompress/Compressors/LZMA/Utilites/CrcBuilderStream.cs index e72c715a..6e8c608f 100644 --- a/src/SharpCompress/Compressors/LZMA/Utilites/CrcBuilderStream.cs +++ b/src/SharpCompress/Compressors/LZMA/Utilites/CrcBuilderStream.cs @@ -1,86 +1,85 @@ -using System; +using System; using System.IO; -namespace SharpCompress.Compressors.LZMA.Utilites +namespace SharpCompress.Compressors.LZMA.Utilites; + +internal class CrcBuilderStream : Stream { - internal class CrcBuilderStream : Stream + private readonly Stream _mTarget; + private uint _mCrc; + private bool _mFinished; + private bool _isDisposed; + + public CrcBuilderStream(Stream target) { - private readonly Stream _mTarget; - private uint _mCrc; - private bool _mFinished; - private bool _isDisposed; + _mTarget = target; + _mCrc = Crc.INIT_CRC; + } - public CrcBuilderStream(Stream target) + protected override void Dispose(bool disposing) + { + if (_isDisposed) { - _mTarget = target; - _mCrc = Crc.INIT_CRC; + return; + } + _isDisposed = true; + _mTarget.Dispose(); + base.Dispose(disposing); + } + + public long Processed { get; private set; } + + public uint Finish() + { + if (!_mFinished) + { + _mFinished = true; + _mCrc = Crc.Finish(_mCrc); } - protected override void Dispose(bool disposing) + return _mCrc; + } + + public override bool CanRead => false; + + public override bool CanSeek => false; + + public override bool CanWrite => true; + + public override void Flush() { } + + public override long Length => throw new NotSupportedException(); + + public override long Position + { + get => throw new NotSupportedException(); + set => throw new NotSupportedException(); + } + + public override int Read(byte[] buffer, int offset, int count) + { + throw new InvalidOperationException(); + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } + + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + public override void Write(byte[] buffer, int offset, int count) + { + if (_mFinished) { - if (_isDisposed) - { - return; - } - _isDisposed = true; - _mTarget.Dispose(); - base.Dispose(disposing); + throw new InvalidOperationException("CRC calculation has been finished."); } - public long Processed { get; private set; } - - public uint Finish() - { - if (!_mFinished) - { - _mFinished = true; - _mCrc = Crc.Finish(_mCrc); - } - - return _mCrc; - } - - public override bool CanRead => false; - - public override bool CanSeek => false; - - public override bool CanWrite => true; - - public override void Flush() { } - - public override long Length => throw new NotSupportedException(); - - public override long Position - { - get => throw new NotSupportedException(); - set => throw new NotSupportedException(); - } - - public override int Read(byte[] buffer, int offset, int count) - { - throw new InvalidOperationException(); - } - - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } - - public override void SetLength(long value) - { - throw new NotSupportedException(); - } - - public override void Write(byte[] buffer, int offset, int count) - { - if (_mFinished) - { - throw new InvalidOperationException("CRC calculation has been finished."); - } - - Processed += count; - _mCrc = Crc.Update(_mCrc, buffer, offset, count); - _mTarget.Write(buffer, offset, count); - } + Processed += count; + _mCrc = Crc.Update(_mCrc, buffer, offset, count); + _mTarget.Write(buffer, offset, count); } } diff --git a/src/SharpCompress/Compressors/LZMA/Utilites/CrcCheckStream.cs b/src/SharpCompress/Compressors/LZMA/Utilites/CrcCheckStream.cs index 2f44bcc3..c81dbb1d 100644 --- a/src/SharpCompress/Compressors/LZMA/Utilites/CrcCheckStream.cs +++ b/src/SharpCompress/Compressors/LZMA/Utilites/CrcCheckStream.cs @@ -2,112 +2,111 @@ using System; using System.Diagnostics; using System.IO; -namespace SharpCompress.Compressors.LZMA.Utilites +namespace SharpCompress.Compressors.LZMA.Utilites; + +[CLSCompliant(false)] +public class CrcCheckStream : Stream { - [CLSCompliant(false)] - public class CrcCheckStream : Stream + private readonly uint _mExpectedCrc; + private uint _mCurrentCrc; + private bool _mClosed; + + private readonly long[] _mBytes = new long[256]; + private long _mLength; + + public CrcCheckStream(uint crc) { - private readonly uint _mExpectedCrc; - private uint _mCurrentCrc; - private bool _mClosed; + _mExpectedCrc = crc; + _mCurrentCrc = Crc.INIT_CRC; + } - private readonly long[] _mBytes = new long[256]; - private long _mLength; - - public CrcCheckStream(uint crc) + protected override void Dispose(bool disposing) + { + //Nanook - is not equal here - _mCurrentCrc is yet to be negated + //if (_mCurrentCrc != _mExpectedCrc) + //{ + // throw new InvalidOperationException(); + //} + try { - _mExpectedCrc = crc; - _mCurrentCrc = Crc.INIT_CRC; - } - - protected override void Dispose(bool disposing) - { - //Nanook - is not equal here - _mCurrentCrc is yet to be negated - //if (_mCurrentCrc != _mExpectedCrc) - //{ - // throw new InvalidOperationException(); - //} - try + if (disposing && !_mClosed) { - if (disposing && !_mClosed) - { - _mClosed = true; - _mCurrentCrc = Crc.Finish(_mCurrentCrc); //now becomes equal + _mClosed = true; + _mCurrentCrc = Crc.Finish(_mCurrentCrc); //now becomes equal #if DEBUG - if (_mCurrentCrc == _mExpectedCrc) - { - Debug.WriteLine("CRC ok: " + _mExpectedCrc.ToString("x8")); - } - else - { - Debugger.Break(); - Debug.WriteLine("bad CRC"); - } + if (_mCurrentCrc == _mExpectedCrc) + { + Debug.WriteLine("CRC ok: " + _mExpectedCrc.ToString("x8")); + } + else + { + Debugger.Break(); + Debug.WriteLine("bad CRC"); + } - double lengthInv = 1.0 / _mLength; - double entropy = 0; - for (int i = 0; i < 256; i++) + var lengthInv = 1.0 / _mLength; + double entropy = 0; + for (var i = 0; i < 256; i++) + { + if (_mBytes[i] != 0) { - if (_mBytes[i] != 0) - { - double p = lengthInv * _mBytes[i]; - entropy -= p * Math.Log(p, 256); - } - } - Debug.WriteLine("entropy: " + (int)(entropy * 100) + "%"); -#endif - if (_mCurrentCrc != _mExpectedCrc) //moved test to here - { - throw new InvalidOperationException(); + var p = lengthInv * _mBytes[i]; + entropy -= p * Math.Log(p, 256); } } - } - finally - { - base.Dispose(disposing); + Debug.WriteLine("entropy: " + (int)(entropy * 100) + "%"); +#endif + if (_mCurrentCrc != _mExpectedCrc) //moved test to here + { + throw new InvalidOperationException(); + } } } - - public override bool CanRead => false; - - public override bool CanSeek => false; - - public override bool CanWrite => true; - - public override void Flush() { } - - public override long Length => throw new NotSupportedException(); - - public override long Position + finally { - get => throw new NotSupportedException(); - set => throw new NotSupportedException(); - } - - public override int Read(byte[] buffer, int offset, int count) - { - throw new InvalidOperationException(); - } - - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } - - public override void SetLength(long value) - { - throw new NotSupportedException(); - } - - public override void Write(byte[] buffer, int offset, int count) - { - _mLength += count; - for (int i = 0; i < count; i++) - { - _mBytes[buffer[offset + i]]++; - } - - _mCurrentCrc = Crc.Update(_mCurrentCrc, buffer, offset, count); + base.Dispose(disposing); } } + + public override bool CanRead => false; + + public override bool CanSeek => false; + + public override bool CanWrite => true; + + public override void Flush() { } + + public override long Length => throw new NotSupportedException(); + + public override long Position + { + get => throw new NotSupportedException(); + set => throw new NotSupportedException(); + } + + public override int Read(byte[] buffer, int offset, int count) + { + throw new InvalidOperationException(); + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } + + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + public override void Write(byte[] buffer, int offset, int count) + { + _mLength += count; + for (var i = 0; i < count; i++) + { + _mBytes[buffer[offset + i]]++; + } + + _mCurrentCrc = Crc.Update(_mCurrentCrc, buffer, offset, count); + } } diff --git a/src/SharpCompress/Compressors/LZMA/Utilites/IPasswordProvider.cs b/src/SharpCompress/Compressors/LZMA/Utilites/IPasswordProvider.cs index 977c86bf..2f0eb904 100644 --- a/src/SharpCompress/Compressors/LZMA/Utilites/IPasswordProvider.cs +++ b/src/SharpCompress/Compressors/LZMA/Utilites/IPasswordProvider.cs @@ -1,7 +1,6 @@ -namespace SharpCompress.Compressors.LZMA.Utilites +namespace SharpCompress.Compressors.LZMA.Utilites; + +internal interface IPasswordProvider { - internal interface IPasswordProvider - { - string CryptoGetTextPassword(); - } + string CryptoGetTextPassword(); } diff --git a/src/SharpCompress/Compressors/LZMA/Utilites/Utils.cs b/src/SharpCompress/Compressors/LZMA/Utilites/Utils.cs index 1b64ccb6..19b0f374 100644 --- a/src/SharpCompress/Compressors/LZMA/Utilites/Utils.cs +++ b/src/SharpCompress/Compressors/LZMA/Utilites/Utils.cs @@ -1,92 +1,91 @@ -using System; +using System; using System.Diagnostics; using System.IO; -namespace SharpCompress.Compressors.LZMA.Utilites +namespace SharpCompress.Compressors.LZMA.Utilites; + +internal enum BlockType : byte { - internal enum BlockType : byte + #region Constants + + End = 0, + Header = 1, + ArchiveProperties = 2, + AdditionalStreamsInfo = 3, + MainStreamsInfo = 4, + FilesInfo = 5, + PackInfo = 6, + UnpackInfo = 7, + SubStreamsInfo = 8, + Size = 9, + Crc = 10, + Folder = 11, + CodersUnpackSize = 12, + NumUnpackStream = 13, + EmptyStream = 14, + EmptyFile = 15, + Anti = 16, + Name = 17, + CTime = 18, + ATime = 19, + MTime = 20, + WinAttributes = 21, + Comment = 22, + EncodedHeader = 23, + StartPos = 24, + Dummy = 25 + + #endregion +} + +internal static class Utils +{ + [Conditional("DEBUG")] + public static void Assert(bool expression) { - #region Constants + if (!expression) + { + if (Debugger.IsAttached) + { + Debugger.Break(); + } - End = 0, - Header = 1, - ArchiveProperties = 2, - AdditionalStreamsInfo = 3, - MainStreamsInfo = 4, - FilesInfo = 5, - PackInfo = 6, - UnpackInfo = 7, - SubStreamsInfo = 8, - Size = 9, - Crc = 10, - Folder = 11, - CodersUnpackSize = 12, - NumUnpackStream = 13, - EmptyStream = 14, - EmptyFile = 15, - Anti = 16, - Name = 17, - CTime = 18, - ATime = 19, - MTime = 20, - WinAttributes = 21, - Comment = 22, - EncodedHeader = 23, - StartPos = 24, - Dummy = 25 - - #endregion + throw new InvalidOperationException("Assertion failed."); + } } - internal static class Utils + public static void ReadExact(this Stream stream, byte[] buffer, int offset, int length) { - [Conditional("DEBUG")] - public static void Assert(bool expression) + if (stream is null) { - if (!expression) - { - if (Debugger.IsAttached) - { - Debugger.Break(); - } - - throw new InvalidOperationException("Assertion failed."); - } + throw new ArgumentNullException(nameof(stream)); } - public static void ReadExact(this Stream stream, byte[] buffer, int offset, int length) + if (buffer is null) { - if (stream is null) + throw new ArgumentNullException(nameof(buffer)); + } + + if (offset < 0 || offset > buffer.Length) + { + throw new ArgumentOutOfRangeException(nameof(offset)); + } + + if (length < 0 || length > buffer.Length - offset) + { + throw new ArgumentOutOfRangeException(nameof(length)); + } + + while (length > 0) + { + var fetched = stream.Read(buffer, offset, length); + if (fetched <= 0) { - throw new ArgumentNullException(nameof(stream)); + throw new EndOfStreamException(); } - if (buffer is null) - { - throw new ArgumentNullException(nameof(buffer)); - } - - if (offset < 0 || offset > buffer.Length) - { - throw new ArgumentOutOfRangeException(nameof(offset)); - } - - if (length < 0 || length > buffer.Length - offset) - { - throw new ArgumentOutOfRangeException(nameof(length)); - } - - while (length > 0) - { - int fetched = stream.Read(buffer, offset, length); - if (fetched <= 0) - { - throw new EndOfStreamException(); - } - - offset += fetched; - length -= fetched; - } + offset += fetched; + length -= fetched; } } } diff --git a/src/SharpCompress/Compressors/PPMd/H/FreqData.cs b/src/SharpCompress/Compressors/PPMd/H/FreqData.cs index a139a449..bb7a630d 100644 --- a/src/SharpCompress/Compressors/PPMd/H/FreqData.cs +++ b/src/SharpCompress/Compressors/PPMd/H/FreqData.cs @@ -2,65 +2,64 @@ using System; using System.Buffers.Binary; using System.Text; -namespace SharpCompress.Compressors.PPMd.H +namespace SharpCompress.Compressors.PPMd.H; + +internal class FreqData : Pointer { - internal class FreqData : Pointer + internal const int SIZE = 6; + + // struct FreqData + // { + // ushort SummFreq; + // STATE _PACK_ATTR * Stats; + // }; + + internal FreqData(byte[] memory) : base(memory) { } + + internal int SummFreq { - internal const int SIZE = 6; + get => BinaryPrimitives.ReadInt16LittleEndian(Memory.AsSpan(Address)) & 0xffff; + set => BinaryPrimitives.WriteInt16LittleEndian(Memory.AsSpan(Address), (short)value); + } - // struct FreqData - // { - // ushort SummFreq; - // STATE _PACK_ATTR * Stats; - // }; + internal FreqData Initialize(byte[] mem) + { + return Initialize(mem); + } - internal FreqData(byte[] memory) : base(memory) { } + internal void IncrementSummFreq(int dSummFreq) + { + SummFreq += (short)dSummFreq; + } - internal int SummFreq - { - get => BinaryPrimitives.ReadInt16LittleEndian(Memory.AsSpan(Address)) & 0xffff; - set => BinaryPrimitives.WriteInt16LittleEndian(Memory.AsSpan(Address), (short)value); - } + internal int GetStats() + { + return BinaryPrimitives.ReadInt32LittleEndian(Memory.AsSpan(Address + 2)); + } - internal FreqData Initialize(byte[] mem) - { - return base.Initialize(mem); - } + internal virtual void SetStats(State state) + { + SetStats(state.Address); + } - internal void IncrementSummFreq(int dSummFreq) - { - SummFreq += (short)dSummFreq; - } + internal void SetStats(int state) + { + BinaryPrimitives.WriteInt32LittleEndian(Memory.AsSpan(Address + 2), state); + } - internal int GetStats() - { - return BinaryPrimitives.ReadInt32LittleEndian(Memory.AsSpan(Address + 2)); - } - - internal virtual void SetStats(State state) - { - SetStats(state.Address); - } - - internal void SetStats(int state) - { - BinaryPrimitives.WriteInt32LittleEndian(Memory.AsSpan(Address + 2), state); - } - - public override String ToString() - { - StringBuilder buffer = new StringBuilder(); - buffer.Append("FreqData["); - buffer.Append("\n Address="); - buffer.Append(Address); - buffer.Append("\n size="); - buffer.Append(SIZE); - buffer.Append("\n summFreq="); - buffer.Append(SummFreq); - buffer.Append("\n stats="); - buffer.Append(GetStats()); - buffer.Append("\n]"); - return buffer.ToString(); - } + public override string ToString() + { + var buffer = new StringBuilder(); + buffer.Append("FreqData["); + buffer.Append("\n Address="); + buffer.Append(Address); + buffer.Append("\n size="); + buffer.Append(SIZE); + buffer.Append("\n summFreq="); + buffer.Append(SummFreq); + buffer.Append("\n stats="); + buffer.Append(GetStats()); + buffer.Append("\n]"); + return buffer.ToString(); } } diff --git a/src/SharpCompress/Compressors/PPMd/H/ModelPPM.cs b/src/SharpCompress/Compressors/PPMd/H/ModelPPM.cs index 974a61ea..1eb8ae3d 100644 --- a/src/SharpCompress/Compressors/PPMd/H/ModelPPM.cs +++ b/src/SharpCompress/Compressors/PPMd/H/ModelPPM.cs @@ -6,984 +6,982 @@ using System.Text; using SharpCompress.Compressors.Rar; using Decoder = SharpCompress.Compressors.LZMA.RangeCoder.Decoder; -namespace SharpCompress.Compressors.PPMd.H +namespace SharpCompress.Compressors.PPMd.H; + +internal class ModelPpm { - internal class ModelPpm + private void InitBlock() { - private void InitBlock() + for (var i = 0; i < 25; i++) { - for (int i = 0; i < 25; i++) + _see2Cont[i] = new See2Context[16]; + } + for (var i2 = 0; i2 < 128; i2++) + { + _binSumm[i2] = new int[64]; + } + } + + public SubAllocator SubAlloc { get; } = new SubAllocator(); + + public virtual See2Context DummySee2Cont => _dummySee2Cont; + + public virtual int InitRl => _initRl; + + public virtual int EscCount + { + get => _escCount; + set => _escCount = value & 0xff; + } + + public virtual int[] CharMask => _charMask; + + public virtual int NumMasked + { + get => _numMasked; + set => _numMasked = value; + } + + public virtual int PrevSuccess + { + get => _prevSuccess; + set => _prevSuccess = value & 0xff; + } + + public virtual int InitEsc + { + get => _initEsc; + set => _initEsc = value; + } + + public virtual int RunLength + { + get => _runLength; + set => _runLength = value; + } + + public virtual int HiBitsFlag + { + get => _hiBitsFlag; + set => _hiBitsFlag = value & 0xff; + } + + public virtual int[][] BinSumm => _binSumm; + + internal RangeCoder Coder { get; private set; } + + internal State FoundState { get; private set; } + + public virtual byte[] Heap => SubAlloc.Heap; + + public virtual int OrderFall => _orderFall; + + public const int MAX_O = 64; /* maximum allowed model order */ + + public const int INT_BITS = 7; + + public const int PERIOD_BITS = 7; + + //UPGRADE_NOTE: Final was removed from the declaration of 'TOT_BITS '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + public static readonly int TOT_BITS = INT_BITS + PERIOD_BITS; + + //UPGRADE_NOTE: Final was removed from the declaration of 'INTERVAL '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + public static readonly int INTERVAL = 1 << INT_BITS; + + //UPGRADE_NOTE: Final was removed from the declaration of 'BIN_SCALE '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + public static readonly int BIN_SCALE = 1 << TOT_BITS; + + public const int MAX_FREQ = 124; + + private readonly See2Context[][] _see2Cont = new See2Context[25][]; + + private See2Context _dummySee2Cont; + + private PpmContext _minContext; //medContext + + private PpmContext _maxContext; + + private int _numMasked, + _initEsc, + _orderFall, + _maxOrder, + _runLength, + _initRl; + + private readonly int[] _charMask = new int[256]; + + private readonly int[] _ns2Indx = new int[256]; + + private readonly int[] _ns2BsIndx = new int[256]; + + private readonly int[] _hb2Flag = new int[256]; + + // byte EscCount, PrevSuccess, HiBitsFlag; + private int _escCount, + _prevSuccess, + _hiBitsFlag; + + private readonly int[][] _binSumm = new int[128][]; // binary SEE-contexts + + private static readonly int[] INIT_BIN_ESC = + { + 0x3CDD, + 0x1F3F, + 0x59BF, + 0x48F3, + 0x64A1, + 0x5ABC, + 0x6632, + 0x6051 + }; + + // Temp fields + //UPGRADE_NOTE: Final was removed from the declaration of 'tempState1 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + private readonly State _tempState1 = new State(null); + + //UPGRADE_NOTE: Final was removed from the declaration of 'tempState2 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + private readonly State _tempState2 = new State(null); + + //UPGRADE_NOTE: Final was removed from the declaration of 'tempState3 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + private readonly State _tempState3 = new State(null); + + //UPGRADE_NOTE: Final was removed from the declaration of 'tempState4 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + private readonly State _tempState4 = new State(null); + + //UPGRADE_NOTE: Final was removed from the declaration of 'tempStateRef1 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + private readonly StateRef _tempStateRef1 = new StateRef(); + + //UPGRADE_NOTE: Final was removed from the declaration of 'tempStateRef2 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + private readonly StateRef _tempStateRef2 = new StateRef(); + + //UPGRADE_NOTE: Final was removed from the declaration of 'tempPPMContext1 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + private readonly PpmContext _tempPpmContext1 = new PpmContext(null); + + //UPGRADE_NOTE: Final was removed from the declaration of 'tempPPMContext2 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + private readonly PpmContext _tempPpmContext2 = new PpmContext(null); + + //UPGRADE_NOTE: Final was removed from the declaration of 'tempPPMContext3 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + private readonly PpmContext _tempPpmContext3 = new PpmContext(null); + + //UPGRADE_NOTE: Final was removed from the declaration of 'tempPPMContext4 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + private readonly PpmContext _tempPpmContext4 = new PpmContext(null); + + //UPGRADE_NOTE: Final was removed from the declaration of 'ps '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + private readonly int[] _ps = new int[MAX_O]; + + public ModelPpm() + { + InitBlock(); + _minContext = null; + _maxContext = null; + + //medContext = null; + } + + private void RestartModelRare() + { + new Span(_charMask).Clear(); + SubAlloc.InitSubAllocator(); + _initRl = -(_maxOrder < 12 ? _maxOrder : 12) - 1; + var addr = SubAlloc.AllocContext(); + _minContext.Address = addr; + _maxContext.Address = addr; + _minContext.SetSuffix(0); + _orderFall = _maxOrder; + _minContext.NumStats = 256; + _minContext.FreqData.SummFreq = _minContext.NumStats + 1; + + addr = SubAlloc.AllocUnits(256 / 2); + FoundState.Address = addr; + _minContext.FreqData.SetStats(addr); + + var state = new State(SubAlloc.Heap); + addr = _minContext.FreqData.GetStats(); + _runLength = _initRl; + _prevSuccess = 0; + for (var i = 0; i < 256; i++) + { + state.Address = addr + (i * State.SIZE); + state.Symbol = i; + state.Freq = 1; + state.SetSuccessor(0); + } + + for (var i = 0; i < 128; i++) + { + for (var k = 0; k < 8; k++) { - _see2Cont[i] = new See2Context[16]; - } - for (int i2 = 0; i2 < 128; i2++) - { - _binSumm[i2] = new int[64]; - } - } - - public SubAllocator SubAlloc { get; } = new SubAllocator(); - - public virtual See2Context DummySee2Cont => _dummySee2Cont; - - public virtual int InitRl => _initRl; - - public virtual int EscCount - { - get => _escCount; - set => _escCount = value & 0xff; - } - - public virtual int[] CharMask => _charMask; - - public virtual int NumMasked - { - get => _numMasked; - set => _numMasked = value; - } - - public virtual int PrevSuccess - { - get => _prevSuccess; - set => _prevSuccess = value & 0xff; - } - - public virtual int InitEsc - { - get => _initEsc; - set => _initEsc = value; - } - - public virtual int RunLength - { - get => _runLength; - set => _runLength = value; - } - - public virtual int HiBitsFlag - { - get => _hiBitsFlag; - set => _hiBitsFlag = value & 0xff; - } - - public virtual int[][] BinSumm => _binSumm; - - internal RangeCoder Coder { get; private set; } - - internal State FoundState { get; private set; } - - public virtual byte[] Heap => SubAlloc.Heap; - - public virtual int OrderFall => _orderFall; - - public const int MAX_O = 64; /* maximum allowed model order */ - - public const int INT_BITS = 7; - - public const int PERIOD_BITS = 7; - - //UPGRADE_NOTE: Final was removed from the declaration of 'TOT_BITS '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly int TOT_BITS = INT_BITS + PERIOD_BITS; - - //UPGRADE_NOTE: Final was removed from the declaration of 'INTERVAL '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly int INTERVAL = 1 << INT_BITS; - - //UPGRADE_NOTE: Final was removed from the declaration of 'BIN_SCALE '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly int BIN_SCALE = 1 << TOT_BITS; - - public const int MAX_FREQ = 124; - - private readonly See2Context[][] _see2Cont = new See2Context[25][]; - - private See2Context _dummySee2Cont; - - private PpmContext _minContext; //medContext - - private PpmContext _maxContext; - - private int _numMasked, - _initEsc, - _orderFall, - _maxOrder, - _runLength, - _initRl; - - private readonly int[] _charMask = new int[256]; - - private readonly int[] _ns2Indx = new int[256]; - - private readonly int[] _ns2BsIndx = new int[256]; - - private readonly int[] _hb2Flag = new int[256]; - - // byte EscCount, PrevSuccess, HiBitsFlag; - private int _escCount, - _prevSuccess, - _hiBitsFlag; - - private readonly int[][] _binSumm = new int[128][]; // binary SEE-contexts - - private static readonly int[] INIT_BIN_ESC = - { - 0x3CDD, - 0x1F3F, - 0x59BF, - 0x48F3, - 0x64A1, - 0x5ABC, - 0x6632, - 0x6051 - }; - - // Temp fields - //UPGRADE_NOTE: Final was removed from the declaration of 'tempState1 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private readonly State _tempState1 = new State(null); - - //UPGRADE_NOTE: Final was removed from the declaration of 'tempState2 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private readonly State _tempState2 = new State(null); - - //UPGRADE_NOTE: Final was removed from the declaration of 'tempState3 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private readonly State _tempState3 = new State(null); - - //UPGRADE_NOTE: Final was removed from the declaration of 'tempState4 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private readonly State _tempState4 = new State(null); - - //UPGRADE_NOTE: Final was removed from the declaration of 'tempStateRef1 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private readonly StateRef _tempStateRef1 = new StateRef(); - - //UPGRADE_NOTE: Final was removed from the declaration of 'tempStateRef2 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private readonly StateRef _tempStateRef2 = new StateRef(); - - //UPGRADE_NOTE: Final was removed from the declaration of 'tempPPMContext1 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private readonly PpmContext _tempPpmContext1 = new PpmContext(null); - - //UPGRADE_NOTE: Final was removed from the declaration of 'tempPPMContext2 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private readonly PpmContext _tempPpmContext2 = new PpmContext(null); - - //UPGRADE_NOTE: Final was removed from the declaration of 'tempPPMContext3 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private readonly PpmContext _tempPpmContext3 = new PpmContext(null); - - //UPGRADE_NOTE: Final was removed from the declaration of 'tempPPMContext4 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private readonly PpmContext _tempPpmContext4 = new PpmContext(null); - - //UPGRADE_NOTE: Final was removed from the declaration of 'ps '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private readonly int[] _ps = new int[MAX_O]; - - public ModelPpm() - { - InitBlock(); - _minContext = null; - _maxContext = null; - - //medContext = null; - } - - private void RestartModelRare() - { - new Span(_charMask).Clear(); - SubAlloc.InitSubAllocator(); - _initRl = -(_maxOrder < 12 ? _maxOrder : 12) - 1; - int addr = SubAlloc.AllocContext(); - _minContext.Address = addr; - _maxContext.Address = addr; - _minContext.SetSuffix(0); - _orderFall = _maxOrder; - _minContext.NumStats = 256; - _minContext.FreqData.SummFreq = _minContext.NumStats + 1; - - addr = SubAlloc.AllocUnits(256 / 2); - FoundState.Address = addr; - _minContext.FreqData.SetStats(addr); - - State state = new State(SubAlloc.Heap); - addr = _minContext.FreqData.GetStats(); - _runLength = _initRl; - _prevSuccess = 0; - for (int i = 0; i < 256; i++) - { - state.Address = addr + i * State.SIZE; - state.Symbol = i; - state.Freq = 1; - state.SetSuccessor(0); - } - - for (int i = 0; i < 128; i++) - { - for (int k = 0; k < 8; k++) + for (var m = 0; m < 64; m += 8) { - for (int m = 0; m < 64; m += 8) - { - _binSumm[i][k + m] = BIN_SCALE - INIT_BIN_ESC[k] / (i + 2); - } - } - } - for (int i = 0; i < 25; i++) - { - for (int k = 0; k < 16; k++) - { - _see2Cont[i][k].Initialize(5 * i + 10); + _binSumm[i][k + m] = BIN_SCALE - (INIT_BIN_ESC[k] / (i + 2)); } } } - - private void StartModelRare(int maxOrder) + for (var i = 0; i < 25; i++) { - int i, - k, - m, - step; - _escCount = 1; - _maxOrder = maxOrder; - RestartModelRare(); - - // Bug Fixed - _ns2BsIndx[0] = 0; - _ns2BsIndx[1] = 2; - for (int j = 0; j < 9; j++) + for (var k = 0; k < 16; k++) { - _ns2BsIndx[2 + j] = 4; + _see2Cont[i][k].Initialize((5 * i) + 10); } - for (int j = 0; j < 256 - 11; j++) - { - _ns2BsIndx[11 + j] = 6; - } - for (i = 0; i < 3; i++) - { - _ns2Indx[i] = i; - } - for (m = i, k = 1, step = 1; i < 256; i++) - { - _ns2Indx[i] = m; - if ((--k) == 0) - { - k = ++step; - m++; - } - } - for (int j = 0; j < 0x40; j++) - { - _hb2Flag[j] = 0; - } - for (int j = 0; j < 0x100 - 0x40; j++) - { - _hb2Flag[0x40 + j] = 0x08; - } - _dummySee2Cont.Shift = PERIOD_BITS; } + } - private void ClearMask() + private void StartModelRare(int maxOrder) + { + int i, + k, + m, + step; + _escCount = 1; + _maxOrder = maxOrder; + RestartModelRare(); + + // Bug Fixed + _ns2BsIndx[0] = 0; + _ns2BsIndx[1] = 2; + for (var j = 0; j < 9; j++) { - _escCount = 1; - new Span(_charMask).Clear(); + _ns2BsIndx[2 + j] = 4; } - - internal bool DecodeInit(IRarUnpack unpackRead, int escChar) + for (var j = 0; j < 256 - 11; j++) { - int maxOrder = unpackRead.Char & 0xff; - bool reset = ((maxOrder & 0x20) != 0); - - int maxMb = 0; - if (reset) - { - maxMb = unpackRead.Char; - } - else - { - if (SubAlloc.GetAllocatedMemory() == 0) - { - return (false); - } - } - if ((maxOrder & 0x40) != 0) - { - escChar = unpackRead.Char; - unpackRead.PpmEscChar = escChar; - } - Coder = new RangeCoder(unpackRead); - if (reset) - { - maxOrder = (maxOrder & 0x1f) + 1; - if (maxOrder > 16) - { - maxOrder = 16 + (maxOrder - 16) * 3; - } - if (maxOrder == 1) - { - SubAlloc.StopSubAllocator(); - return (false); - } - SubAlloc.StartSubAllocator((maxMb + 1) << 20); - _minContext = new PpmContext(Heap); - - //medContext = new PPMContext(Heap); - _maxContext = new PpmContext(Heap); - FoundState = new State(Heap); - _dummySee2Cont = new See2Context(); - for (int i = 0; i < 25; i++) - { - for (int j = 0; j < 16; j++) - { - _see2Cont[i][j] = new See2Context(); - } - } - StartModelRare(maxOrder); - } - return (_minContext.Address != 0); + _ns2BsIndx[11 + j] = 6; } - - public virtual int DecodeChar() + for (i = 0; i < 3; i++) { - // Debug - //subAlloc.dumpHeap(); - - if (_minContext.Address <= SubAlloc.PText || _minContext.Address > SubAlloc.HeapEnd) - { - return (-1); - } - - if (_minContext.NumStats != 1) - { - if ( - _minContext.FreqData.GetStats() <= SubAlloc.PText - || _minContext.FreqData.GetStats() > SubAlloc.HeapEnd - ) - { - return (-1); - } - if (!_minContext.DecodeSymbol1(this)) - { - return (-1); - } - } - else - { - _minContext.DecodeBinSymbol(this); - } - Coder.Decode(); - while (FoundState.Address == 0) - { - Coder.AriDecNormalize(); - do - { - _orderFall++; - _minContext.Address = _minContext.GetSuffix(); // =MinContext->Suffix; - if ( - _minContext.Address <= SubAlloc.PText - || _minContext.Address > SubAlloc.HeapEnd - ) - { - return (-1); - } - } while (_minContext.NumStats == _numMasked); - if (!_minContext.DecodeSymbol2(this)) - { - return (-1); - } - Coder.Decode(); - } - int symbol = FoundState.Symbol; - if ((_orderFall == 0) && FoundState.GetSuccessor() > SubAlloc.PText) - { - // MinContext=MaxContext=FoundState->Successor; - int addr = FoundState.GetSuccessor(); - _minContext.Address = addr; - _maxContext.Address = addr; - } - else - { - UpdateModel(); - - //this.foundState.Address=foundState.Address);//TODO just 4 debugging - if (_escCount == 0) - { - ClearMask(); - } - } - Coder.AriDecNormalize(); // ARI_DEC_NORMALIZE(Coder.code,Coder.low,Coder.range,Coder.UnpackRead); - return (symbol); + _ns2Indx[i] = i; } - - public virtual See2Context[][] GetSee2Cont() + for (m = i, k = 1, step = 1; i < 256; i++) { - return _see2Cont; + _ns2Indx[i] = m; + if ((--k) == 0) + { + k = ++step; + m++; + } } - - public virtual void IncEscCount(int dEscCount) + for (var j = 0; j < 0x40; j++) { - EscCount = EscCount + dEscCount; + _hb2Flag[j] = 0; } - - public virtual void IncRunLength(int dRunLength) + for (var j = 0; j < 0x100 - 0x40; j++) { - RunLength = RunLength + dRunLength; + _hb2Flag[0x40 + j] = 0x08; } + _dummySee2Cont.Shift = PERIOD_BITS; + } - public virtual int[] GetHb2Flag() + private void ClearMask() + { + _escCount = 1; + new Span(_charMask).Clear(); + } + + internal bool DecodeInit(IRarUnpack unpackRead, int escChar) + { + var maxOrder = unpackRead.Char & 0xff; + var reset = ((maxOrder & 0x20) != 0); + + var maxMb = 0; + if (reset) { - return _hb2Flag; + maxMb = unpackRead.Char; } - - public virtual int[] GetNs2BsIndx() + else { - return _ns2BsIndx; + if (SubAlloc.GetAllocatedMemory() == 0) + { + return (false); + } } - - public virtual int[] GetNs2Indx() + if ((maxOrder & 0x40) != 0) { - return _ns2Indx; + escChar = unpackRead.Char; + unpackRead.PpmEscChar = escChar; } - - private int CreateSuccessors(bool skip, State p1) + Coder = new RangeCoder(unpackRead); + if (reset) { - //State upState = tempState1.Initialize(null); - StateRef upState = _tempStateRef2; - State tempState = _tempState1.Initialize(Heap); - - // PPM_CONTEXT* pc=MinContext, * UpBranch=FoundState->Successor; - PpmContext pc = _tempPpmContext1.Initialize(Heap); - pc.Address = _minContext.Address; - PpmContext upBranch = _tempPpmContext2.Initialize(Heap); - upBranch.Address = FoundState.GetSuccessor(); - - // STATE * p, * ps[MAX_O], ** pps=ps; - State p = _tempState2.Initialize(Heap); - int pps = 0; - - bool noLoop = false; - - if (!skip) + maxOrder = (maxOrder & 0x1f) + 1; + if (maxOrder > 16) { - _ps[pps++] = FoundState.Address; // *pps++ = FoundState; - if (pc.GetSuffix() == 0) - { - noLoop = true; - } + maxOrder = 16 + ((maxOrder - 16) * 3); } - if (!noLoop) - { - bool loopEntry = false; - if (p1.Address != 0) - { - p.Address = p1.Address; - pc.Address = pc.GetSuffix(); // =pc->Suffix; - loopEntry = true; - } - do - { - if (!loopEntry) - { - pc.Address = pc.GetSuffix(); // pc=pc->Suffix; - if (pc.NumStats != 1) - { - p.Address = pc.FreqData.GetStats(); // p=pc->U.Stats - if (p.Symbol != FoundState.Symbol) - { - do - { - p.IncrementAddress(); - } while (p.Symbol != FoundState.Symbol); - } - } - else - { - p.Address = pc.GetOneState().Address; // p=&(pc->OneState); - } - } // LOOP_ENTRY: - loopEntry = false; - if (p.GetSuccessor() != upBranch.Address) - { - pc.Address = p.GetSuccessor(); // =p->Successor; - break; - } - _ps[pps++] = p.Address; - } while (pc.GetSuffix() != 0); - } // NO_LOOP: - if (pps == 0) - { - return pc.Address; - } - upState.Symbol = Heap[upBranch.Address]; // UpState.Symbol=*(byte*) - - // UpBranch; - // UpState.Successor=(PPM_CONTEXT*) (((byte*) UpBranch)+1); - upState.SetSuccessor(upBranch.Address + 1); //TODO check if +1 necessary - if (pc.NumStats != 1) - { - if (pc.Address <= SubAlloc.PText) - { - return (0); - } - p.Address = pc.FreqData.GetStats(); - if (p.Symbol != upState.Symbol) - { - do - { - p.IncrementAddress(); - } while (p.Symbol != upState.Symbol); - } - int cf = p.Freq - 1; - int s0 = pc.FreqData.SummFreq - pc.NumStats - cf; - - // UpState.Freq=1+((2*cf <= s0)?(5*cf > s0):((2*cf+3*s0-1)/(2*s0))); - upState.Freq = - 1 - + ((2 * cf <= s0) ? (5 * cf > s0 ? 1 : 0) : ((2 * cf + 3 * s0 - 1) / (2 * s0))); - } - else - { - upState.Freq = pc.GetOneState().Freq; // UpState.Freq=pc->OneState.Freq; - } - do - { - // pc = pc->createChild(this,*--pps,UpState); - tempState.Address = _ps[--pps]; - pc.Address = pc.CreateChild(this, tempState, upState); - if (pc.Address == 0) - { - return 0; - } - } while (pps != 0); - return pc.Address; - } - - private void UpdateModelRestart() - { - RestartModelRare(); - _escCount = 0; - } - - private void UpdateModel() - { - //System.out.println("ModelPPM.updateModel()"); - // STATE fs = *FoundState, *p = NULL; - StateRef fs = _tempStateRef1; - fs.Values = FoundState; - State p = _tempState3.Initialize(Heap); - State tempState = _tempState4.Initialize(Heap); - - PpmContext pc = _tempPpmContext3.Initialize(Heap); - PpmContext successor = _tempPpmContext4.Initialize(Heap); - - int ns1, - ns, - cf, - sf, - s0; - pc.Address = _minContext.GetSuffix(); - if (fs.Freq < MAX_FREQ / 4 && pc.Address != 0) - { - if (pc.NumStats != 1) - { - p.Address = pc.FreqData.GetStats(); - if (p.Symbol != fs.Symbol) - { - do - { - p.IncrementAddress(); - } while (p.Symbol != fs.Symbol); - tempState.Address = p.Address - State.SIZE; - if (p.Freq >= tempState.Freq) - { - State.PpmdSwap(p, tempState); - p.DecrementAddress(); - } - } - if (p.Freq < MAX_FREQ - 9) - { - p.IncrementFreq(2); - pc.FreqData.IncrementSummFreq(2); - } - } - else - { - p.Address = pc.GetOneState().Address; - if (p.Freq < 32) - { - p.IncrementFreq(1); - } - } - } - if (_orderFall == 0) - { - FoundState.SetSuccessor(CreateSuccessors(true, p)); - _minContext.Address = FoundState.GetSuccessor(); - _maxContext.Address = FoundState.GetSuccessor(); - if (_minContext.Address == 0) - { - UpdateModelRestart(); - return; - } - return; - } - SubAlloc.Heap[SubAlloc.PText] = (byte)fs.Symbol; - SubAlloc.IncPText(); - successor.Address = SubAlloc.PText; - if (SubAlloc.PText >= SubAlloc.FakeUnitsStart) - { - UpdateModelRestart(); - return; - } - - // // Debug - // subAlloc.dumpHeap(); - if (fs.GetSuccessor() != 0) - { - if (fs.GetSuccessor() <= SubAlloc.PText) - { - fs.SetSuccessor(CreateSuccessors(false, p)); - if (fs.GetSuccessor() == 0) - { - UpdateModelRestart(); - return; - } - } - if (--_orderFall == 0) - { - successor.Address = fs.GetSuccessor(); - if (_maxContext.Address != _minContext.Address) - { - SubAlloc.DecPText(1); - } - } - } - else - { - FoundState.SetSuccessor(successor.Address); - fs.SetSuccessor(_minContext); - } - - // // Debug - // subAlloc.dumpHeap(); - ns = _minContext.NumStats; - s0 = _minContext.FreqData.SummFreq - (ns) - (fs.Freq - 1); - for ( - pc.Address = _maxContext.Address; - pc.Address != _minContext.Address; - pc.Address = pc.GetSuffix() - ) - { - if ((ns1 = pc.NumStats) != 1) - { - if ((ns1 & 1) == 0) - { - //System.out.println(ns1); - pc.FreqData.SetStats( - SubAlloc.ExpandUnits(pc.FreqData.GetStats(), Utility.URShift(ns1, 1)) - ); - if (pc.FreqData.GetStats() == 0) - { - UpdateModelRestart(); - return; - } - } - - // bug fixed - // int sum = ((2 * ns1 < ns) ? 1 : 0) + - // 2 * ((4 * ((ns1 <= ns) ? 1 : 0)) & ((pc.getFreqData() - // .getSummFreq() <= 8 * ns1) ? 1 : 0)); - int sum = - ((2 * ns1 < ns) ? 1 : 0) - + 2 - * ( - ((4 * ns1 <= ns) ? 1 : 0) - & ((pc.FreqData.SummFreq <= 8 * ns1) ? 1 : 0) - ); - pc.FreqData.IncrementSummFreq(sum); - } - else - { - p.Address = SubAlloc.AllocUnits(1); - if (p.Address == 0) - { - UpdateModelRestart(); - return; - } - p.SetValues(pc.GetOneState()); - pc.FreqData.SetStats(p); - if (p.Freq < MAX_FREQ / 4 - 1) - { - p.IncrementFreq(p.Freq); - } - else - { - p.Freq = MAX_FREQ - 4; - } - pc.FreqData.SummFreq = (p.Freq + _initEsc + (ns > 3 ? 1 : 0)); - } - cf = 2 * fs.Freq * (pc.FreqData.SummFreq + 6); - sf = s0 + pc.FreqData.SummFreq; - if (cf < 6 * sf) - { - cf = 1 + (cf > sf ? 1 : 0) + (cf >= 4 * sf ? 1 : 0); - pc.FreqData.IncrementSummFreq(3); - } - else - { - cf = - 4 - + (cf >= 9 * sf ? 1 : 0) - + (cf >= 12 * sf ? 1 : 0) - + (cf >= 15 * sf ? 1 : 0); - pc.FreqData.IncrementSummFreq(cf); - } - p.Address = pc.FreqData.GetStats() + ns1 * State.SIZE; - p.SetSuccessor(successor); - p.Symbol = fs.Symbol; - p.Freq = cf; - pc.NumStats = ++ns1; - } - - int address = fs.GetSuccessor(); - _maxContext.Address = address; - _minContext.Address = address; - - //TODO-----debug - // int pos = minContext.getFreqData().getStats(); - // State a = new State(getHeap()); - // a.Address=pos); - // pos+=State.size; - // a.Address=pos); - //--dbg end - } - - // Debug - public override String ToString() - { - StringBuilder buffer = new StringBuilder(); - buffer.Append("ModelPPM["); - buffer.Append("\n numMasked="); - buffer.Append(_numMasked); - buffer.Append("\n initEsc="); - buffer.Append(_initEsc); - buffer.Append("\n orderFall="); - buffer.Append(_orderFall); - buffer.Append("\n maxOrder="); - buffer.Append(_maxOrder); - buffer.Append("\n runLength="); - buffer.Append(_runLength); - buffer.Append("\n initRL="); - buffer.Append(_initRl); - buffer.Append("\n escCount="); - buffer.Append(_escCount); - buffer.Append("\n prevSuccess="); - buffer.Append(_prevSuccess); - buffer.Append("\n foundState="); - buffer.Append(FoundState); - buffer.Append("\n coder="); - buffer.Append(Coder); - buffer.Append("\n subAlloc="); - buffer.Append(SubAlloc); - buffer.Append("\n]"); - return buffer.ToString(); - } - - // Debug - // public void dumpHeap() { - // subAlloc.dumpHeap(); - // } - - internal bool DecodeInit(Stream stream, int maxOrder, int maxMemory) - { - if (stream != null) - { - Coder = new RangeCoder(stream); - } - if (maxOrder == 1) { SubAlloc.StopSubAllocator(); return (false); } - SubAlloc.StartSubAllocator(maxMemory); + SubAlloc.StartSubAllocator((maxMb + 1) << 20); _minContext = new PpmContext(Heap); //medContext = new PPMContext(Heap); _maxContext = new PpmContext(Heap); FoundState = new State(Heap); _dummySee2Cont = new See2Context(); - for (int i = 0; i < 25; i++) + for (var i = 0; i < 25; i++) { - for (int j = 0; j < 16; j++) + for (var j = 0; j < 16; j++) { _see2Cont[i][j] = new See2Context(); } } StartModelRare(maxOrder); + } + return (_minContext.Address != 0); + } - return (_minContext.Address != 0); + public virtual int DecodeChar() + { + // Debug + //subAlloc.dumpHeap(); + + if (_minContext.Address <= SubAlloc.PText || _minContext.Address > SubAlloc.HeapEnd) + { + return (-1); } - internal void NextContext() + if (_minContext.NumStats != 1) { - int addr = FoundState.GetSuccessor(); - if (_orderFall == 0 && addr > SubAlloc.PText) + if ( + _minContext.FreqData.GetStats() <= SubAlloc.PText + || _minContext.FreqData.GetStats() > SubAlloc.HeapEnd + ) { - _minContext.Address = addr; - _maxContext.Address = addr; + return (-1); } - else + if (!_minContext.DecodeSymbol1(this)) { - UpdateModel(); + return (-1); } } - - public int DecodeChar(Decoder decoder) + else { - if (_minContext.NumStats != 1) + _minContext.DecodeBinSymbol(this); + } + Coder.Decode(); + while (FoundState.Address == 0) + { + Coder.AriDecNormalize(); + do { - State s = _tempState1.Initialize(Heap); - s.Address = _minContext.FreqData.GetStats(); - int i; - int count, - hiCnt; + _orderFall++; + _minContext.Address = _minContext.GetSuffix(); // =MinContext->Suffix; if ( - (count = (int)decoder.GetThreshold((uint)_minContext.FreqData.SummFreq)) - < (hiCnt = s.Freq) + _minContext.Address <= SubAlloc.PText + || _minContext.Address > SubAlloc.HeapEnd ) { - byte symbol; - decoder.Decode(0, (uint)s.Freq); - symbol = (byte)s.Symbol; - _minContext.update1_0(this, s.Address); - NextContext(); - return symbol; + return (-1); } - _prevSuccess = 0; - i = _minContext.NumStats - 1; - do + } while (_minContext.NumStats == _numMasked); + if (!_minContext.DecodeSymbol2(this)) + { + return (-1); + } + Coder.Decode(); + } + var symbol = FoundState.Symbol; + if ((_orderFall == 0) && FoundState.GetSuccessor() > SubAlloc.PText) + { + // MinContext=MaxContext=FoundState->Successor; + var addr = FoundState.GetSuccessor(); + _minContext.Address = addr; + _maxContext.Address = addr; + } + else + { + UpdateModel(); + + //this.foundState.Address=foundState.Address);//TODO just 4 debugging + if (_escCount == 0) + { + ClearMask(); + } + } + Coder.AriDecNormalize(); // ARI_DEC_NORMALIZE(Coder.code,Coder.low,Coder.range,Coder.UnpackRead); + return (symbol); + } + + public virtual See2Context[][] GetSee2Cont() + { + return _see2Cont; + } + + public virtual void IncEscCount(int dEscCount) + { + EscCount += dEscCount; + } + + public virtual void IncRunLength(int dRunLength) + { + RunLength += dRunLength; + } + + public virtual int[] GetHb2Flag() + { + return _hb2Flag; + } + + public virtual int[] GetNs2BsIndx() + { + return _ns2BsIndx; + } + + public virtual int[] GetNs2Indx() + { + return _ns2Indx; + } + + private int CreateSuccessors(bool skip, State p1) + { + //State upState = tempState1.Initialize(null); + var upState = _tempStateRef2; + var tempState = _tempState1.Initialize(Heap); + + // PPM_CONTEXT* pc=MinContext, * UpBranch=FoundState->Successor; + var pc = _tempPpmContext1.Initialize(Heap); + pc.Address = _minContext.Address; + var upBranch = _tempPpmContext2.Initialize(Heap); + upBranch.Address = FoundState.GetSuccessor(); + + // STATE * p, * ps[MAX_O], ** pps=ps; + var p = _tempState2.Initialize(Heap); + var pps = 0; + + var noLoop = false; + + if (!skip) + { + _ps[pps++] = FoundState.Address; // *pps++ = FoundState; + if (pc.GetSuffix() == 0) + { + noLoop = true; + } + } + if (!noLoop) + { + var loopEntry = false; + if (p1.Address != 0) + { + p.Address = p1.Address; + pc.Address = pc.GetSuffix(); // =pc->Suffix; + loopEntry = true; + } + do + { + if (!loopEntry) { - s.IncrementAddress(); - if ((hiCnt += s.Freq) > count) + pc.Address = pc.GetSuffix(); // pc=pc->Suffix; + if (pc.NumStats != 1) { - byte symbol; - decoder.Decode((uint)(hiCnt - s.Freq), (uint)s.Freq); - symbol = (byte)s.Symbol; - _minContext.Update1(this, s.Address); - NextContext(); - return symbol; + p.Address = pc.FreqData.GetStats(); // p=pc->U.Stats + if (p.Symbol != FoundState.Symbol) + { + do + { + p.IncrementAddress(); + } while (p.Symbol != FoundState.Symbol); + } } - } while (--i > 0); - if (count >= _minContext.FreqData.SummFreq) + else + { + p.Address = pc.GetOneState().Address; // p=&(pc->OneState); + } + } // LOOP_ENTRY: + loopEntry = false; + if (p.GetSuccessor() != upBranch.Address) { - return -2; + pc.Address = p.GetSuccessor(); // =p->Successor; + break; } - _hiBitsFlag = _hb2Flag[FoundState.Symbol]; - decoder.Decode((uint)hiCnt, (uint)(_minContext.FreqData.SummFreq - hiCnt)); - for (i = 0; i < 256; i++) - { - _charMask[i] = -1; - } - _charMask[s.Symbol] = 0; - i = _minContext.NumStats - 1; + _ps[pps++] = p.Address; + } while (pc.GetSuffix() != 0); + } // NO_LOOP: + if (pps == 0) + { + return pc.Address; + } + upState.Symbol = Heap[upBranch.Address]; // UpState.Symbol=*(byte*) + + // UpBranch; + // UpState.Successor=(PPM_CONTEXT*) (((byte*) UpBranch)+1); + upState.SetSuccessor(upBranch.Address + 1); //TODO check if +1 necessary + if (pc.NumStats != 1) + { + if (pc.Address <= SubAlloc.PText) + { + return (0); + } + p.Address = pc.FreqData.GetStats(); + if (p.Symbol != upState.Symbol) + { do { - s.DecrementAddress(); - _charMask[s.Symbol] = 0; - } while (--i > 0); + p.IncrementAddress(); + } while (p.Symbol != upState.Symbol); + } + var cf = p.Freq - 1; + var s0 = pc.FreqData.SummFreq - pc.NumStats - cf; + + // UpState.Freq=1+((2*cf <= s0)?(5*cf > s0):((2*cf+3*s0-1)/(2*s0))); + upState.Freq = + 1 + + ((2 * cf <= s0) ? (5 * cf > s0 ? 1 : 0) : (((2 * cf) + (3 * s0) - 1) / (2 * s0))); + } + else + { + upState.Freq = pc.GetOneState().Freq; // UpState.Freq=pc->OneState.Freq; + } + do + { + // pc = pc->createChild(this,*--pps,UpState); + tempState.Address = _ps[--pps]; + pc.Address = pc.CreateChild(this, tempState, upState); + if (pc.Address == 0) + { + return 0; + } + } while (pps != 0); + return pc.Address; + } + + private void UpdateModelRestart() + { + RestartModelRare(); + _escCount = 0; + } + + private void UpdateModel() + { + //System.out.println("ModelPPM.updateModel()"); + // STATE fs = *FoundState, *p = NULL; + var fs = _tempStateRef1; + fs.Values = FoundState; + var p = _tempState3.Initialize(Heap); + var tempState = _tempState4.Initialize(Heap); + + var pc = _tempPpmContext3.Initialize(Heap); + var successor = _tempPpmContext4.Initialize(Heap); + + int ns1, + ns, + cf, + sf, + s0; + pc.Address = _minContext.GetSuffix(); + if (fs.Freq < MAX_FREQ / 4 && pc.Address != 0) + { + if (pc.NumStats != 1) + { + p.Address = pc.FreqData.GetStats(); + if (p.Symbol != fs.Symbol) + { + do + { + p.IncrementAddress(); + } while (p.Symbol != fs.Symbol); + tempState.Address = p.Address - State.SIZE; + if (p.Freq >= tempState.Freq) + { + State.PpmdSwap(p, tempState); + p.DecrementAddress(); + } + } + if (p.Freq < MAX_FREQ - 9) + { + p.IncrementFreq(2); + pc.FreqData.IncrementSummFreq(2); + } } else { - State rs = _tempState1.Initialize(Heap); - rs.Address = _minContext.GetOneState().Address; - _hiBitsFlag = GetHb2Flag()[FoundState.Symbol]; - int off1 = rs.Freq - 1; - int off2 = _minContext.GetArrayIndex(this, rs); - int bs = _binSumm[off1][off2]; - if (decoder.DecodeBit((uint)bs, 14) == 0) + p.Address = pc.GetOneState().Address; + if (p.Freq < 32) + { + p.IncrementFreq(1); + } + } + } + if (_orderFall == 0) + { + FoundState.SetSuccessor(CreateSuccessors(true, p)); + _minContext.Address = FoundState.GetSuccessor(); + _maxContext.Address = FoundState.GetSuccessor(); + if (_minContext.Address == 0) + { + UpdateModelRestart(); + return; + } + return; + } + SubAlloc.Heap[SubAlloc.PText] = (byte)fs.Symbol; + SubAlloc.IncPText(); + successor.Address = SubAlloc.PText; + if (SubAlloc.PText >= SubAlloc.FakeUnitsStart) + { + UpdateModelRestart(); + return; + } + + // // Debug + // subAlloc.dumpHeap(); + if (fs.GetSuccessor() != 0) + { + if (fs.GetSuccessor() <= SubAlloc.PText) + { + fs.SetSuccessor(CreateSuccessors(false, p)); + if (fs.GetSuccessor() == 0) + { + UpdateModelRestart(); + return; + } + } + if (--_orderFall == 0) + { + successor.Address = fs.GetSuccessor(); + if (_maxContext.Address != _minContext.Address) + { + SubAlloc.DecPText(1); + } + } + } + else + { + FoundState.SetSuccessor(successor.Address); + fs.SetSuccessor(_minContext); + } + + // // Debug + // subAlloc.dumpHeap(); + ns = _minContext.NumStats; + s0 = _minContext.FreqData.SummFreq - (ns) - (fs.Freq - 1); + for ( + pc.Address = _maxContext.Address; + pc.Address != _minContext.Address; + pc.Address = pc.GetSuffix() + ) + { + if ((ns1 = pc.NumStats) != 1) + { + if ((ns1 & 1) == 0) + { + //System.out.println(ns1); + pc.FreqData.SetStats( + SubAlloc.ExpandUnits(pc.FreqData.GetStats(), Utility.URShift(ns1, 1)) + ); + if (pc.FreqData.GetStats() == 0) + { + UpdateModelRestart(); + return; + } + } + + // bug fixed + // int sum = ((2 * ns1 < ns) ? 1 : 0) + + // 2 * ((4 * ((ns1 <= ns) ? 1 : 0)) & ((pc.getFreqData() + // .getSummFreq() <= 8 * ns1) ? 1 : 0)); + var sum = + ((2 * ns1 < ns) ? 1 : 0) + + (2 + * ( + ((4 * ns1 <= ns) ? 1 : 0) + & ((pc.FreqData.SummFreq <= 8 * ns1) ? 1 : 0) + )); + pc.FreqData.IncrementSummFreq(sum); + } + else + { + p.Address = SubAlloc.AllocUnits(1); + if (p.Address == 0) + { + UpdateModelRestart(); + return; + } + p.SetValues(pc.GetOneState()); + pc.FreqData.SetStats(p); + if (p.Freq < (MAX_FREQ / 4) - 1) + { + p.IncrementFreq(p.Freq); + } + else + { + p.Freq = MAX_FREQ - 4; + } + pc.FreqData.SummFreq = (p.Freq + _initEsc + (ns > 3 ? 1 : 0)); + } + cf = 2 * fs.Freq * (pc.FreqData.SummFreq + 6); + sf = s0 + pc.FreqData.SummFreq; + if (cf < 6 * sf) + { + cf = 1 + (cf > sf ? 1 : 0) + (cf >= 4 * sf ? 1 : 0); + pc.FreqData.IncrementSummFreq(3); + } + else + { + cf = + 4 + + (cf >= 9 * sf ? 1 : 0) + + (cf >= 12 * sf ? 1 : 0) + + (cf >= 15 * sf ? 1 : 0); + pc.FreqData.IncrementSummFreq(cf); + } + p.Address = pc.FreqData.GetStats() + (ns1 * State.SIZE); + p.SetSuccessor(successor); + p.Symbol = fs.Symbol; + p.Freq = cf; + pc.NumStats = ++ns1; + } + + var address = fs.GetSuccessor(); + _maxContext.Address = address; + _minContext.Address = address; + + //TODO-----debug + // int pos = minContext.getFreqData().getStats(); + // State a = new State(getHeap()); + // a.Address=pos); + // pos+=State.size; + // a.Address=pos); + //--dbg end + } + + // Debug + public override string ToString() + { + var buffer = new StringBuilder(); + buffer.Append("ModelPPM["); + buffer.Append("\n numMasked="); + buffer.Append(_numMasked); + buffer.Append("\n initEsc="); + buffer.Append(_initEsc); + buffer.Append("\n orderFall="); + buffer.Append(_orderFall); + buffer.Append("\n maxOrder="); + buffer.Append(_maxOrder); + buffer.Append("\n runLength="); + buffer.Append(_runLength); + buffer.Append("\n initRL="); + buffer.Append(_initRl); + buffer.Append("\n escCount="); + buffer.Append(_escCount); + buffer.Append("\n prevSuccess="); + buffer.Append(_prevSuccess); + buffer.Append("\n foundState="); + buffer.Append(FoundState); + buffer.Append("\n coder="); + buffer.Append(Coder); + buffer.Append("\n subAlloc="); + buffer.Append(SubAlloc); + buffer.Append("\n]"); + return buffer.ToString(); + } + + // Debug + // public void dumpHeap() { + // subAlloc.dumpHeap(); + // } + + internal bool DecodeInit(Stream stream, int maxOrder, int maxMemory) + { + if (stream != null) + { + Coder = new RangeCoder(stream); + } + + if (maxOrder == 1) + { + SubAlloc.StopSubAllocator(); + return (false); + } + SubAlloc.StartSubAllocator(maxMemory); + _minContext = new PpmContext(Heap); + + //medContext = new PPMContext(Heap); + _maxContext = new PpmContext(Heap); + FoundState = new State(Heap); + _dummySee2Cont = new See2Context(); + for (var i = 0; i < 25; i++) + { + for (var j = 0; j < 16; j++) + { + _see2Cont[i][j] = new See2Context(); + } + } + StartModelRare(maxOrder); + + return (_minContext.Address != 0); + } + + internal void NextContext() + { + var addr = FoundState.GetSuccessor(); + if (_orderFall == 0 && addr > SubAlloc.PText) + { + _minContext.Address = addr; + _maxContext.Address = addr; + } + else + { + UpdateModel(); + } + } + + public int DecodeChar(Decoder decoder) + { + if (_minContext.NumStats != 1) + { + var s = _tempState1.Initialize(Heap); + s.Address = _minContext.FreqData.GetStats(); + int i; + int count, + hiCnt; + if ( + (count = (int)decoder.GetThreshold((uint)_minContext.FreqData.SummFreq)) + < (hiCnt = s.Freq) + ) + { + byte symbol; + decoder.Decode(0, (uint)s.Freq); + symbol = (byte)s.Symbol; + _minContext.update1_0(this, s.Address); + NextContext(); + return symbol; + } + _prevSuccess = 0; + i = _minContext.NumStats - 1; + do + { + s.IncrementAddress(); + if ((hiCnt += s.Freq) > count) { byte symbol; - _binSumm[off1][off2] = - (bs + INTERVAL - _minContext.GetMean(bs, PERIOD_BITS, 2)) & 0xFFFF; - FoundState.Address = rs.Address; - symbol = (byte)rs.Symbol; - rs.IncrementFreq((rs.Freq < 128) ? 1 : 0); - _prevSuccess = 1; - IncRunLength(1); + decoder.Decode((uint)(hiCnt - s.Freq), (uint)s.Freq); + symbol = (byte)s.Symbol; + _minContext.Update1(this, s.Address); NextContext(); return symbol; } - bs = (bs - _minContext.GetMean(bs, PERIOD_BITS, 2)) & 0xFFFF; - _binSumm[off1][off2] = bs; - _initEsc = PpmContext.EXP_ESCAPE[Utility.URShift(bs, 10)]; - int i; - for (i = 0; i < 256; i++) - { - _charMask[i] = -1; - } - _charMask[rs.Symbol] = 0; - _prevSuccess = 0; - } - for (; ; ) + } while (--i > 0); + if (count >= _minContext.FreqData.SummFreq) { - State s = _tempState1.Initialize(Heap); - int i; - int freqSum, - count, - hiCnt; - See2Context see; - int num, - numMasked = _minContext.NumStats; - do - { - _orderFall++; - _minContext.Address = _minContext.GetSuffix(); - if ( - _minContext.Address <= SubAlloc.PText - || _minContext.Address > SubAlloc.HeapEnd - ) - { - return -1; - } - } while (_minContext.NumStats == numMasked); - hiCnt = 0; - s.Address = _minContext.FreqData.GetStats(); - i = 0; - num = _minContext.NumStats - numMasked; - do - { - int k = _charMask[s.Symbol]; - hiCnt += s.Freq & k; - _minContext._ps[i] = s.Address; - s.IncrementAddress(); - i -= k; - } while (i != num); - - see = _minContext.MakeEscFreq(this, numMasked, out freqSum); - freqSum += hiCnt; - count = (int)decoder.GetThreshold((uint)freqSum); - - if (count < hiCnt) - { - byte symbol; - State ps = _tempState2.Initialize(Heap); - for ( - hiCnt = 0, i = 0, ps.Address = _minContext._ps[i]; - (hiCnt += ps.Freq) <= count; - i++, ps.Address = _minContext._ps[i] - ) - { - ; - } - s.Address = ps.Address; - decoder.Decode((uint)(hiCnt - s.Freq), (uint)s.Freq); - see.Update(); - symbol = (byte)s.Symbol; - _minContext.Update2(this, s.Address); - UpdateModel(); - return symbol; - } - if (count >= freqSum) - { - return -2; - } - decoder.Decode((uint)hiCnt, (uint)(freqSum - hiCnt)); - see.Summ = see.Summ + freqSum; - do - { - s.Address = _minContext._ps[--i]; - _charMask[s.Symbol] = 0; - } while (i != 0); + return -2; } + _hiBitsFlag = _hb2Flag[FoundState.Symbol]; + decoder.Decode((uint)hiCnt, (uint)(_minContext.FreqData.SummFreq - hiCnt)); + for (i = 0; i < 256; i++) + { + _charMask[i] = -1; + } + _charMask[s.Symbol] = 0; + i = _minContext.NumStats - 1; + do + { + s.DecrementAddress(); + _charMask[s.Symbol] = 0; + } while (--i > 0); + } + else + { + var rs = _tempState1.Initialize(Heap); + rs.Address = _minContext.GetOneState().Address; + _hiBitsFlag = GetHb2Flag()[FoundState.Symbol]; + var off1 = rs.Freq - 1; + var off2 = _minContext.GetArrayIndex(this, rs); + var bs = _binSumm[off1][off2]; + if (decoder.DecodeBit((uint)bs, 14) == 0) + { + byte symbol; + _binSumm[off1][off2] = + (bs + INTERVAL - _minContext.GetMean(bs, PERIOD_BITS, 2)) & 0xFFFF; + FoundState.Address = rs.Address; + symbol = (byte)rs.Symbol; + rs.IncrementFreq((rs.Freq < 128) ? 1 : 0); + _prevSuccess = 1; + IncRunLength(1); + NextContext(); + return symbol; + } + bs = (bs - _minContext.GetMean(bs, PERIOD_BITS, 2)) & 0xFFFF; + _binSumm[off1][off2] = bs; + _initEsc = PpmContext.EXP_ESCAPE[Utility.URShift(bs, 10)]; + int i; + for (i = 0; i < 256; i++) + { + _charMask[i] = -1; + } + _charMask[rs.Symbol] = 0; + _prevSuccess = 0; + } + for (; ; ) + { + var s = _tempState1.Initialize(Heap); + int i; + int count, + hiCnt; + See2Context see; + int num, + numMasked = _minContext.NumStats; + do + { + _orderFall++; + _minContext.Address = _minContext.GetSuffix(); + if ( + _minContext.Address <= SubAlloc.PText + || _minContext.Address > SubAlloc.HeapEnd + ) + { + return -1; + } + } while (_minContext.NumStats == numMasked); + hiCnt = 0; + s.Address = _minContext.FreqData.GetStats(); + i = 0; + num = _minContext.NumStats - numMasked; + do + { + var k = _charMask[s.Symbol]; + hiCnt += s.Freq & k; + _minContext._ps[i] = s.Address; + s.IncrementAddress(); + i -= k; + } while (i != num); + + see = _minContext.MakeEscFreq(this, numMasked, out var freqSum); + freqSum += hiCnt; + count = (int)decoder.GetThreshold((uint)freqSum); + + if (count < hiCnt) + { + byte symbol; + var ps = _tempState2.Initialize(Heap); + for ( + hiCnt = 0, i = 0, ps.Address = _minContext._ps[i]; + (hiCnt += ps.Freq) <= count; + i++, ps.Address = _minContext._ps[i] + ) + { + ; + } + s.Address = ps.Address; + decoder.Decode((uint)(hiCnt - s.Freq), (uint)s.Freq); + see.Update(); + symbol = (byte)s.Symbol; + _minContext.Update2(this, s.Address); + UpdateModel(); + return symbol; + } + if (count >= freqSum) + { + return -2; + } + decoder.Decode((uint)hiCnt, (uint)(freqSum - hiCnt)); + see.Summ += freqSum; + do + { + s.Address = _minContext._ps[--i]; + _charMask[s.Symbol] = 0; + } while (i != 0); } } } diff --git a/src/SharpCompress/Compressors/PPMd/H/PPMContext.cs b/src/SharpCompress/Compressors/PPMd/H/PPMContext.cs index 53d9cc7f..52768984 100644 --- a/src/SharpCompress/Compressors/PPMd/H/PPMContext.cs +++ b/src/SharpCompress/Compressors/PPMd/H/PPMContext.cs @@ -4,585 +4,581 @@ using System; using System.Buffers.Binary; using System.Text; -namespace SharpCompress.Compressors.PPMd.H +namespace SharpCompress.Compressors.PPMd.H; + +internal class PpmContext : Pointer { - internal class PpmContext : Pointer + internal FreqData FreqData { - internal FreqData FreqData + get => _freqData; + set { - get => _freqData; - set - { - _freqData.SummFreq = value.SummFreq; - _freqData.SetStats(value.GetStats()); - } - } - - public virtual int NumStats - { - get - { - if (Memory != null) - { - _numStats = - BinaryPrimitives.ReadInt16LittleEndian(Memory.AsSpan(Address)) & 0xffff; - } - return _numStats; - } - set - { - _numStats = value & 0xffff; - if (Memory != null) - { - BinaryPrimitives.WriteInt16LittleEndian(Memory.AsSpan(Address), (short)value); - } - } - } - - //UPGRADE_NOTE: Final was removed from the declaration of 'unionSize '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - //UPGRADE_NOTE: The initialization of 'unionSize' was moved to static method 'SharpCompress.Unpack.PPM.PPMContext'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1005'" - private static readonly int UNION_SIZE; - - //UPGRADE_NOTE: Final was removed from the declaration of 'size '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly int SIZE = 2 + UNION_SIZE + 4; // 12 - - // ushort NumStats; - private int _numStats; // determines if feqData or onstate is used - - // (1==onestate) - - //UPGRADE_NOTE: Final was removed from the declaration of 'freqData '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private readonly FreqData _freqData; // -\ - - // |-> union - //UPGRADE_NOTE: Final was removed from the declaration of 'oneState '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private readonly State _oneState; // -/ - - private int _suffix; // pointer ppmcontext - - //UPGRADE_NOTE: Final was removed from the declaration of 'ExpEscape'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly int[] EXP_ESCAPE = - { - 25, - 14, - 9, - 7, - 5, - 5, - 4, - 4, - 4, - 3, - 3, - 3, - 2, - 2, - 2, - 2 - }; - - // Temp fields - //UPGRADE_NOTE: Final was removed from the declaration of 'tempState1 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private readonly State _tempState1 = new State(null); - - //UPGRADE_NOTE: Final was removed from the declaration of 'tempState2 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private readonly State _tempState2 = new State(null); - - //UPGRADE_NOTE: Final was removed from the declaration of 'tempState3 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private readonly State _tempState3 = new State(null); - - //UPGRADE_NOTE: Final was removed from the declaration of 'tempState4 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private readonly State _tempState4 = new State(null); - - //UPGRADE_NOTE: Final was removed from the declaration of 'tempState5 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private readonly State _tempState5 = new State(null); - private PpmContext _tempPpmContext; - - //UPGRADE_NOTE: Final was removed from the declaration of 'ps '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - internal int[] _ps = new int[256]; - - public PpmContext(byte[] memory) : base(memory) - { - _oneState = new State(memory); - _freqData = new FreqData(memory); - } - - internal PpmContext Initialize(byte[] mem) - { - _oneState.Initialize(mem); - _freqData.Initialize(mem); - return base.Initialize(mem); - } - - internal State GetOneState() - { - return _oneState; - } - - internal void SetOneState(StateRef oneState) - { - _oneState.SetValues(oneState); - } - - internal int GetSuffix() - { - if (Memory != null) - { - _suffix = BinaryPrimitives.ReadInt32LittleEndian(Memory.AsSpan(Address + 8)); - } - return _suffix; - } - - internal void SetSuffix(PpmContext suffix) - { - SetSuffix(suffix.Address); - } - - internal void SetSuffix(int suffix) - { - _suffix = suffix; - if (Memory != null) - { - BinaryPrimitives.WriteInt32LittleEndian(Memory.AsSpan(Address + 8), suffix); - } - } - - internal override int Address - { - get => base.Address; - set - { - base.Address = value; - _oneState.Address = value + 2; - _freqData.Address = value + 2; - } - } - - private PpmContext GetTempPpmContext(byte[] memory) - { - if (_tempPpmContext is null) - { - _tempPpmContext = new PpmContext(null); - } - return _tempPpmContext.Initialize(memory); - } - - internal int CreateChild(ModelPpm model, State pStats, StateRef firstState) - { - PpmContext pc = GetTempPpmContext(model.SubAlloc.Heap); - pc.Address = model.SubAlloc.AllocContext(); - if (pc != null) - { - pc.NumStats = 1; - pc.SetOneState(firstState); - pc.SetSuffix(this); - pStats.SetSuccessor(pc); - } - return pc.Address; - } - - internal void Rescale(ModelPpm model) - { - int oldNs = NumStats, - i = NumStats - 1, - adder, - escFreq; - - // STATE* p1, * p; - State p1 = new State(model.Heap); - State p = new State(model.Heap); - State temp = new State(model.Heap); - - for ( - p.Address = model.FoundState.Address; - p.Address != _freqData.GetStats(); - p.DecrementAddress() - ) - { - temp.Address = p.Address - State.SIZE; - State.PpmdSwap(p, temp); - } - temp.Address = _freqData.GetStats(); - temp.IncrementFreq(4); - _freqData.IncrementSummFreq(4); - escFreq = _freqData.SummFreq - p.Freq; - adder = (model.OrderFall != 0) ? 1 : 0; - p.Freq = Utility.URShift((p.Freq + adder), 1); - _freqData.SummFreq = p.Freq; - do - { - p.IncrementAddress(); - escFreq -= p.Freq; - p.Freq = Utility.URShift((p.Freq + adder), 1); - _freqData.IncrementSummFreq(p.Freq); - temp.Address = p.Address - State.SIZE; - if (p.Freq > temp.Freq) - { - p1.Address = p.Address; - StateRef tmp = new StateRef(); - tmp.Values = p1; - State temp2 = new State(model.Heap); - State temp3 = new State(model.Heap); - do - { - // p1[0]=p1[-1]; - temp2.Address = p1.Address - State.SIZE; - p1.SetValues(temp2); - p1.DecrementAddress(); - temp3.Address = p1.Address - State.SIZE; - } while (p1.Address != _freqData.GetStats() && tmp.Freq > temp3.Freq); - p1.SetValues(tmp); - } - } while (--i != 0); - if (p.Freq == 0) - { - do - { - i++; - p.DecrementAddress(); - } while (p.Freq == 0); - escFreq += i; - NumStats = NumStats - i; - if (NumStats == 1) - { - StateRef tmp = new StateRef(); - temp.Address = _freqData.GetStats(); - tmp.Values = temp; - - // STATE tmp=*U.Stats; - do - { - // tmp.Freq-=(tmp.Freq >> 1) - tmp.DecrementFreq(Utility.URShift(tmp.Freq, 1)); - escFreq = Utility.URShift(escFreq, 1); - } while (escFreq > 1); - model.SubAlloc.FreeUnits(_freqData.GetStats(), Utility.URShift((oldNs + 1), 1)); - _oneState.SetValues(tmp); - model.FoundState.Address = _oneState.Address; - return; - } - } - escFreq -= Utility.URShift(escFreq, 1); - _freqData.IncrementSummFreq(escFreq); - int n0 = Utility.URShift((oldNs + 1), 1), - n1 = Utility.URShift((NumStats + 1), 1); - if (n0 != n1) - { - _freqData.SetStats(model.SubAlloc.ShrinkUnits(_freqData.GetStats(), n0, n1)); - } - model.FoundState.Address = _freqData.GetStats(); - } - - internal int GetArrayIndex(ModelPpm model, State rs) - { - PpmContext tempSuffix = GetTempPpmContext(model.SubAlloc.Heap); - tempSuffix.Address = GetSuffix(); - int ret = 0; - ret += model.PrevSuccess; - ret += model.GetNs2BsIndx()[tempSuffix.NumStats - 1]; - ret += model.HiBitsFlag + 2 * model.GetHb2Flag()[rs.Symbol]; - ret += ((Utility.URShift(model.RunLength, 26)) & 0x20); - return ret; - } - - internal int GetMean(int summ, int shift, int round) - { - return (Utility.URShift((summ + (1 << (shift - round))), (shift))); - } - - internal void DecodeBinSymbol(ModelPpm model) - { - State rs = _tempState1.Initialize(model.Heap); - rs.Address = _oneState.Address; // State& - model.HiBitsFlag = model.GetHb2Flag()[model.FoundState.Symbol]; - int off1 = rs.Freq - 1; - int off2 = GetArrayIndex(model, rs); - int bs = model.BinSumm[off1][off2]; - if (model.Coder.GetCurrentShiftCount(ModelPpm.TOT_BITS) < bs) - { - model.FoundState.Address = rs.Address; - rs.IncrementFreq((rs.Freq < 128) ? 1 : 0); - model.Coder.SubRange.LowCount = 0; - model.Coder.SubRange.HighCount = bs; - bs = ((bs + ModelPpm.INTERVAL - GetMean(bs, ModelPpm.PERIOD_BITS, 2)) & 0xffff); - model.BinSumm[off1][off2] = bs; - model.PrevSuccess = 1; - model.IncRunLength(1); - } - else - { - model.Coder.SubRange.LowCount = bs; - bs = (bs - GetMean(bs, ModelPpm.PERIOD_BITS, 2)) & 0xFFFF; - model.BinSumm[off1][off2] = bs; - model.Coder.SubRange.HighCount = ModelPpm.BIN_SCALE; - model.InitEsc = EXP_ESCAPE[Utility.URShift(bs, 10)]; - model.NumMasked = 1; - model.CharMask[rs.Symbol] = model.EscCount; - model.PrevSuccess = 0; - model.FoundState.Address = 0; - } - - //int a = 0;//TODO just 4 debugging - } - - // public static void ppmdSwap(ModelPPM model, StatePtr state1, StatePtr state2) - // { - // byte[] bytes = model.getSubAlloc().getHeap(); - // int p1 = state1.Address; - // int p2 = state2.Address; - // - // for (int i = 0; i < StatePtr.size; i++) { - // byte temp = bytes[p1+i]; - // bytes[p1+i] = bytes[p2+i]; - // bytes[p2+i] = temp; - // } - // state1.Address=p1); - // state2.Address=p2); - // } - - internal void Update1(ModelPpm model, int p) - { - model.FoundState.Address = p; - model.FoundState.IncrementFreq(4); - _freqData.IncrementSummFreq(4); - State p0 = _tempState3.Initialize(model.Heap); - State p1 = _tempState4.Initialize(model.Heap); - p0.Address = p; - p1.Address = p - State.SIZE; - if (p0.Freq > p1.Freq) - { - State.PpmdSwap(p0, p1); - model.FoundState.Address = p1.Address; - if (p1.Freq > ModelPpm.MAX_FREQ) - { - Rescale(model); - } - } - } - - internal void update1_0(ModelPpm model, int p) - { - model.FoundState.Address = p; - model.PrevSuccess = 2 * model.FoundState.Freq > _freqData.SummFreq ? 1 : 0; - model.IncRunLength(model.PrevSuccess); - _freqData.IncrementSummFreq(4); - model.FoundState.IncrementFreq(4); - if (model.FoundState.Freq > ModelPpm.MAX_FREQ) - { - Rescale(model); - } - } - - internal bool DecodeSymbol2(ModelPpm model) - { - long count; - int hiCnt, - i = NumStats - model.NumMasked; - See2Context psee2C = MakeEscFreq2(model, i); - RangeCoder coder = model.Coder; - - // STATE* ps[256], ** pps=ps, * p=U.Stats-1; - State p = _tempState1.Initialize(model.Heap); - State temp = _tempState2.Initialize(model.Heap); - p.Address = _freqData.GetStats() - State.SIZE; - int pps = 0; - hiCnt = 0; - - do - { - do - { - p.IncrementAddress(); // p++; - } while (model.CharMask[p.Symbol] == model.EscCount); - hiCnt += p.Freq; - _ps[pps++] = p.Address; - } while (--i != 0); - coder.SubRange.IncScale(hiCnt); - count = coder.CurrentCount; - if (count >= coder.SubRange.Scale) - { - return false; - } - pps = 0; - p.Address = _ps[pps]; - if (count < hiCnt) - { - hiCnt = 0; - while ((hiCnt += p.Freq) <= count) - { - p.Address = _ps[++pps]; // p=*++pps; - } - coder.SubRange.HighCount = hiCnt; - coder.SubRange.LowCount = hiCnt - p.Freq; - psee2C.Update(); - Update2(model, p.Address); - } - else - { - coder.SubRange.LowCount = hiCnt; - coder.SubRange.HighCount = coder.SubRange.Scale; - i = NumStats - model.NumMasked; // ->NumMasked; - pps--; - do - { - temp.Address = _ps[++pps]; // (*++pps) - model.CharMask[temp.Symbol] = model.EscCount; - } while (--i != 0); - psee2C.IncSumm((int)coder.SubRange.Scale); - model.NumMasked = NumStats; - } - return (true); - } - - internal void Update2(ModelPpm model, int p) - { - State temp = _tempState5.Initialize(model.Heap); - temp.Address = p; - model.FoundState.Address = p; - model.FoundState.IncrementFreq(4); - _freqData.IncrementSummFreq(4); - if (temp.Freq > ModelPpm.MAX_FREQ) - { - Rescale(model); - } - model.IncEscCount(1); - model.RunLength = model.InitRl; - } - - private See2Context MakeEscFreq2(ModelPpm model, int diff) - { - See2Context psee2C; - int numStats = NumStats; - if (numStats != 256) - { - PpmContext suff = GetTempPpmContext(model.Heap); - suff.Address = GetSuffix(); - int idx1 = model.GetNs2Indx()[diff - 1]; - int idx2 = 0; - idx2 += ((diff < suff.NumStats - numStats) ? 1 : 0); - idx2 += 2 * ((_freqData.SummFreq < 11 * numStats) ? 1 : 0); - idx2 += 4 * ((model.NumMasked > diff) ? 1 : 0); - idx2 += model.HiBitsFlag; - psee2C = model.GetSee2Cont()[idx1][idx2]; - model.Coder.SubRange.Scale = psee2C.Mean; - } - else - { - psee2C = model.DummySee2Cont; - model.Coder.SubRange.Scale = 1; - } - return psee2C; - } - - internal See2Context MakeEscFreq(ModelPpm model, int numMasked, out int escFreq) - { - See2Context psee2C; - int numStats = NumStats; - int nonMasked = numStats - numMasked; - if (numStats != 256) - { - PpmContext suff = GetTempPpmContext(model.Heap); - suff.Address = GetSuffix(); - int idx1 = model.GetNs2Indx()[nonMasked - 1]; - int idx2 = 0; - idx2 += ((nonMasked < suff.NumStats - numStats) ? 1 : 0); - idx2 += 2 * ((_freqData.SummFreq < 11 * numStats) ? 1 : 0); - idx2 += 4 * ((numMasked > nonMasked) ? 1 : 0); - idx2 += model.HiBitsFlag; - psee2C = model.GetSee2Cont()[idx1][idx2]; - escFreq = psee2C.Mean; - } - else - { - psee2C = model.DummySee2Cont; - escFreq = 1; - } - return psee2C; - } - - internal bool DecodeSymbol1(ModelPpm model) - { - RangeCoder coder = model.Coder; - coder.SubRange.Scale = _freqData.SummFreq; - State p = new State(model.Heap); - p.Address = _freqData.GetStats(); - int i, - hiCnt; - long count = coder.CurrentCount; - if (count >= coder.SubRange.Scale) - { - return false; - } - if (count < (hiCnt = p.Freq)) - { - coder.SubRange.HighCount = hiCnt; - model.PrevSuccess = (2 * hiCnt > coder.SubRange.Scale) ? 1 : 0; - model.IncRunLength(model.PrevSuccess); - hiCnt += 4; - model.FoundState.Address = p.Address; - model.FoundState.Freq = hiCnt; - _freqData.IncrementSummFreq(4); - if (hiCnt > ModelPpm.MAX_FREQ) - { - Rescale(model); - } - coder.SubRange.LowCount = 0; - return true; - } - if (model.FoundState.Address == 0) - { - return (false); - } - model.PrevSuccess = 0; - int numStats = NumStats; - i = numStats - 1; - while ((hiCnt += p.IncrementAddress().Freq) <= count) - { - if (--i == 0) - { - model.HiBitsFlag = model.GetHb2Flag()[model.FoundState.Symbol]; - coder.SubRange.LowCount = hiCnt; - model.CharMask[p.Symbol] = model.EscCount; - model.NumMasked = numStats; - i = numStats - 1; - model.FoundState.Address = 0; - do - { - model.CharMask[p.DecrementAddress().Symbol] = model.EscCount; - } while (--i != 0); - coder.SubRange.HighCount = coder.SubRange.Scale; - return (true); - } - } - coder.SubRange.LowCount = hiCnt - p.Freq; - coder.SubRange.HighCount = hiCnt; - Update1(model, p.Address); - return (true); - } - - public override String ToString() - { - StringBuilder buffer = new StringBuilder(); - buffer.Append("PPMContext["); - buffer.Append("\n Address="); - buffer.Append(Address); - buffer.Append("\n size="); - buffer.Append(SIZE); - buffer.Append("\n numStats="); - buffer.Append(NumStats); - buffer.Append("\n Suffix="); - buffer.Append(GetSuffix()); - buffer.Append("\n freqData="); - buffer.Append(_freqData); - buffer.Append("\n oneState="); - buffer.Append(_oneState); - buffer.Append("\n]"); - return buffer.ToString(); - } - - static PpmContext() - { - UNION_SIZE = Math.Max(FreqData.SIZE, State.SIZE); + _freqData.SummFreq = value.SummFreq; + _freqData.SetStats(value.GetStats()); } } + + public virtual int NumStats + { + get + { + if (Memory != null) + { + _numStats = + BinaryPrimitives.ReadInt16LittleEndian(Memory.AsSpan(Address)) & 0xffff; + } + return _numStats; + } + set + { + _numStats = value & 0xffff; + if (Memory != null) + { + BinaryPrimitives.WriteInt16LittleEndian(Memory.AsSpan(Address), (short)value); + } + } + } + + //UPGRADE_NOTE: Final was removed from the declaration of 'unionSize '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + //UPGRADE_NOTE: The initialization of 'unionSize' was moved to static method 'SharpCompress.Unpack.PPM.PPMContext'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1005'" + private static readonly int UNION_SIZE; + + //UPGRADE_NOTE: Final was removed from the declaration of 'size '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + public static readonly int SIZE = 2 + UNION_SIZE + 4; // 12 + + // ushort NumStats; + private int _numStats; // determines if feqData or onstate is used + + // (1==onestate) + + //UPGRADE_NOTE: Final was removed from the declaration of 'freqData '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + private readonly FreqData _freqData; // -\ + + // |-> union + //UPGRADE_NOTE: Final was removed from the declaration of 'oneState '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + private readonly State _oneState; // -/ + + private int _suffix; // pointer ppmcontext + + //UPGRADE_NOTE: Final was removed from the declaration of 'ExpEscape'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + public static readonly int[] EXP_ESCAPE = + { + 25, + 14, + 9, + 7, + 5, + 5, + 4, + 4, + 4, + 3, + 3, + 3, + 2, + 2, + 2, + 2 + }; + + // Temp fields + //UPGRADE_NOTE: Final was removed from the declaration of 'tempState1 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + private readonly State _tempState1 = new State(null); + + //UPGRADE_NOTE: Final was removed from the declaration of 'tempState2 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + private readonly State _tempState2 = new State(null); + + //UPGRADE_NOTE: Final was removed from the declaration of 'tempState3 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + private readonly State _tempState3 = new State(null); + + //UPGRADE_NOTE: Final was removed from the declaration of 'tempState4 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + private readonly State _tempState4 = new State(null); + + //UPGRADE_NOTE: Final was removed from the declaration of 'tempState5 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + private readonly State _tempState5 = new State(null); + private PpmContext _tempPpmContext; + + //UPGRADE_NOTE: Final was removed from the declaration of 'ps '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + internal int[] _ps = new int[256]; + + public PpmContext(byte[] memory) : base(memory) + { + _oneState = new State(memory); + _freqData = new FreqData(memory); + } + + internal PpmContext Initialize(byte[] mem) + { + _oneState.Initialize(mem); + _freqData.Initialize(mem); + return Initialize(mem); + } + + internal State GetOneState() + { + return _oneState; + } + + internal void SetOneState(StateRef oneState) + { + _oneState.SetValues(oneState); + } + + internal int GetSuffix() + { + if (Memory != null) + { + _suffix = BinaryPrimitives.ReadInt32LittleEndian(Memory.AsSpan(Address + 8)); + } + return _suffix; + } + + internal void SetSuffix(PpmContext suffix) + { + SetSuffix(suffix.Address); + } + + internal void SetSuffix(int suffix) + { + _suffix = suffix; + if (Memory != null) + { + BinaryPrimitives.WriteInt32LittleEndian(Memory.AsSpan(Address + 8), suffix); + } + } + + internal override int Address + { + get => base.Address; + set + { + base.Address = value; + _oneState.Address = value + 2; + _freqData.Address = value + 2; + } + } + + private PpmContext GetTempPpmContext(byte[] memory) + { + _tempPpmContext ??= new PpmContext(null); + return _tempPpmContext.Initialize(memory); + } + + internal int CreateChild(ModelPpm model, State pStats, StateRef firstState) + { + var pc = GetTempPpmContext(model.SubAlloc.Heap); + pc.Address = model.SubAlloc.AllocContext(); + if (pc != null) + { + pc.NumStats = 1; + pc.SetOneState(firstState); + pc.SetSuffix(this); + pStats.SetSuccessor(pc); + } + return pc.Address; + } + + internal void Rescale(ModelPpm model) + { + int oldNs = NumStats, + i = NumStats - 1, + adder, + escFreq; + + // STATE* p1, * p; + var p1 = new State(model.Heap); + var p = new State(model.Heap); + var temp = new State(model.Heap); + + for ( + p.Address = model.FoundState.Address; + p.Address != _freqData.GetStats(); + p.DecrementAddress() + ) + { + temp.Address = p.Address - State.SIZE; + State.PpmdSwap(p, temp); + } + temp.Address = _freqData.GetStats(); + temp.IncrementFreq(4); + _freqData.IncrementSummFreq(4); + escFreq = _freqData.SummFreq - p.Freq; + adder = (model.OrderFall != 0) ? 1 : 0; + p.Freq = Utility.URShift((p.Freq + adder), 1); + _freqData.SummFreq = p.Freq; + do + { + p.IncrementAddress(); + escFreq -= p.Freq; + p.Freq = Utility.URShift((p.Freq + adder), 1); + _freqData.IncrementSummFreq(p.Freq); + temp.Address = p.Address - State.SIZE; + if (p.Freq > temp.Freq) + { + p1.Address = p.Address; + var tmp = new StateRef(); + tmp.Values = p1; + var temp2 = new State(model.Heap); + var temp3 = new State(model.Heap); + do + { + // p1[0]=p1[-1]; + temp2.Address = p1.Address - State.SIZE; + p1.SetValues(temp2); + p1.DecrementAddress(); + temp3.Address = p1.Address - State.SIZE; + } while (p1.Address != _freqData.GetStats() && tmp.Freq > temp3.Freq); + p1.SetValues(tmp); + } + } while (--i != 0); + if (p.Freq == 0) + { + do + { + i++; + p.DecrementAddress(); + } while (p.Freq == 0); + escFreq += i; + NumStats -= i; + if (NumStats == 1) + { + var tmp = new StateRef(); + temp.Address = _freqData.GetStats(); + tmp.Values = temp; + + // STATE tmp=*U.Stats; + do + { + // tmp.Freq-=(tmp.Freq >> 1) + tmp.DecrementFreq(Utility.URShift(tmp.Freq, 1)); + escFreq = Utility.URShift(escFreq, 1); + } while (escFreq > 1); + model.SubAlloc.FreeUnits(_freqData.GetStats(), Utility.URShift((oldNs + 1), 1)); + _oneState.SetValues(tmp); + model.FoundState.Address = _oneState.Address; + return; + } + } + escFreq -= Utility.URShift(escFreq, 1); + _freqData.IncrementSummFreq(escFreq); + int n0 = Utility.URShift((oldNs + 1), 1), + n1 = Utility.URShift((NumStats + 1), 1); + if (n0 != n1) + { + _freqData.SetStats(model.SubAlloc.ShrinkUnits(_freqData.GetStats(), n0, n1)); + } + model.FoundState.Address = _freqData.GetStats(); + } + + internal int GetArrayIndex(ModelPpm model, State rs) + { + var tempSuffix = GetTempPpmContext(model.SubAlloc.Heap); + tempSuffix.Address = GetSuffix(); + var ret = 0; + ret += model.PrevSuccess; + ret += model.GetNs2BsIndx()[tempSuffix.NumStats - 1]; + ret += model.HiBitsFlag + (2 * model.GetHb2Flag()[rs.Symbol]); + ret += ((Utility.URShift(model.RunLength, 26)) & 0x20); + return ret; + } + + internal int GetMean(int summ, int shift, int round) + { + return (Utility.URShift((summ + (1 << (shift - round))), (shift))); + } + + internal void DecodeBinSymbol(ModelPpm model) + { + var rs = _tempState1.Initialize(model.Heap); + rs.Address = _oneState.Address; // State& + model.HiBitsFlag = model.GetHb2Flag()[model.FoundState.Symbol]; + var off1 = rs.Freq - 1; + var off2 = GetArrayIndex(model, rs); + var bs = model.BinSumm[off1][off2]; + if (model.Coder.GetCurrentShiftCount(ModelPpm.TOT_BITS) < bs) + { + model.FoundState.Address = rs.Address; + rs.IncrementFreq((rs.Freq < 128) ? 1 : 0); + model.Coder.SubRange.LowCount = 0; + model.Coder.SubRange.HighCount = bs; + bs = ((bs + ModelPpm.INTERVAL - GetMean(bs, ModelPpm.PERIOD_BITS, 2)) & 0xffff); + model.BinSumm[off1][off2] = bs; + model.PrevSuccess = 1; + model.IncRunLength(1); + } + else + { + model.Coder.SubRange.LowCount = bs; + bs = (bs - GetMean(bs, ModelPpm.PERIOD_BITS, 2)) & 0xFFFF; + model.BinSumm[off1][off2] = bs; + model.Coder.SubRange.HighCount = ModelPpm.BIN_SCALE; + model.InitEsc = EXP_ESCAPE[Utility.URShift(bs, 10)]; + model.NumMasked = 1; + model.CharMask[rs.Symbol] = model.EscCount; + model.PrevSuccess = 0; + model.FoundState.Address = 0; + } + + //int a = 0;//TODO just 4 debugging + } + + // public static void ppmdSwap(ModelPPM model, StatePtr state1, StatePtr state2) + // { + // byte[] bytes = model.getSubAlloc().getHeap(); + // int p1 = state1.Address; + // int p2 = state2.Address; + // + // for (int i = 0; i < StatePtr.size; i++) { + // byte temp = bytes[p1+i]; + // bytes[p1+i] = bytes[p2+i]; + // bytes[p2+i] = temp; + // } + // state1.Address=p1); + // state2.Address=p2); + // } + + internal void Update1(ModelPpm model, int p) + { + model.FoundState.Address = p; + model.FoundState.IncrementFreq(4); + _freqData.IncrementSummFreq(4); + var p0 = _tempState3.Initialize(model.Heap); + var p1 = _tempState4.Initialize(model.Heap); + p0.Address = p; + p1.Address = p - State.SIZE; + if (p0.Freq > p1.Freq) + { + State.PpmdSwap(p0, p1); + model.FoundState.Address = p1.Address; + if (p1.Freq > ModelPpm.MAX_FREQ) + { + Rescale(model); + } + } + } + + internal void update1_0(ModelPpm model, int p) + { + model.FoundState.Address = p; + model.PrevSuccess = 2 * model.FoundState.Freq > _freqData.SummFreq ? 1 : 0; + model.IncRunLength(model.PrevSuccess); + _freqData.IncrementSummFreq(4); + model.FoundState.IncrementFreq(4); + if (model.FoundState.Freq > ModelPpm.MAX_FREQ) + { + Rescale(model); + } + } + + internal bool DecodeSymbol2(ModelPpm model) + { + long count; + int hiCnt, + i = NumStats - model.NumMasked; + var psee2C = MakeEscFreq2(model, i); + var coder = model.Coder; + + // STATE* ps[256], ** pps=ps, * p=U.Stats-1; + var p = _tempState1.Initialize(model.Heap); + var temp = _tempState2.Initialize(model.Heap); + p.Address = _freqData.GetStats() - State.SIZE; + var pps = 0; + hiCnt = 0; + + do + { + do + { + p.IncrementAddress(); // p++; + } while (model.CharMask[p.Symbol] == model.EscCount); + hiCnt += p.Freq; + _ps[pps++] = p.Address; + } while (--i != 0); + coder.SubRange.IncScale(hiCnt); + count = coder.CurrentCount; + if (count >= coder.SubRange.Scale) + { + return false; + } + pps = 0; + p.Address = _ps[pps]; + if (count < hiCnt) + { + hiCnt = 0; + while ((hiCnt += p.Freq) <= count) + { + p.Address = _ps[++pps]; // p=*++pps; + } + coder.SubRange.HighCount = hiCnt; + coder.SubRange.LowCount = hiCnt - p.Freq; + psee2C.Update(); + Update2(model, p.Address); + } + else + { + coder.SubRange.LowCount = hiCnt; + coder.SubRange.HighCount = coder.SubRange.Scale; + i = NumStats - model.NumMasked; // ->NumMasked; + pps--; + do + { + temp.Address = _ps[++pps]; // (*++pps) + model.CharMask[temp.Symbol] = model.EscCount; + } while (--i != 0); + psee2C.IncSumm((int)coder.SubRange.Scale); + model.NumMasked = NumStats; + } + return (true); + } + + internal void Update2(ModelPpm model, int p) + { + var temp = _tempState5.Initialize(model.Heap); + temp.Address = p; + model.FoundState.Address = p; + model.FoundState.IncrementFreq(4); + _freqData.IncrementSummFreq(4); + if (temp.Freq > ModelPpm.MAX_FREQ) + { + Rescale(model); + } + model.IncEscCount(1); + model.RunLength = model.InitRl; + } + + private See2Context MakeEscFreq2(ModelPpm model, int diff) + { + See2Context psee2C; + var numStats = NumStats; + if (numStats != 256) + { + var suff = GetTempPpmContext(model.Heap); + suff.Address = GetSuffix(); + var idx1 = model.GetNs2Indx()[diff - 1]; + var idx2 = 0; + idx2 += ((diff < suff.NumStats - numStats) ? 1 : 0); + idx2 += 2 * ((_freqData.SummFreq < 11 * numStats) ? 1 : 0); + idx2 += 4 * ((model.NumMasked > diff) ? 1 : 0); + idx2 += model.HiBitsFlag; + psee2C = model.GetSee2Cont()[idx1][idx2]; + model.Coder.SubRange.Scale = psee2C.Mean; + } + else + { + psee2C = model.DummySee2Cont; + model.Coder.SubRange.Scale = 1; + } + return psee2C; + } + + internal See2Context MakeEscFreq(ModelPpm model, int numMasked, out int escFreq) + { + See2Context psee2C; + var numStats = NumStats; + var nonMasked = numStats - numMasked; + if (numStats != 256) + { + var suff = GetTempPpmContext(model.Heap); + suff.Address = GetSuffix(); + var idx1 = model.GetNs2Indx()[nonMasked - 1]; + var idx2 = 0; + idx2 += ((nonMasked < suff.NumStats - numStats) ? 1 : 0); + idx2 += 2 * ((_freqData.SummFreq < 11 * numStats) ? 1 : 0); + idx2 += 4 * ((numMasked > nonMasked) ? 1 : 0); + idx2 += model.HiBitsFlag; + psee2C = model.GetSee2Cont()[idx1][idx2]; + escFreq = psee2C.Mean; + } + else + { + psee2C = model.DummySee2Cont; + escFreq = 1; + } + return psee2C; + } + + internal bool DecodeSymbol1(ModelPpm model) + { + var coder = model.Coder; + coder.SubRange.Scale = _freqData.SummFreq; + var p = new State(model.Heap); + p.Address = _freqData.GetStats(); + int i, + hiCnt; + long count = coder.CurrentCount; + if (count >= coder.SubRange.Scale) + { + return false; + } + if (count < (hiCnt = p.Freq)) + { + coder.SubRange.HighCount = hiCnt; + model.PrevSuccess = (2 * hiCnt > coder.SubRange.Scale) ? 1 : 0; + model.IncRunLength(model.PrevSuccess); + hiCnt += 4; + model.FoundState.Address = p.Address; + model.FoundState.Freq = hiCnt; + _freqData.IncrementSummFreq(4); + if (hiCnt > ModelPpm.MAX_FREQ) + { + Rescale(model); + } + coder.SubRange.LowCount = 0; + return true; + } + if (model.FoundState.Address == 0) + { + return (false); + } + model.PrevSuccess = 0; + var numStats = NumStats; + i = numStats - 1; + while ((hiCnt += p.IncrementAddress().Freq) <= count) + { + if (--i == 0) + { + model.HiBitsFlag = model.GetHb2Flag()[model.FoundState.Symbol]; + coder.SubRange.LowCount = hiCnt; + model.CharMask[p.Symbol] = model.EscCount; + model.NumMasked = numStats; + i = numStats - 1; + model.FoundState.Address = 0; + do + { + model.CharMask[p.DecrementAddress().Symbol] = model.EscCount; + } while (--i != 0); + coder.SubRange.HighCount = coder.SubRange.Scale; + return (true); + } + } + coder.SubRange.LowCount = hiCnt - p.Freq; + coder.SubRange.HighCount = hiCnt; + Update1(model, p.Address); + return (true); + } + + public override string ToString() + { + var buffer = new StringBuilder(); + buffer.Append("PPMContext["); + buffer.Append("\n Address="); + buffer.Append(Address); + buffer.Append("\n size="); + buffer.Append(SIZE); + buffer.Append("\n numStats="); + buffer.Append(NumStats); + buffer.Append("\n Suffix="); + buffer.Append(GetSuffix()); + buffer.Append("\n freqData="); + buffer.Append(_freqData); + buffer.Append("\n oneState="); + buffer.Append(_oneState); + buffer.Append("\n]"); + return buffer.ToString(); + } + + static PpmContext() + { + UNION_SIZE = Math.Max(FreqData.SIZE, State.SIZE); + } } diff --git a/src/SharpCompress/Compressors/PPMd/H/Pointer.cs b/src/SharpCompress/Compressors/PPMd/H/Pointer.cs index 40a15c30..b7f04d48 100644 --- a/src/SharpCompress/Compressors/PPMd/H/Pointer.cs +++ b/src/SharpCompress/Compressors/PPMd/H/Pointer.cs @@ -1,26 +1,25 @@ #nullable disable -namespace SharpCompress.Compressors.PPMd.H +namespace SharpCompress.Compressors.PPMd.H; + +internal abstract class Pointer { - internal abstract class Pointer + /// Initialize the object with the array (may be null) + /// the byte array + /// + internal Pointer(byte[] mem) { - /// Initialize the object with the array (may be null) - /// the byte array - /// - internal Pointer(byte[] mem) - { - Memory = mem; - } + Memory = mem; + } - internal byte[] Memory { get; private set; } + internal byte[] Memory { get; private set; } - internal virtual int Address { get; set; } + internal virtual int Address { get; set; } - protected T Initialize(byte[] mem) where T : Pointer - { - Memory = mem; - Address = 0; - return this as T; - } + protected T Initialize(byte[] mem) where T : Pointer + { + Memory = mem; + Address = 0; + return this as T; } } diff --git a/src/SharpCompress/Compressors/PPMd/H/RangeCoder.cs b/src/SharpCompress/Compressors/PPMd/H/RangeCoder.cs index 1d87849b..67f437ad 100644 --- a/src/SharpCompress/Compressors/PPMd/H/RangeCoder.cs +++ b/src/SharpCompress/Compressors/PPMd/H/RangeCoder.cs @@ -1,173 +1,171 @@ #nullable disable -using System; using System.IO; using System.Text; using SharpCompress.Compressors.Rar; -namespace SharpCompress.Compressors.PPMd.H +namespace SharpCompress.Compressors.PPMd.H; + +internal class RangeCoder { - internal class RangeCoder + internal const int TOP = 1 << 24; + internal const int BOT = 1 << 15; + internal const long UINT_MASK = 0xFFFFffffL; + + // uint low, code, range; + private long _low, + _code, + _range; + private readonly IRarUnpack _unpackRead; + private readonly Stream _stream; + + internal RangeCoder(IRarUnpack unpackRead) { - internal const int TOP = 1 << 24; - internal const int BOT = 1 << 15; - internal const long UINT_MASK = 0xFFFFffffL; + _unpackRead = unpackRead; + Init(); + } - // uint low, code, range; - private long _low, - _code, - _range; - private readonly IRarUnpack _unpackRead; - private readonly Stream _stream; + internal RangeCoder(Stream stream) + { + _stream = stream; + Init(); + } - internal RangeCoder(IRarUnpack unpackRead) + private void Init() + { + SubRange = new SubRange(); + + _low = _code = 0L; + _range = 0xFFFFffffL; + for (var i = 0; i < 4; i++) { - _unpackRead = unpackRead; - Init(); - } - - internal RangeCoder(Stream stream) - { - _stream = stream; - Init(); - } - - private void Init() - { - SubRange = new SubRange(); - - _low = _code = 0L; - _range = 0xFFFFffffL; - for (int i = 0; i < 4; i++) - { - _code = ((_code << 8) | Char) & UINT_MASK; - } - } - - internal int CurrentCount - { - get - { - _range = (_range / SubRange.Scale) & UINT_MASK; - return (int)((_code - _low) / (_range)); - } - } - - private long Char - { - get - { - if (_unpackRead != null) - { - return (_unpackRead.Char); - } - if (_stream != null) - { - return _stream.ReadByte(); - } - return -1; - } - } - - internal SubRange SubRange { get; private set; } - - internal long GetCurrentShiftCount(int shift) - { - _range = Utility.URShift(_range, shift); - return ((_code - _low) / (_range)) & UINT_MASK; - } - - internal void Decode() - { - _low = (_low + (_range * SubRange.LowCount)) & UINT_MASK; - _range = (_range * (SubRange.HighCount - SubRange.LowCount)) & UINT_MASK; - } - - internal void AriDecNormalize() - { - // while ((low ^ (low + range)) < TOP || range < BOT && ((range = -low & (BOT - 1)) != 0 ? true : true)) - // { - // code = ((code << 8) | unpackRead.getChar()&0xff)&uintMask; - // range = (range << 8)&uintMask; - // low = (low << 8)&uintMask; - // } - - // Rewrote for clarity - bool c2 = false; - while ((_low ^ (_low + _range)) < TOP || (c2 = _range < BOT)) - { - if (c2) - { - _range = (-_low & (BOT - 1)) & UINT_MASK; - c2 = false; - } - _code = ((_code << 8) | Char) & UINT_MASK; - _range = (_range << 8) & UINT_MASK; - _low = (_low << 8) & UINT_MASK; - } - } - - // Debug - public override String ToString() - { - StringBuilder buffer = new StringBuilder(); - buffer.Append("RangeCoder["); - buffer.Append("\n low="); - buffer.Append(_low); - buffer.Append("\n code="); - buffer.Append(_code); - buffer.Append("\n range="); - buffer.Append(_range); - buffer.Append("\n subrange="); - buffer.Append(SubRange); - buffer.Append(']'); - return buffer.ToString(); + _code = ((_code << 8) | Char) & UINT_MASK; } } - internal class SubRange + internal int CurrentCount { - // uint LowCount, HighCount, scale; - private long _lowCount, - _highCount, - _scale; - - internal void IncScale(int dScale) + get { - Scale = Scale + dScale; + _range = (_range / SubRange.Scale) & UINT_MASK; + return (int)((_code - _low) / (_range)); } + } - internal long HighCount + private long Char + { + get { - get => _highCount; - set => _highCount = value & RangeCoder.UINT_MASK; + if (_unpackRead != null) + { + return (_unpackRead.Char); + } + if (_stream != null) + { + return _stream.ReadByte(); + } + return -1; } + } - internal long LowCount - { - get => _lowCount & RangeCoder.UINT_MASK; - set => _lowCount = value & RangeCoder.UINT_MASK; - } + internal SubRange SubRange { get; private set; } - internal long Scale - { - get => _scale; - set => _scale = value & RangeCoder.UINT_MASK; - } + internal long GetCurrentShiftCount(int shift) + { + _range = Utility.URShift(_range, shift); + return ((_code - _low) / (_range)) & UINT_MASK; + } - // Debug - public override String ToString() + internal void Decode() + { + _low = (_low + (_range * SubRange.LowCount)) & UINT_MASK; + _range = (_range * (SubRange.HighCount - SubRange.LowCount)) & UINT_MASK; + } + + internal void AriDecNormalize() + { + // while ((low ^ (low + range)) < TOP || range < BOT && ((range = -low & (BOT - 1)) != 0 ? true : true)) + // { + // code = ((code << 8) | unpackRead.getChar()&0xff)&uintMask; + // range = (range << 8)&uintMask; + // low = (low << 8)&uintMask; + // } + + // Rewrote for clarity + var c2 = false; + while ((_low ^ (_low + _range)) < TOP || (c2 = _range < BOT)) { - StringBuilder buffer = new StringBuilder(); - buffer.Append("SubRange["); - buffer.Append("\n lowCount="); - buffer.Append(_lowCount); - buffer.Append("\n highCount="); - buffer.Append(_highCount); - buffer.Append("\n scale="); - buffer.Append(_scale); - buffer.Append(']'); - return buffer.ToString(); + if (c2) + { + _range = (-_low & (BOT - 1)) & UINT_MASK; + c2 = false; + } + _code = ((_code << 8) | Char) & UINT_MASK; + _range = (_range << 8) & UINT_MASK; + _low = (_low << 8) & UINT_MASK; } } + + // Debug + public override string ToString() + { + var buffer = new StringBuilder(); + buffer.Append("RangeCoder["); + buffer.Append("\n low="); + buffer.Append(_low); + buffer.Append("\n code="); + buffer.Append(_code); + buffer.Append("\n range="); + buffer.Append(_range); + buffer.Append("\n subrange="); + buffer.Append(SubRange); + buffer.Append(']'); + return buffer.ToString(); + } +} + +internal class SubRange +{ + // uint LowCount, HighCount, scale; + private long _lowCount, + _highCount, + _scale; + + internal void IncScale(int dScale) + { + Scale += dScale; + } + + internal long HighCount + { + get => _highCount; + set => _highCount = value & RangeCoder.UINT_MASK; + } + + internal long LowCount + { + get => _lowCount & RangeCoder.UINT_MASK; + set => _lowCount = value & RangeCoder.UINT_MASK; + } + + internal long Scale + { + get => _scale; + set => _scale = value & RangeCoder.UINT_MASK; + } + + // Debug + public override string ToString() + { + var buffer = new StringBuilder(); + buffer.Append("SubRange["); + buffer.Append("\n lowCount="); + buffer.Append(_lowCount); + buffer.Append("\n highCount="); + buffer.Append(_highCount); + buffer.Append("\n scale="); + buffer.Append(_scale); + buffer.Append(']'); + return buffer.ToString(); + } } diff --git a/src/SharpCompress/Compressors/PPMd/H/RarMemBlock.cs b/src/SharpCompress/Compressors/PPMd/H/RarMemBlock.cs index b067fac8..f3f7b147 100644 --- a/src/SharpCompress/Compressors/PPMd/H/RarMemBlock.cs +++ b/src/SharpCompress/Compressors/PPMd/H/RarMemBlock.cs @@ -1,126 +1,125 @@ using System; using System.Buffers.Binary; -namespace SharpCompress.Compressors.PPMd.H +namespace SharpCompress.Compressors.PPMd.H; + +internal class RarMemBlock : Pointer { - internal class RarMemBlock : Pointer + public const int SIZE = 12; + + private int _stamp, + _nu; + + private int _next, + _prev; // Pointer RarMemBlock + + public RarMemBlock(byte[] memory) : base(memory) { } + + internal int Stamp { - public const int SIZE = 12; - - private int _stamp, - _nu; - - private int _next, - _prev; // Pointer RarMemBlock - - public RarMemBlock(byte[] memory) : base(memory) { } - - internal int Stamp - { - get - { - if (Memory != null) - { - _stamp = - BinaryPrimitives.ReadInt16LittleEndian(Memory.AsSpan(Address)) & 0xffff; - } - return _stamp; - } - set - { - _stamp = value; - if (Memory != null) - { - BinaryPrimitives.WriteInt16LittleEndian(Memory.AsSpan(Address), (short)value); - } - } - } - - internal void InsertAt(RarMemBlock p) - { - RarMemBlock temp = new RarMemBlock(Memory); - SetPrev(p.Address); - temp.Address = GetPrev(); - SetNext(temp.GetNext()); // prev.getNext(); - temp.SetNext(this); // prev.setNext(this); - temp.Address = GetNext(); - temp.SetPrev(this); // next.setPrev(this); - } - - internal void Remove() - { - RarMemBlock temp = new RarMemBlock(Memory); - temp.Address = GetPrev(); - temp.SetNext(GetNext()); // prev.setNext(next); - temp.Address = GetNext(); - temp.SetPrev(GetPrev()); // next.setPrev(prev); - - // next = -1; - // prev = -1; - } - - internal int GetNext() + get { if (Memory != null) { - _next = BinaryPrimitives.ReadInt32LittleEndian(Memory.AsSpan(Address + 4)); + _stamp = + BinaryPrimitives.ReadInt16LittleEndian(Memory.AsSpan(Address)) & 0xffff; } - return _next; + return _stamp; } - - internal void SetNext(RarMemBlock next) + set { - SetNext(next.Address); - } - - internal void SetNext(int next) - { - _next = next; + _stamp = value; if (Memory != null) { - BinaryPrimitives.WriteInt32LittleEndian(Memory.AsSpan(Address + 4), next); - } - } - - internal int GetNu() - { - if (Memory != null) - { - _nu = BinaryPrimitives.ReadInt16LittleEndian(Memory.AsSpan(Address + 2)) & 0xffff; - } - return _nu; - } - - internal void SetNu(int nu) - { - _nu = nu & 0xffff; - if (Memory != null) - { - BinaryPrimitives.WriteInt16LittleEndian(Memory.AsSpan(Address + 2), (short)nu); - } - } - - internal int GetPrev() - { - if (Memory != null) - { - _prev = BinaryPrimitives.ReadInt32LittleEndian(Memory.AsSpan(Address + 8)); - } - return _prev; - } - - internal void SetPrev(RarMemBlock prev) - { - SetPrev(prev.Address); - } - - internal void SetPrev(int prev) - { - _prev = prev; - if (Memory != null) - { - BinaryPrimitives.WriteInt32LittleEndian(Memory.AsSpan(Address + 8), prev); + BinaryPrimitives.WriteInt16LittleEndian(Memory.AsSpan(Address), (short)value); } } } + + internal void InsertAt(RarMemBlock p) + { + var temp = new RarMemBlock(Memory); + SetPrev(p.Address); + temp.Address = GetPrev(); + SetNext(temp.GetNext()); // prev.getNext(); + temp.SetNext(this); // prev.setNext(this); + temp.Address = GetNext(); + temp.SetPrev(this); // next.setPrev(this); + } + + internal void Remove() + { + var temp = new RarMemBlock(Memory); + temp.Address = GetPrev(); + temp.SetNext(GetNext()); // prev.setNext(next); + temp.Address = GetNext(); + temp.SetPrev(GetPrev()); // next.setPrev(prev); + + // next = -1; + // prev = -1; + } + + internal int GetNext() + { + if (Memory != null) + { + _next = BinaryPrimitives.ReadInt32LittleEndian(Memory.AsSpan(Address + 4)); + } + return _next; + } + + internal void SetNext(RarMemBlock next) + { + SetNext(next.Address); + } + + internal void SetNext(int next) + { + _next = next; + if (Memory != null) + { + BinaryPrimitives.WriteInt32LittleEndian(Memory.AsSpan(Address + 4), next); + } + } + + internal int GetNu() + { + if (Memory != null) + { + _nu = BinaryPrimitives.ReadInt16LittleEndian(Memory.AsSpan(Address + 2)) & 0xffff; + } + return _nu; + } + + internal void SetNu(int nu) + { + _nu = nu & 0xffff; + if (Memory != null) + { + BinaryPrimitives.WriteInt16LittleEndian(Memory.AsSpan(Address + 2), (short)nu); + } + } + + internal int GetPrev() + { + if (Memory != null) + { + _prev = BinaryPrimitives.ReadInt32LittleEndian(Memory.AsSpan(Address + 8)); + } + return _prev; + } + + internal void SetPrev(RarMemBlock prev) + { + SetPrev(prev.Address); + } + + internal void SetPrev(int prev) + { + _prev = prev; + if (Memory != null) + { + BinaryPrimitives.WriteInt32LittleEndian(Memory.AsSpan(Address + 8), prev); + } + } } diff --git a/src/SharpCompress/Compressors/PPMd/H/RarNode.cs b/src/SharpCompress/Compressors/PPMd/H/RarNode.cs index 15775229..5a9e5a29 100644 --- a/src/SharpCompress/Compressors/PPMd/H/RarNode.cs +++ b/src/SharpCompress/Compressors/PPMd/H/RarNode.cs @@ -2,51 +2,50 @@ using System; using System.Buffers.Binary; using System.Text; -namespace SharpCompress.Compressors.PPMd.H +namespace SharpCompress.Compressors.PPMd.H; + +internal class RarNode : Pointer { - internal class RarNode : Pointer + private int _next; //rarnode pointer + + public const int SIZE = 4; + + public RarNode(byte[] memory) : base(memory) { } + + internal int GetNext() { - private int _next; //rarnode pointer - - public const int SIZE = 4; - - public RarNode(byte[] memory) : base(memory) { } - - internal int GetNext() + if (Memory != null) { - if (Memory != null) - { - _next = BinaryPrimitives.ReadInt32LittleEndian(Memory.AsSpan(Address)); - } - return _next; + _next = BinaryPrimitives.ReadInt32LittleEndian(Memory.AsSpan(Address)); } + return _next; + } - internal void SetNext(RarNode next) - { - SetNext(next.Address); - } + internal void SetNext(RarNode next) + { + SetNext(next.Address); + } - internal void SetNext(int next) + internal void SetNext(int next) + { + _next = next; + if (Memory != null) { - _next = next; - if (Memory != null) - { - BinaryPrimitives.WriteInt32LittleEndian(Memory.AsSpan(Address), next); - } - } - - public override string ToString() - { - StringBuilder buffer = new StringBuilder(); - buffer.Append("State["); - buffer.Append("\n Address="); - buffer.Append(Address); - buffer.Append("\n size="); - buffer.Append(SIZE); - buffer.Append("\n next="); - buffer.Append(GetNext()); - buffer.Append("\n]"); - return buffer.ToString(); + BinaryPrimitives.WriteInt32LittleEndian(Memory.AsSpan(Address), next); } } + + public override string ToString() + { + var buffer = new StringBuilder(); + buffer.Append("State["); + buffer.Append("\n Address="); + buffer.Append(Address); + buffer.Append("\n size="); + buffer.Append(SIZE); + buffer.Append("\n next="); + buffer.Append(GetNext()); + buffer.Append("\n]"); + return buffer.ToString(); + } } diff --git a/src/SharpCompress/Compressors/PPMd/H/SEE2Context.cs b/src/SharpCompress/Compressors/PPMd/H/SEE2Context.cs index dd4fa7c6..742bd279 100644 --- a/src/SharpCompress/Compressors/PPMd/H/SEE2Context.cs +++ b/src/SharpCompress/Compressors/PPMd/H/SEE2Context.cs @@ -1,87 +1,85 @@ -using System; using System.Text; -namespace SharpCompress.Compressors.PPMd.H +namespace SharpCompress.Compressors.PPMd.H; + +internal class See2Context { - internal class See2Context + public virtual int Mean { - public virtual int Mean + get { - get - { - int retVal = Utility.URShift(_summ, _shift); - _summ -= retVal; - return retVal + ((retVal == 0) ? 1 : 0); - } - } - - public virtual int Count - { - get => _count; - set => _count = value & 0xff; - } - - public virtual int Shift - { - get => _shift; - set => _shift = value & 0xff; - } - - public virtual int Summ - { - get => _summ; - set => _summ = value & 0xffff; - } - - public const int SIZE = 4; - - // ushort Summ; - private int _summ; - - // byte Shift; - private int _shift; - - // byte Count; - private int _count; - - public void Initialize(int initVal) - { - _shift = (ModelPpm.PERIOD_BITS - 4) & 0xff; - _summ = (initVal << _shift) & 0xffff; - _count = 4; - } - - public virtual void Update() - { - if (_shift < ModelPpm.PERIOD_BITS && --_count == 0) - { - _summ += _summ; - _count = (3 << _shift++); - } - _summ &= 0xffff; - _count &= 0xff; - _shift &= 0xff; - } - - public virtual void IncSumm(int dSumm) - { - Summ = Summ + dSumm; - } - - public override String ToString() - { - StringBuilder buffer = new StringBuilder(); - buffer.Append("SEE2Context["); - buffer.Append("\n size="); - buffer.Append(SIZE); - buffer.Append("\n summ="); - buffer.Append(_summ); - buffer.Append("\n shift="); - buffer.Append(_shift); - buffer.Append("\n count="); - buffer.Append(_count); - buffer.Append("\n]"); - return buffer.ToString(); + var retVal = Utility.URShift(_summ, _shift); + _summ -= retVal; + return retVal + ((retVal == 0) ? 1 : 0); } } + + public virtual int Count + { + get => _count; + set => _count = value & 0xff; + } + + public virtual int Shift + { + get => _shift; + set => _shift = value & 0xff; + } + + public virtual int Summ + { + get => _summ; + set => _summ = value & 0xffff; + } + + public const int SIZE = 4; + + // ushort Summ; + private int _summ; + + // byte Shift; + private int _shift; + + // byte Count; + private int _count; + + public void Initialize(int initVal) + { + _shift = (ModelPpm.PERIOD_BITS - 4) & 0xff; + _summ = (initVal << _shift) & 0xffff; + _count = 4; + } + + public virtual void Update() + { + if (_shift < ModelPpm.PERIOD_BITS && --_count == 0) + { + _summ += _summ; + _count = (3 << _shift++); + } + _summ &= 0xffff; + _count &= 0xff; + _shift &= 0xff; + } + + public virtual void IncSumm(int dSumm) + { + Summ += dSumm; + } + + public override string ToString() + { + var buffer = new StringBuilder(); + buffer.Append("SEE2Context["); + buffer.Append("\n size="); + buffer.Append(SIZE); + buffer.Append("\n summ="); + buffer.Append(_summ); + buffer.Append("\n shift="); + buffer.Append(_shift); + buffer.Append("\n count="); + buffer.Append(_count); + buffer.Append("\n]"); + return buffer.ToString(); + } } diff --git a/src/SharpCompress/Compressors/PPMd/H/State.cs b/src/SharpCompress/Compressors/PPMd/H/State.cs index 6ce6d2d0..3aa9b20f 100644 --- a/src/SharpCompress/Compressors/PPMd/H/State.cs +++ b/src/SharpCompress/Compressors/PPMd/H/State.cs @@ -2,74 +2,74 @@ using System; using System.Buffers.Binary; using System.Text; -namespace SharpCompress.Compressors.PPMd.H +namespace SharpCompress.Compressors.PPMd.H; + +internal sealed class State : Pointer { - internal sealed class State : Pointer + internal const int SIZE = 6; + + internal State(byte[]? memory) : base(memory) { } + + internal int Symbol { - internal const int SIZE = 6; + get => Memory[Address] & 0xff; + set => Memory[Address] = (byte)value; + } - internal State(byte[]? memory) : base(memory) { } + internal int Freq + { + get => Memory[Address + 1] & 0xff; + set => Memory[Address + 1] = (byte)value; + } - internal int Symbol - { - get => Memory[Address] & 0xff; - set => Memory[Address] = (byte)value; - } + internal State Initialize(byte[] mem) + { + return Initialize(mem); + } - internal int Freq - { - get => Memory[Address + 1] & 0xff; - set => Memory[Address + 1] = (byte)value; - } + internal void IncrementFreq(int dFreq) + { + Memory[Address + 1] = (byte)(Memory[Address + 1] + dFreq); + } - internal State Initialize(byte[] mem) - { - return base.Initialize(mem); - } + internal int GetSuccessor() + { + return BinaryPrimitives.ReadInt32LittleEndian(Memory.AsSpan(Address + 2)); + } - internal void IncrementFreq(int dFreq) - { - Memory[Address + 1] = (byte)(Memory[Address + 1] + dFreq); - } + internal void SetSuccessor(PpmContext successor) + { + SetSuccessor(successor.Address); + } - internal int GetSuccessor() - { - return BinaryPrimitives.ReadInt32LittleEndian(Memory.AsSpan(Address + 2)); - } + internal void SetSuccessor(int successor) + { + BinaryPrimitives.WriteInt32LittleEndian(Memory.AsSpan(Address + 2), successor); + } - internal void SetSuccessor(PpmContext successor) - { - SetSuccessor(successor.Address); - } + internal void SetValues(StateRef state) + { + Symbol = state.Symbol; + Freq = state.Freq; + SetSuccessor(state.GetSuccessor()); + } - internal void SetSuccessor(int successor) - { - BinaryPrimitives.WriteInt32LittleEndian(Memory.AsSpan(Address + 2), successor); - } + internal void SetValues(State ptr) + { + Array.Copy(ptr.Memory, ptr.Address, Memory, Address, SIZE); + } - internal void SetValues(StateRef state) - { - Symbol = state.Symbol; - Freq = state.Freq; - SetSuccessor(state.GetSuccessor()); - } + internal State DecrementAddress() + { + Address -= SIZE; + return this; + } - internal void SetValues(State ptr) - { - Array.Copy(ptr.Memory, ptr.Address, Memory, Address, SIZE); - } - - internal State DecrementAddress() - { - Address = Address - SIZE; - return this; - } - - internal State IncrementAddress() - { - Address = Address + SIZE; - return this; - } + internal State IncrementAddress() + { + Address += SIZE; + return this; + } internal static void PpmdSwap(State ptr1, State ptr2) { @@ -77,28 +77,27 @@ namespace SharpCompress.Compressors.PPMd.H mem2 = ptr2.Memory; for (int i = 0, pos1 = ptr1.Address, pos2 = ptr2.Address; i < SIZE; i++, pos1++, pos2++) { - byte temp = mem1[pos1]; + var temp = mem1[pos1]; mem1[pos1] = mem2[pos2]; mem2[pos2] = temp; } } - public override String ToString() - { - StringBuilder buffer = new StringBuilder(); - buffer.Append("State["); - buffer.Append("\n Address="); - buffer.Append(Address); - buffer.Append("\n size="); - buffer.Append(SIZE); - buffer.Append("\n symbol="); - buffer.Append(Symbol); - buffer.Append("\n freq="); - buffer.Append(Freq); - buffer.Append("\n successor="); - buffer.Append(GetSuccessor()); - buffer.Append("\n]"); - return buffer.ToString(); - } + public override string ToString() + { + var buffer = new StringBuilder(); + buffer.Append("State["); + buffer.Append("\n Address="); + buffer.Append(Address); + buffer.Append("\n size="); + buffer.Append(SIZE); + buffer.Append("\n symbol="); + buffer.Append(Symbol); + buffer.Append("\n freq="); + buffer.Append(Freq); + buffer.Append("\n successor="); + buffer.Append(GetSuccessor()); + buffer.Append("\n]"); + return buffer.ToString(); } } diff --git a/src/SharpCompress/Compressors/PPMd/H/StateRef.cs b/src/SharpCompress/Compressors/PPMd/H/StateRef.cs index 686c1128..9df43814 100644 --- a/src/SharpCompress/Compressors/PPMd/H/StateRef.cs +++ b/src/SharpCompress/Compressors/PPMd/H/StateRef.cs @@ -1,75 +1,73 @@ -using System; using System.Text; -namespace SharpCompress.Compressors.PPMd.H +namespace SharpCompress.Compressors.PPMd.H; + +internal class StateRef { - internal class StateRef + private int _symbol; + + private int _freq; + + private int _successor; // pointer ppmcontext + + internal int Symbol { - private int _symbol; + get => _symbol; + set => _symbol = value & 0xff; + } - private int _freq; + internal int Freq + { + get => _freq; + set => _freq = value & 0xff; + } - private int _successor; // pointer ppmcontext - - internal int Symbol + internal State Values + { + set { - get => _symbol; - set => _symbol = value & 0xff; - } - - internal int Freq - { - get => _freq; - set => _freq = value & 0xff; - } - - internal State Values - { - set - { - Freq = value.Freq; - SetSuccessor(value.GetSuccessor()); - Symbol = value.Symbol; - } - } - - public virtual void IncrementFreq(int dFreq) - { - _freq = (_freq + dFreq) & 0xff; - } - - public virtual void DecrementFreq(int dFreq) - { - _freq = (_freq - dFreq) & 0xff; - } - - public virtual int GetSuccessor() - { - return _successor; - } - - public virtual void SetSuccessor(PpmContext successor) - { - SetSuccessor(successor.Address); - } - - public virtual void SetSuccessor(int successor) - { - _successor = successor; - } - - public override String ToString() - { - StringBuilder buffer = new StringBuilder(); - buffer.Append("State["); - buffer.Append("\n symbol="); - buffer.Append(Symbol); - buffer.Append("\n freq="); - buffer.Append(Freq); - buffer.Append("\n successor="); - buffer.Append(GetSuccessor()); - buffer.Append("\n]"); - return buffer.ToString(); + Freq = value.Freq; + SetSuccessor(value.GetSuccessor()); + Symbol = value.Symbol; } } + + public virtual void IncrementFreq(int dFreq) + { + _freq = (_freq + dFreq) & 0xff; + } + + public virtual void DecrementFreq(int dFreq) + { + _freq = (_freq - dFreq) & 0xff; + } + + public virtual int GetSuccessor() + { + return _successor; + } + + public virtual void SetSuccessor(PpmContext successor) + { + SetSuccessor(successor.Address); + } + + public virtual void SetSuccessor(int successor) + { + _successor = successor; + } + + public override string ToString() + { + var buffer = new StringBuilder(); + buffer.Append("State["); + buffer.Append("\n symbol="); + buffer.Append(Symbol); + buffer.Append("\n freq="); + buffer.Append(Freq); + buffer.Append("\n successor="); + buffer.Append(GetSuccessor()); + buffer.Append("\n]"); + return buffer.ToString(); + } } diff --git a/src/SharpCompress/Compressors/PPMd/H/SubAllocator.cs b/src/SharpCompress/Compressors/PPMd/H/SubAllocator.cs index dba09739..a3757715 100644 --- a/src/SharpCompress/Compressors/PPMd/H/SubAllocator.cs +++ b/src/SharpCompress/Compressors/PPMd/H/SubAllocator.cs @@ -3,475 +3,474 @@ using System; using System.Text; -namespace SharpCompress.Compressors.PPMd.H +namespace SharpCompress.Compressors.PPMd.H; + +internal class SubAllocator { - internal class SubAllocator + public virtual int FakeUnitsStart { - public virtual int FakeUnitsStart + get => _fakeUnitsStart; + set => _fakeUnitsStart = value; + } + + public virtual int HeapEnd => _heapEnd; + + public virtual int PText + { + get => _pText; + set => _pText = value; + } + + public virtual int UnitsStart + { + get => _unitsStart; + set => _unitsStart = value; + } + + public virtual byte[] Heap => _heap; + + //UPGRADE_NOTE: Final was removed from the declaration of 'N4 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + public const int N1 = 4; + public const int N2 = 4; + public const int N3 = 4; + public static readonly int N4 = (128 + 3 - (1 * N1) - (2 * N2) - (3 * N3)) / 4; + + //UPGRADE_NOTE: Final was removed from the declaration of 'N_INDEXES '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + public static readonly int N_INDEXES = N1 + N2 + N3 + N4; + + //UPGRADE_NOTE: Final was removed from the declaration of 'UNIT_SIZE '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + //UPGRADE_NOTE: The initialization of 'UNIT_SIZE' was moved to static method 'SharpCompress.Unpack.PPM.SubAllocator'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1005'" + public static readonly int UNIT_SIZE; + + public const int FIXED_UNIT_SIZE = 12; + + private int _subAllocatorSize; + + // byte Indx2Units[N_INDEXES], Units2Indx[128], GlueCount; + private readonly int[] _indx2Units = new int[N_INDEXES]; + private readonly int[] _units2Indx = new int[128]; + private int _glueCount; + + // byte *HeapStart,*LoUnit, *HiUnit; + private int _heapStart, + _loUnit, + _hiUnit; + + //UPGRADE_NOTE: Final was removed from the declaration of 'freeList '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + private readonly RarNode[] _freeList = new RarNode[N_INDEXES]; + + // byte *pText, *UnitsStart,*HeapEnd,*FakeUnitsStart; + private int _pText, + _unitsStart, + _heapEnd, + _fakeUnitsStart; + + private byte[] _heap; + + private int _freeListPos; + + private int _tempMemBlockPos; + + // Temp fields + private RarNode _tempRarNode; + private RarMemBlock _tempRarMemBlock1; + private RarMemBlock _tempRarMemBlock2; + private RarMemBlock _tempRarMemBlock3; + + public SubAllocator() + { + Clean(); + } + + public virtual void Clean() + { + _subAllocatorSize = 0; + } + + private void InsertNode(int p, int indx) + { + var temp = _tempRarNode; + temp.Address = p; + temp.SetNext(_freeList[indx].GetNext()); + _freeList[indx].SetNext(temp); + } + + public virtual void IncPText() + { + _pText++; + } + + private int RemoveNode(int indx) + { + var retVal = _freeList[indx].GetNext(); + var temp = _tempRarNode; + temp.Address = retVal; + _freeList[indx].SetNext(temp.GetNext()); + return retVal; + } + + private int U2B(int nu) + { + return UNIT_SIZE * nu; + } + + /* memblockptr */ + + private int MbPtr(int basePtr, int items) + { + return (basePtr + U2B(items)); + } + + private void SplitBlock(int pv, int oldIndx, int newIndx) + { + int i, + uDiff = _indx2Units[oldIndx] - _indx2Units[newIndx]; + var p = pv + U2B(_indx2Units[newIndx]); + if (_indx2Units[i = _units2Indx[uDiff - 1]] != uDiff) { - get => _fakeUnitsStart; - set => _fakeUnitsStart = value; + InsertNode(p, --i); + p += U2B(i = _indx2Units[i]); + uDiff -= i; } + InsertNode(p, _units2Indx[uDiff - 1]); + } - public virtual int HeapEnd => _heapEnd; - - public virtual int PText - { - get => _pText; - set => _pText = value; - } - - public virtual int UnitsStart - { - get => _unitsStart; - set => _unitsStart = value; - } - - public virtual byte[] Heap => _heap; - - //UPGRADE_NOTE: Final was removed from the declaration of 'N4 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public const int N1 = 4; - public const int N2 = 4; - public const int N3 = 4; - public static readonly int N4 = (128 + 3 - 1 * N1 - 2 * N2 - 3 * N3) / 4; - - //UPGRADE_NOTE: Final was removed from the declaration of 'N_INDEXES '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly int N_INDEXES = N1 + N2 + N3 + N4; - - //UPGRADE_NOTE: Final was removed from the declaration of 'UNIT_SIZE '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - //UPGRADE_NOTE: The initialization of 'UNIT_SIZE' was moved to static method 'SharpCompress.Unpack.PPM.SubAllocator'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1005'" - public static readonly int UNIT_SIZE; - - public const int FIXED_UNIT_SIZE = 12; - - private int _subAllocatorSize; - - // byte Indx2Units[N_INDEXES], Units2Indx[128], GlueCount; - private readonly int[] _indx2Units = new int[N_INDEXES]; - private readonly int[] _units2Indx = new int[128]; - private int _glueCount; - - // byte *HeapStart,*LoUnit, *HiUnit; - private int _heapStart, - _loUnit, - _hiUnit; - - //UPGRADE_NOTE: Final was removed from the declaration of 'freeList '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private readonly RarNode[] _freeList = new RarNode[N_INDEXES]; - - // byte *pText, *UnitsStart,*HeapEnd,*FakeUnitsStart; - private int _pText, - _unitsStart, - _heapEnd, - _fakeUnitsStart; - - private byte[] _heap; - - private int _freeListPos; - - private int _tempMemBlockPos; - - // Temp fields - private RarNode _tempRarNode; - private RarMemBlock _tempRarMemBlock1; - private RarMemBlock _tempRarMemBlock2; - private RarMemBlock _tempRarMemBlock3; - - public SubAllocator() - { - Clean(); - } - - public virtual void Clean() + public virtual void StopSubAllocator() + { + if (_subAllocatorSize != 0) { _subAllocatorSize = 0; - } - private void InsertNode(int p, int indx) - { - RarNode temp = _tempRarNode; - temp.Address = p; - temp.SetNext(_freeList[indx].GetNext()); - _freeList[indx].SetNext(temp); - } - - public virtual void IncPText() - { - _pText++; - } - - private int RemoveNode(int indx) - { - int retVal = _freeList[indx].GetNext(); - RarNode temp = _tempRarNode; - temp.Address = retVal; - _freeList[indx].SetNext(temp.GetNext()); - return retVal; - } - - private int U2B(int nu) - { - return UNIT_SIZE * nu; - } - - /* memblockptr */ - - private int MbPtr(int basePtr, int items) - { - return (basePtr + U2B(items)); - } - - private void SplitBlock(int pv, int oldIndx, int newIndx) - { - int i, - uDiff = _indx2Units[oldIndx] - _indx2Units[newIndx]; - int p = pv + U2B(_indx2Units[newIndx]); - if (_indx2Units[i = _units2Indx[uDiff - 1]] != uDiff) - { - InsertNode(p, --i); - p += U2B(i = _indx2Units[i]); - uDiff -= i; - } - InsertNode(p, _units2Indx[uDiff - 1]); - } - - public virtual void StopSubAllocator() - { - if (_subAllocatorSize != 0) - { - _subAllocatorSize = 0; - - //ArrayFactory.BYTES_FACTORY.recycle(heap); - _heap = null; - _heapStart = 1; - - // rarfree(HeapStart); - // Free temp fields - _tempRarNode = null; - _tempRarMemBlock1 = null; - _tempRarMemBlock2 = null; - _tempRarMemBlock3 = null; - } - } - - public virtual int GetAllocatedMemory() - { - return _subAllocatorSize; - } - - public virtual bool StartSubAllocator(int saSize) - { - int t = saSize; - if (_subAllocatorSize == t) - { - return true; - } - StopSubAllocator(); - int allocSize = t / FIXED_UNIT_SIZE * UNIT_SIZE + UNIT_SIZE; - - // adding space for freelist (needed for poiters) - // 1+ for null pointer - int realAllocSize = 1 + allocSize + 4 * N_INDEXES; - - // adding space for an additional memblock - _tempMemBlockPos = realAllocSize; - realAllocSize += RarMemBlock.SIZE; - - _heap = new byte[realAllocSize]; + //ArrayFactory.BYTES_FACTORY.recycle(heap); + _heap = null; _heapStart = 1; - _heapEnd = _heapStart + allocSize - UNIT_SIZE; - _subAllocatorSize = t; - // Bug fixed - _freeListPos = _heapStart + allocSize; + // rarfree(HeapStart); + // Free temp fields + _tempRarNode = null; + _tempRarMemBlock1 = null; + _tempRarMemBlock2 = null; + _tempRarMemBlock3 = null; + } + } - //UPGRADE_ISSUE: The following fragment of code could not be parsed and was not converted. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1156'" - //assert(realAllocSize - tempMemBlockPos == RarMemBlock.size): realAllocSize - //+ + tempMemBlockPos + + RarMemBlock.size; - - // Init freeList - for (int i = 0, pos = _freeListPos; i < _freeList.Length; i++, pos += RarNode.SIZE) - { - _freeList[i] = new RarNode(_heap); - _freeList[i].Address = pos; - } - - // Init temp fields - _tempRarNode = new RarNode(_heap); - _tempRarMemBlock1 = new RarMemBlock(_heap); - _tempRarMemBlock2 = new RarMemBlock(_heap); - _tempRarMemBlock3 = new RarMemBlock(_heap); + public virtual int GetAllocatedMemory() + { + return _subAllocatorSize; + } + public virtual bool StartSubAllocator(int saSize) + { + var t = saSize; + if (_subAllocatorSize == t) + { return true; } + StopSubAllocator(); + var allocSize = (t / FIXED_UNIT_SIZE * UNIT_SIZE) + UNIT_SIZE; - private void GlueFreeBlocks() + // adding space for freelist (needed for poiters) + // 1+ for null pointer + var realAllocSize = 1 + allocSize + (4 * N_INDEXES); + + // adding space for an additional memblock + _tempMemBlockPos = realAllocSize; + realAllocSize += RarMemBlock.SIZE; + + _heap = new byte[realAllocSize]; + _heapStart = 1; + _heapEnd = _heapStart + allocSize - UNIT_SIZE; + _subAllocatorSize = t; + + // Bug fixed + _freeListPos = _heapStart + allocSize; + + //UPGRADE_ISSUE: The following fragment of code could not be parsed and was not converted. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1156'" + //assert(realAllocSize - tempMemBlockPos == RarMemBlock.size): realAllocSize + //+ + tempMemBlockPos + + RarMemBlock.size; + + // Init freeList + for (int i = 0, pos = _freeListPos; i < _freeList.Length; i++, pos += RarNode.SIZE) { - RarMemBlock s0 = _tempRarMemBlock1; - s0.Address = _tempMemBlockPos; - RarMemBlock p = _tempRarMemBlock2; - RarMemBlock p1 = _tempRarMemBlock3; - int i, - k, - sz; - if (_loUnit != _hiUnit) - { - _heap[_loUnit] = 0; - } - for (i = 0, s0.SetPrev(s0), s0.SetNext(s0); i < N_INDEXES; i++) - { - while (_freeList[i].GetNext() != 0) - { - p.Address = RemoveNode(i); // =(RAR_MEM_BLK*)RemoveNode(i); - p.InsertAt(s0); // p->insertAt(&s0); - p.Stamp = 0xFFFF; // p->Stamp=0xFFFF; - p.SetNu(_indx2Units[i]); // p->NU=Indx2Units[i]; - } - } - for (p.Address = s0.GetNext(); p.Address != s0.Address; p.Address = p.GetNext()) - { - // while ((p1=MBPtr(p,p->NU))->Stamp == 0xFFFF && int(p->NU)+p1->NU - // < 0x10000) - // Bug fixed - p1.Address = MbPtr(p.Address, p.GetNu()); - while (p1.Stamp == 0xFFFF && p.GetNu() + p1.GetNu() < 0x10000) - { - p1.Remove(); - p.SetNu(p.GetNu() + p1.GetNu()); // ->NU += p1->NU; - p1.Address = MbPtr(p.Address, p.GetNu()); - } - } + _freeList[i] = new RarNode(_heap); + _freeList[i].Address = pos; + } - // while ((p=s0.next) != &s0) + // Init temp fields + _tempRarNode = new RarNode(_heap); + _tempRarMemBlock1 = new RarMemBlock(_heap); + _tempRarMemBlock2 = new RarMemBlock(_heap); + _tempRarMemBlock3 = new RarMemBlock(_heap); + + return true; + } + + private void GlueFreeBlocks() + { + var s0 = _tempRarMemBlock1; + s0.Address = _tempMemBlockPos; + var p = _tempRarMemBlock2; + var p1 = _tempRarMemBlock3; + int i, + k, + sz; + if (_loUnit != _hiUnit) + { + _heap[_loUnit] = 0; + } + for (i = 0, s0.SetPrev(s0), s0.SetNext(s0); i < N_INDEXES; i++) + { + while (_freeList[i].GetNext() != 0) + { + p.Address = RemoveNode(i); // =(RAR_MEM_BLK*)RemoveNode(i); + p.InsertAt(s0); // p->insertAt(&s0); + p.Stamp = 0xFFFF; // p->Stamp=0xFFFF; + p.SetNu(_indx2Units[i]); // p->NU=Indx2Units[i]; + } + } + for (p.Address = s0.GetNext(); p.Address != s0.Address; p.Address = p.GetNext()) + { + // while ((p1=MBPtr(p,p->NU))->Stamp == 0xFFFF && int(p->NU)+p1->NU + // < 0x10000) // Bug fixed + p1.Address = MbPtr(p.Address, p.GetNu()); + while (p1.Stamp == 0xFFFF && p.GetNu() + p1.GetNu() < 0x10000) + { + p1.Remove(); + p.SetNu(p.GetNu() + p1.GetNu()); // ->NU += p1->NU; + p1.Address = MbPtr(p.Address, p.GetNu()); + } + } + + // while ((p=s0.next) != &s0) + // Bug fixed + p.Address = s0.GetNext(); + while (p.Address != s0.Address) + { + for ( + p.Remove(), sz = p.GetNu(); + sz > 128; + sz -= 128, p.Address = MbPtr(p.Address, 128) + ) + { + InsertNode(p.Address, N_INDEXES - 1); + } + if (_indx2Units[i = _units2Indx[sz - 1]] != sz) + { + k = sz - _indx2Units[--i]; + InsertNode(MbPtr(p.Address, sz - k), k - 1); + } + InsertNode(p.Address, i); p.Address = s0.GetNext(); - while (p.Address != s0.Address) - { - for ( - p.Remove(), sz = p.GetNu(); - sz > 128; - sz -= 128, p.Address = MbPtr(p.Address, 128) - ) - { - InsertNode(p.Address, N_INDEXES - 1); - } - if (_indx2Units[i = _units2Indx[sz - 1]] != sz) - { - k = sz - _indx2Units[--i]; - InsertNode(MbPtr(p.Address, sz - k), k - 1); - } - InsertNode(p.Address, i); - p.Address = s0.GetNext(); - } } + } - private int AllocUnitsRare(int indx) + private int AllocUnitsRare(int indx) + { + if (_glueCount == 0) { - if (_glueCount == 0) - { - _glueCount = 255; - GlueFreeBlocks(); - if (_freeList[indx].GetNext() != 0) - { - return RemoveNode(indx); - } - } - int i = indx; - do - { - if (++i == N_INDEXES) - { - _glueCount--; - i = U2B(_indx2Units[indx]); - int j = FIXED_UNIT_SIZE * _indx2Units[indx]; - if (_fakeUnitsStart - _pText > j) - { - _fakeUnitsStart -= j; - _unitsStart -= i; - return _unitsStart; - } - return (0); - } - } while (_freeList[i].GetNext() == 0); - int retVal = RemoveNode(i); - SplitBlock(retVal, i, indx); - return retVal; - } - - public virtual int AllocUnits(int nu) - { - int indx = _units2Indx[nu - 1]; + _glueCount = 255; + GlueFreeBlocks(); if (_freeList[indx].GetNext() != 0) { return RemoveNode(indx); } - int retVal = _loUnit; - _loUnit += U2B(_indx2Units[indx]); - if (_loUnit <= _hiUnit) - { - return retVal; - } - _loUnit -= U2B(_indx2Units[indx]); - return AllocUnitsRare(indx); } - - public virtual int AllocContext() + var i = indx; + do { - if (_hiUnit != _loUnit) + if (++i == N_INDEXES) { - return (_hiUnit -= UNIT_SIZE); + _glueCount--; + i = U2B(_indx2Units[indx]); + var j = FIXED_UNIT_SIZE * _indx2Units[indx]; + if (_fakeUnitsStart - _pText > j) + { + _fakeUnitsStart -= j; + _unitsStart -= i; + return _unitsStart; + } + return (0); } - if (_freeList[0].GetNext() != 0) - { - return RemoveNode(0); - } - return AllocUnitsRare(0); + } while (_freeList[i].GetNext() == 0); + var retVal = RemoveNode(i); + SplitBlock(retVal, i, indx); + return retVal; + } + + public virtual int AllocUnits(int nu) + { + var indx = _units2Indx[nu - 1]; + if (_freeList[indx].GetNext() != 0) + { + return RemoveNode(indx); } - - public virtual int ExpandUnits(int oldPtr, int oldNu) + var retVal = _loUnit; + _loUnit += U2B(_indx2Units[indx]); + if (_loUnit <= _hiUnit) { - int i0 = _units2Indx[oldNu - 1]; - int i1 = _units2Indx[oldNu - 1 + 1]; - if (i0 == i1) - { - return oldPtr; - } - int ptr = AllocUnits(oldNu + 1); - if (ptr != 0) - { - // memcpy(ptr,OldPtr,U2B(OldNU)); - Array.Copy(_heap, oldPtr, _heap, ptr, U2B(oldNu)); - InsertNode(oldPtr, i0); - } - return ptr; + return retVal; } + _loUnit -= U2B(_indx2Units[indx]); + return AllocUnitsRare(indx); + } - public virtual int ShrinkUnits(int oldPtr, int oldNu, int newNu) + public virtual int AllocContext() + { + if (_hiUnit != _loUnit) { - // System.out.println("SubAllocator.shrinkUnits(" + OldPtr + ", " + - // OldNU + ", " + NewNU + ")"); - int i0 = _units2Indx[oldNu - 1]; - int i1 = _units2Indx[newNu - 1]; - if (i0 == i1) - { - return oldPtr; - } - if (_freeList[i1].GetNext() != 0) - { - int ptr = RemoveNode(i1); + return (_hiUnit -= UNIT_SIZE); + } + if (_freeList[0].GetNext() != 0) + { + return RemoveNode(0); + } + return AllocUnitsRare(0); + } - // memcpy(ptr,OldPtr,U2B(NewNU)); - // for (int i = 0; i < U2B(NewNU); i++) { - // heap[ptr + i] = heap[OldPtr + i]; - // } - Array.Copy(_heap, oldPtr, _heap, ptr, U2B(newNu)); - InsertNode(oldPtr, i0); - return ptr; - } - SplitBlock(oldPtr, i0, i1); + public virtual int ExpandUnits(int oldPtr, int oldNu) + { + var i0 = _units2Indx[oldNu - 1]; + var i1 = _units2Indx[oldNu - 1 + 1]; + if (i0 == i1) + { return oldPtr; } - - public virtual void FreeUnits(int ptr, int oldNu) + var ptr = AllocUnits(oldNu + 1); + if (ptr != 0) { - InsertNode(ptr, _units2Indx[oldNu - 1]); + // memcpy(ptr,OldPtr,U2B(OldNU)); + Array.Copy(_heap, oldPtr, _heap, ptr, U2B(oldNu)); + InsertNode(oldPtr, i0); + } + return ptr; + } + + public virtual int ShrinkUnits(int oldPtr, int oldNu, int newNu) + { + // System.out.println("SubAllocator.shrinkUnits(" + OldPtr + ", " + + // OldNU + ", " + NewNU + ")"); + var i0 = _units2Indx[oldNu - 1]; + var i1 = _units2Indx[newNu - 1]; + if (i0 == i1) + { + return oldPtr; + } + if (_freeList[i1].GetNext() != 0) + { + var ptr = RemoveNode(i1); + + // memcpy(ptr,OldPtr,U2B(NewNU)); + // for (int i = 0; i < U2B(NewNU); i++) { + // heap[ptr + i] = heap[OldPtr + i]; + // } + Array.Copy(_heap, oldPtr, _heap, ptr, U2B(newNu)); + InsertNode(oldPtr, i0); + return ptr; + } + SplitBlock(oldPtr, i0, i1); + return oldPtr; + } + + public virtual void FreeUnits(int ptr, int oldNu) + { + InsertNode(ptr, _units2Indx[oldNu - 1]); + } + + public virtual void DecPText(int dPText) + { + PText -= dPText; + } + + public virtual void InitSubAllocator() + { + int i, + k; + new Span(_heap, _freeListPos, SizeOfFreeList()).Clear(); + + _pText = _heapStart; + + var size2 = FIXED_UNIT_SIZE * (_subAllocatorSize / 8 / FIXED_UNIT_SIZE * 7); + var realSize2 = size2 / FIXED_UNIT_SIZE * UNIT_SIZE; + var size1 = _subAllocatorSize - size2; + var realSize1 = (size1 / FIXED_UNIT_SIZE * UNIT_SIZE) + (size1 % FIXED_UNIT_SIZE); + _hiUnit = _heapStart + _subAllocatorSize; + _loUnit = _unitsStart = _heapStart + realSize1; + _fakeUnitsStart = _heapStart + size1; + _hiUnit = _loUnit + realSize2; + + for (i = 0, k = 1; i < N1; i++, k += 1) + { + _indx2Units[i] = k & 0xff; + } + for (k++; i < N1 + N2; i++, k += 2) + { + _indx2Units[i] = k & 0xff; + } + for (k++; i < N1 + N2 + N3; i++, k += 3) + { + _indx2Units[i] = k & 0xff; + } + for (k++; i < (N1 + N2 + N3 + N4); i++, k += 4) + { + _indx2Units[i] = k & 0xff; } - public virtual void DecPText(int dPText) + for (_glueCount = 0, k = 0, i = 0; k < 128; k++) { - PText = PText - dPText; - } - - public virtual void InitSubAllocator() - { - int i, - k; - new Span(_heap, _freeListPos, SizeOfFreeList()).Clear(); - - _pText = _heapStart; - - int size2 = FIXED_UNIT_SIZE * (_subAllocatorSize / 8 / FIXED_UNIT_SIZE * 7); - int realSize2 = size2 / FIXED_UNIT_SIZE * UNIT_SIZE; - int size1 = _subAllocatorSize - size2; - int realSize1 = size1 / FIXED_UNIT_SIZE * UNIT_SIZE + size1 % FIXED_UNIT_SIZE; - _hiUnit = _heapStart + _subAllocatorSize; - _loUnit = _unitsStart = _heapStart + realSize1; - _fakeUnitsStart = _heapStart + size1; - _hiUnit = _loUnit + realSize2; - - for (i = 0, k = 1; i < N1; i++, k += 1) - { - _indx2Units[i] = k & 0xff; - } - for (k++; i < N1 + N2; i++, k += 2) - { - _indx2Units[i] = k & 0xff; - } - for (k++; i < N1 + N2 + N3; i++, k += 3) - { - _indx2Units[i] = k & 0xff; - } - for (k++; i < (N1 + N2 + N3 + N4); i++, k += 4) - { - _indx2Units[i] = k & 0xff; - } - - for (_glueCount = 0, k = 0, i = 0; k < 128; k++) - { - i += ((_indx2Units[i] < (k + 1)) ? 1 : 0); - _units2Indx[k] = i & 0xff; - } - } - - private int SizeOfFreeList() - { - return _freeList.Length * RarNode.SIZE; - } - - // Debug - // public void dumpHeap() { - // File file = new File("P:\\test\\heapdumpj"); - // OutputStream out = null; - // try { - // out = new FileOutputStream(file); - // out.write(heap, heapStart, heapEnd - heapStart); - // out.flush(); - // System.out.println("Heap dumped to " + file.getAbsolutePath()); - // } - // catch (IOException e) { - // e.printStackTrace(); - // } - // finally { - // FileUtil.close(out); - // } - // } - - // Debug - public override String ToString() - { - StringBuilder buffer = new StringBuilder(); - buffer.Append("SubAllocator["); - buffer.Append("\n subAllocatorSize="); - buffer.Append(_subAllocatorSize); - buffer.Append("\n glueCount="); - buffer.Append(_glueCount); - buffer.Append("\n heapStart="); - buffer.Append(_heapStart); - buffer.Append("\n loUnit="); - buffer.Append(_loUnit); - buffer.Append("\n hiUnit="); - buffer.Append(_hiUnit); - buffer.Append("\n pText="); - buffer.Append(_pText); - buffer.Append("\n unitsStart="); - buffer.Append(_unitsStart); - buffer.Append("\n]"); - return buffer.ToString(); - } - - static SubAllocator() - { - UNIT_SIZE = Math.Max(PpmContext.SIZE, RarMemBlock.SIZE); + i += ((_indx2Units[i] < (k + 1)) ? 1 : 0); + _units2Indx[k] = i & 0xff; } } + + private int SizeOfFreeList() + { + return _freeList.Length * RarNode.SIZE; + } + + // Debug + // public void dumpHeap() { + // File file = new File("P:\\test\\heapdumpj"); + // OutputStream out = null; + // try { + // out = new FileOutputStream(file); + // out.write(heap, heapStart, heapEnd - heapStart); + // out.flush(); + // System.out.println("Heap dumped to " + file.getAbsolutePath()); + // } + // catch (IOException e) { + // e.printStackTrace(); + // } + // finally { + // FileUtil.close(out); + // } + // } + + // Debug + public override string ToString() + { + var buffer = new StringBuilder(); + buffer.Append("SubAllocator["); + buffer.Append("\n subAllocatorSize="); + buffer.Append(_subAllocatorSize); + buffer.Append("\n glueCount="); + buffer.Append(_glueCount); + buffer.Append("\n heapStart="); + buffer.Append(_heapStart); + buffer.Append("\n loUnit="); + buffer.Append(_loUnit); + buffer.Append("\n hiUnit="); + buffer.Append(_hiUnit); + buffer.Append("\n pText="); + buffer.Append(_pText); + buffer.Append("\n unitsStart="); + buffer.Append(_unitsStart); + buffer.Append("\n]"); + return buffer.ToString(); + } + + static SubAllocator() + { + UNIT_SIZE = Math.Max(PpmContext.SIZE, RarMemBlock.SIZE); + } } diff --git a/src/SharpCompress/Compressors/PPMd/I1/Allocator.cs b/src/SharpCompress/Compressors/PPMd/I1/Allocator.cs index 39a0c94d..6f66e310 100644 --- a/src/SharpCompress/Compressors/PPMd/I1/Allocator.cs +++ b/src/SharpCompress/Compressors/PPMd/I1/Allocator.cs @@ -1,504 +1,503 @@ #nullable disable -namespace SharpCompress.Compressors.PPMd.I1 +namespace SharpCompress.Compressors.PPMd.I1; + +/// Allocate a single, large array and then provide sections of this array to callers. Callers are provided with +/// instances of (which simply contain a single address value, representing a location +/// in the large array). Callers can then cast to one of the following structures (all +/// of which also simply contain a single address value): +internal class Allocator { - /// Allocate a single, large array and then provide sections of this array to callers. Callers are provided with - /// instances of (which simply contain a single address value, representing a location - /// in the large array). Callers can then cast to one of the following structures (all - /// of which also simply contain a single address value): - internal class Allocator + private const uint UNIT_SIZE = 12; + private const uint LOCAL_OFFSET = 4; // reserve the first four bytes for Pointer.Zero + private const uint NODE_OFFSET = LOCAL_OFFSET + MemoryNode.SIZE; // reserve space for a single memory node + + private const uint HEAP_OFFSET = NODE_OFFSET + (INDEX_COUNT * MemoryNode.SIZE); + + // reserve space for the array of memory nodes + + private const uint N1 = 4; + private const uint N2 = 4; + private const uint N3 = 4; + private const uint N4 = (128 + 3 - (1 * N1) - (2 * N2) - (3 * N3)) / 4; + private const uint INDEX_COUNT = N1 + N2 + N3 + N4; + + private static readonly byte[] INDEX_TO_UNITS; + private static readonly byte[] UNITS_TO_INDEX; + + public uint _allocatorSize; + public uint _glueCount; + public Pointer _baseUnit; + public Pointer _lowUnit; + public Pointer _highUnit; + public Pointer _text; + public Pointer _heap; + public MemoryNode[] _memoryNodes; + + public byte[] _memory; + + /// + /// Initializes static read-only arrays used by the . + /// + static Allocator() { - private const uint UNIT_SIZE = 12; - private const uint LOCAL_OFFSET = 4; // reserve the first four bytes for Pointer.Zero - private const uint NODE_OFFSET = LOCAL_OFFSET + MemoryNode.SIZE; // reserve space for a single memory node + // Construct the static index to units lookup array. It will contain the following values. + // + // 1 2 3 4 6 8 10 12 15 18 21 24 28 32 36 40 44 48 52 56 60 64 68 72 76 80 84 88 92 96 100 104 108 + // 112 116 120 124 128 - private const uint HEAP_OFFSET = NODE_OFFSET + INDEX_COUNT * MemoryNode.SIZE; + uint index; + uint unitCount; - // reserve space for the array of memory nodes + INDEX_TO_UNITS = new byte[INDEX_COUNT]; - private const uint N1 = 4; - private const uint N2 = 4; - private const uint N3 = 4; - private const uint N4 = (128 + 3 - 1 * N1 - 2 * N2 - 3 * N3) / 4; - private const uint INDEX_COUNT = N1 + N2 + N3 + N4; - - private static readonly byte[] INDEX_TO_UNITS; - private static readonly byte[] UNITS_TO_INDEX; - - public uint _allocatorSize; - public uint _glueCount; - public Pointer _baseUnit; - public Pointer _lowUnit; - public Pointer _highUnit; - public Pointer _text; - public Pointer _heap; - public MemoryNode[] _memoryNodes; - - public byte[] _memory; - - /// - /// Initializes static read-only arrays used by the . - /// - static Allocator() + for (index = 0, unitCount = 1; index < N1; index++, unitCount += 1) { - // Construct the static index to units lookup array. It will contain the following values. - // - // 1 2 3 4 6 8 10 12 15 18 21 24 28 32 36 40 44 48 52 56 60 64 68 72 76 80 84 88 92 96 100 104 108 - // 112 116 120 124 128 - - uint index; - uint unitCount; - - INDEX_TO_UNITS = new byte[INDEX_COUNT]; - - for (index = 0, unitCount = 1; index < N1; index++, unitCount += 1) - { - INDEX_TO_UNITS[index] = (byte)unitCount; - } - - for (unitCount++; index < N1 + N2; index++, unitCount += 2) - { - INDEX_TO_UNITS[index] = (byte)unitCount; - } - - for (unitCount++; index < N1 + N2 + N3; index++, unitCount += 3) - { - INDEX_TO_UNITS[index] = (byte)unitCount; - } - - for (unitCount++; index < N1 + N2 + N3 + N4; index++, unitCount += 4) - { - INDEX_TO_UNITS[index] = (byte)unitCount; - } - - // Construct the static units to index lookup array. It will contain the following values. - // - // 00 01 02 03 04 04 05 05 06 06 07 07 08 08 08 09 09 09 10 10 10 11 11 11 12 12 12 12 13 13 13 13 - // 14 14 14 14 15 15 15 15 16 16 16 16 17 17 17 17 18 18 18 18 19 19 19 19 20 20 20 20 21 21 21 21 - // 22 22 22 22 23 23 23 23 24 24 24 24 25 25 25 25 26 26 26 26 27 27 27 27 28 28 28 28 29 29 29 29 - // 30 30 30 30 31 31 31 31 32 32 32 32 33 33 33 33 34 34 34 34 35 35 35 35 36 36 36 36 37 37 37 37 - - UNITS_TO_INDEX = new byte[128]; - - for (unitCount = index = 0; unitCount < 128; unitCount++) - { - index += (uint)((INDEX_TO_UNITS[index] < unitCount + 1) ? 1 : 0); - UNITS_TO_INDEX[unitCount] = (byte)index; - } + INDEX_TO_UNITS[index] = (byte)unitCount; } - #region Public Methods - - public Allocator() + for (unitCount++; index < N1 + N2; index++, unitCount += 2) { - _memoryNodes = new MemoryNode[INDEX_COUNT]; + INDEX_TO_UNITS[index] = (byte)unitCount; } - /// - /// Initialize or reset the memory allocator (so that the single, large array can be re-used without destroying - /// and re-creating it). - /// - public void Initialize() + for (unitCount++; index < N1 + N2 + N3; index++, unitCount += 3) { - for (int index = 0; index < INDEX_COUNT; index++) - { - _memoryNodes[index] = new MemoryNode( - (uint)(NODE_OFFSET + index * MemoryNode.SIZE), - _memory - ); - _memoryNodes[index].Stamp = 0; - _memoryNodes[index].Next = MemoryNode.ZERO; - _memoryNodes[index].UnitCount = 0; - } - - _text = _heap; - - uint difference = UNIT_SIZE * (_allocatorSize / 8 / UNIT_SIZE * 7); - - _highUnit = _heap + _allocatorSize; - _lowUnit = _highUnit - difference; - _baseUnit = _highUnit - difference; - - _glueCount = 0; + INDEX_TO_UNITS[index] = (byte)unitCount; } - /// - /// Start the allocator (create a single, large array of bytes). - /// - /// - /// Note that .NET will create that array on the large object heap (because it is so large). - /// - /// - public void Start(int allocatorSize) + for (unitCount++; index < N1 + N2 + N3 + N4; index++, unitCount += 4) { - uint size = (uint)allocatorSize; - if (_allocatorSize != size) + INDEX_TO_UNITS[index] = (byte)unitCount; + } + + // Construct the static units to index lookup array. It will contain the following values. + // + // 00 01 02 03 04 04 05 05 06 06 07 07 08 08 08 09 09 09 10 10 10 11 11 11 12 12 12 12 13 13 13 13 + // 14 14 14 14 15 15 15 15 16 16 16 16 17 17 17 17 18 18 18 18 19 19 19 19 20 20 20 20 21 21 21 21 + // 22 22 22 22 23 23 23 23 24 24 24 24 25 25 25 25 26 26 26 26 27 27 27 27 28 28 28 28 29 29 29 29 + // 30 30 30 30 31 31 31 31 32 32 32 32 33 33 33 33 34 34 34 34 35 35 35 35 36 36 36 36 37 37 37 37 + + UNITS_TO_INDEX = new byte[128]; + + for (unitCount = index = 0; unitCount < 128; unitCount++) + { + index += (uint)((INDEX_TO_UNITS[index] < unitCount + 1) ? 1 : 0); + UNITS_TO_INDEX[unitCount] = (byte)index; + } + } + + #region Public Methods + + public Allocator() + { + _memoryNodes = new MemoryNode[INDEX_COUNT]; + } + + /// + /// Initialize or reset the memory allocator (so that the single, large array can be re-used without destroying + /// and re-creating it). + /// + public void Initialize() + { + for (var index = 0; index < INDEX_COUNT; index++) + { + _memoryNodes[index] = new MemoryNode( + (uint)(NODE_OFFSET + (index * MemoryNode.SIZE)), + _memory + ); + _memoryNodes[index].Stamp = 0; + _memoryNodes[index].Next = MemoryNode.ZERO; + _memoryNodes[index].UnitCount = 0; + } + + _text = _heap; + + var difference = UNIT_SIZE * (_allocatorSize / 8 / UNIT_SIZE * 7); + + _highUnit = _heap + _allocatorSize; + _lowUnit = _highUnit - difference; + _baseUnit = _highUnit - difference; + + _glueCount = 0; + } + + /// + /// Start the allocator (create a single, large array of bytes). + /// + /// + /// Note that .NET will create that array on the large object heap (because it is so large). + /// + /// + public void Start(int allocatorSize) + { + var size = (uint)allocatorSize; + if (_allocatorSize != size) + { + Stop(); + _memory = new byte[HEAP_OFFSET + size]; // the single, large array of bytes + _heap = new Pointer(HEAP_OFFSET, _memory); // reserve bytes in the range 0 .. HeapOffset - 1 + _allocatorSize = size; + } + } + + /// + /// Stop the allocator (free the single, large array of bytes). This can safely be called multiple times (without + /// intervening calls to ). + /// + /// + /// Because the array is on the large object heap it may not be freed immediately. + /// + public void Stop() + { + if (_allocatorSize != 0) + { + _allocatorSize = 0; + _memory = null; + _heap = Pointer.ZERO; + } + } + + /// + /// Determine how much memory (from the single, large array) is currenly in use. + /// + /// + public uint GetMemoryUsed() + { + var memoryUsed = _allocatorSize - (_highUnit - _lowUnit) - (_baseUnit - _text); + for (uint index = 0; index < INDEX_COUNT; index++) + { + memoryUsed -= UNIT_SIZE * INDEX_TO_UNITS[index] * _memoryNodes[index].Stamp; + } + return memoryUsed; + } + + /// + /// Allocate a given number of units from the single, large array. Each unit is bytes + /// in size. + /// + /// + /// + public Pointer AllocateUnits(uint unitCount) + { + uint index = UNITS_TO_INDEX[unitCount - 1]; + if (_memoryNodes[index].Available) + { + return _memoryNodes[index].Remove(); + } + + var allocatedBlock = _lowUnit; + _lowUnit += INDEX_TO_UNITS[index] * UNIT_SIZE; + if (_lowUnit <= _highUnit) + { + return allocatedBlock; + } + + _lowUnit -= INDEX_TO_UNITS[index] * UNIT_SIZE; + return AllocateUnitsRare(index); + } + + /// + /// Allocate enough space for a PpmContext instance in the single, large array. + /// + /// + public Pointer AllocateContext() + { + if (_highUnit != _lowUnit) + { + return (_highUnit -= UNIT_SIZE); + } + if (_memoryNodes[0].Available) + { + return _memoryNodes[0].Remove(); + } + return AllocateUnitsRare(0); + } + + /// + /// Increase the size of an existing allocation (represented by a ). + /// + /// + /// + /// + public Pointer ExpandUnits(Pointer oldPointer, uint oldUnitCount) + { + uint oldIndex = UNITS_TO_INDEX[oldUnitCount - 1]; + uint newIndex = UNITS_TO_INDEX[oldUnitCount]; + + if (oldIndex == newIndex) + { + return oldPointer; + } + + var pointer = AllocateUnits(oldUnitCount + 1); + + if (pointer != Pointer.ZERO) + { + CopyUnits(pointer, oldPointer, oldUnitCount); + _memoryNodes[oldIndex].Insert(oldPointer, oldUnitCount); + } + + return pointer; + } + + /// + /// Decrease the size of an existing allocation (represented by a ). + /// + /// + /// + /// + /// + public Pointer ShrinkUnits(Pointer oldPointer, uint oldUnitCount, uint newUnitCount) + { + uint oldIndex = UNITS_TO_INDEX[oldUnitCount - 1]; + uint newIndex = UNITS_TO_INDEX[newUnitCount - 1]; + + if (oldIndex == newIndex) + { + return oldPointer; + } + + if (_memoryNodes[newIndex].Available) + { + Pointer pointer = _memoryNodes[newIndex].Remove(); + CopyUnits(pointer, oldPointer, newUnitCount); + _memoryNodes[oldIndex].Insert(oldPointer, INDEX_TO_UNITS[oldIndex]); + return pointer; + } + SplitBlock(oldPointer, oldIndex, newIndex); + return oldPointer; + } + + /// + /// Free previously allocated space (the location and amount of space to free must be specified by using + /// a to indicate the location and a number of units to indicate the amount). + /// + /// + /// + public void FreeUnits(Pointer pointer, uint unitCount) + { + uint index = UNITS_TO_INDEX[unitCount - 1]; + _memoryNodes[index].Insert(pointer, INDEX_TO_UNITS[index]); + } + + public void SpecialFreeUnits(Pointer pointer) + { + if (pointer != _baseUnit) + { + _memoryNodes[0].Insert(pointer, 1); + } + else + { + MemoryNode memoryNode = pointer; + memoryNode.Stamp = uint.MaxValue; + _baseUnit += UNIT_SIZE; + } + } + + public Pointer MoveUnitsUp(Pointer oldPointer, uint unitCount) + { + uint index = UNITS_TO_INDEX[unitCount - 1]; + + if (oldPointer > _baseUnit + (16 * 1024) || oldPointer > _memoryNodes[index].Next) + { + return oldPointer; + } + + Pointer pointer = _memoryNodes[index].Remove(); + CopyUnits(pointer, oldPointer, unitCount); + unitCount = INDEX_TO_UNITS[index]; + + if (oldPointer != _baseUnit) + { + _memoryNodes[index].Insert(oldPointer, unitCount); + } + else + { + _baseUnit += unitCount * UNIT_SIZE; + } + + return pointer; + } + + /// + /// Expand the space allocated (in the single, large array) for the bytes of the data (ie. the "text") that is + /// being encoded or decoded. + /// + public void ExpandText() + { + MemoryNode memoryNode; + var counts = new uint[INDEX_COUNT]; + + while ((memoryNode = _baseUnit).Stamp == uint.MaxValue) + { + _baseUnit = memoryNode + memoryNode.UnitCount; + counts[UNITS_TO_INDEX[memoryNode.UnitCount - 1]]++; + memoryNode.Stamp = 0; + } + + for (uint index = 0; index < INDEX_COUNT; index++) + { + for ( + memoryNode = _memoryNodes[index]; + counts[index] != 0; + memoryNode = memoryNode.Next + ) { - Stop(); - _memory = new byte[HEAP_OFFSET + size]; // the single, large array of bytes - _heap = new Pointer(HEAP_OFFSET, _memory); // reserve bytes in the range 0 .. HeapOffset - 1 - _allocatorSize = size; + while (memoryNode.Next.Stamp == 0) + { + memoryNode.Unlink(); + _memoryNodes[index].Stamp--; + if (--counts[index] == 0) + { + break; + } + } } } + } - /// - /// Stop the allocator (free the single, large array of bytes). This can safely be called multiple times (without - /// intervening calls to ). - /// - /// - /// Because the array is on the large object heap it may not be freed immediately. - /// - public void Stop() - { - if (_allocatorSize != 0) - { - _allocatorSize = 0; - _memory = null; - _heap = Pointer.ZERO; - } - } + #endregion - /// - /// Determine how much memory (from the single, large array) is currenly in use. - /// - /// - public uint GetMemoryUsed() - { - uint memoryUsed = _allocatorSize - (_highUnit - _lowUnit) - (_baseUnit - _text); - for (uint index = 0; index < INDEX_COUNT; index++) - { - memoryUsed -= UNIT_SIZE * INDEX_TO_UNITS[index] * _memoryNodes[index].Stamp; - } - return memoryUsed; - } + #region Private Methods - /// - /// Allocate a given number of units from the single, large array. Each unit is bytes - /// in size. - /// - /// - /// - public Pointer AllocateUnits(uint unitCount) + private Pointer AllocateUnitsRare(uint index) + { + if (_glueCount == 0) { - uint index = UNITS_TO_INDEX[unitCount - 1]; + GlueFreeBlocks(); if (_memoryNodes[index].Available) { return _memoryNodes[index].Remove(); } - - Pointer allocatedBlock = _lowUnit; - _lowUnit += INDEX_TO_UNITS[index] * UNIT_SIZE; - if (_lowUnit <= _highUnit) - { - return allocatedBlock; - } - - _lowUnit -= INDEX_TO_UNITS[index] * UNIT_SIZE; - return AllocateUnitsRare(index); } - /// - /// Allocate enough space for a PpmContext instance in the single, large array. - /// - /// - public Pointer AllocateContext() + var oldIndex = index; + do { - if (_highUnit != _lowUnit) + if (++oldIndex == INDEX_COUNT) { - return (_highUnit -= UNIT_SIZE); + _glueCount--; + oldIndex = INDEX_TO_UNITS[index] * UNIT_SIZE; + return (_baseUnit - _text > oldIndex) ? (_baseUnit -= oldIndex) : Pointer.ZERO; } - if (_memoryNodes[0].Available) - { - return _memoryNodes[0].Remove(); - } - return AllocateUnitsRare(0); - } + } while (!_memoryNodes[oldIndex].Available); - /// - /// Increase the size of an existing allocation (represented by a ). - /// - /// - /// - /// - public Pointer ExpandUnits(Pointer oldPointer, uint oldUnitCount) - { - uint oldIndex = UNITS_TO_INDEX[oldUnitCount - 1]; - uint newIndex = UNITS_TO_INDEX[oldUnitCount]; - - if (oldIndex == newIndex) - { - return oldPointer; - } - - Pointer pointer = AllocateUnits(oldUnitCount + 1); - - if (pointer != Pointer.ZERO) - { - CopyUnits(pointer, oldPointer, oldUnitCount); - _memoryNodes[oldIndex].Insert(oldPointer, oldUnitCount); - } - - return pointer; - } - - /// - /// Decrease the size of an existing allocation (represented by a ). - /// - /// - /// - /// - /// - public Pointer ShrinkUnits(Pointer oldPointer, uint oldUnitCount, uint newUnitCount) - { - uint oldIndex = UNITS_TO_INDEX[oldUnitCount - 1]; - uint newIndex = UNITS_TO_INDEX[newUnitCount - 1]; - - if (oldIndex == newIndex) - { - return oldPointer; - } - - if (_memoryNodes[newIndex].Available) - { - Pointer pointer = _memoryNodes[newIndex].Remove(); - CopyUnits(pointer, oldPointer, newUnitCount); - _memoryNodes[oldIndex].Insert(oldPointer, INDEX_TO_UNITS[oldIndex]); - return pointer; - } - SplitBlock(oldPointer, oldIndex, newIndex); - return oldPointer; - } - - /// - /// Free previously allocated space (the location and amount of space to free must be specified by using - /// a to indicate the location and a number of units to indicate the amount). - /// - /// - /// - public void FreeUnits(Pointer pointer, uint unitCount) - { - uint index = UNITS_TO_INDEX[unitCount - 1]; - _memoryNodes[index].Insert(pointer, INDEX_TO_UNITS[index]); - } - - public void SpecialFreeUnits(Pointer pointer) - { - if (pointer != _baseUnit) - { - _memoryNodes[0].Insert(pointer, 1); - } - else - { - MemoryNode memoryNode = pointer; - memoryNode.Stamp = uint.MaxValue; - _baseUnit += UNIT_SIZE; - } - } - - public Pointer MoveUnitsUp(Pointer oldPointer, uint unitCount) - { - uint index = UNITS_TO_INDEX[unitCount - 1]; - - if (oldPointer > _baseUnit + 16 * 1024 || oldPointer > _memoryNodes[index].Next) - { - return oldPointer; - } - - Pointer pointer = _memoryNodes[index].Remove(); - CopyUnits(pointer, oldPointer, unitCount); - unitCount = INDEX_TO_UNITS[index]; - - if (oldPointer != _baseUnit) - { - _memoryNodes[index].Insert(oldPointer, unitCount); - } - else - { - _baseUnit += unitCount * UNIT_SIZE; - } - - return pointer; - } - - /// - /// Expand the space allocated (in the single, large array) for the bytes of the data (ie. the "text") that is - /// being encoded or decoded. - /// - public void ExpandText() - { - MemoryNode memoryNode; - uint[] counts = new uint[INDEX_COUNT]; - - while ((memoryNode = _baseUnit).Stamp == uint.MaxValue) - { - _baseUnit = memoryNode + memoryNode.UnitCount; - counts[UNITS_TO_INDEX[memoryNode.UnitCount - 1]]++; - memoryNode.Stamp = 0; - } - - for (uint index = 0; index < INDEX_COUNT; index++) - { - for ( - memoryNode = _memoryNodes[index]; - counts[index] != 0; - memoryNode = memoryNode.Next - ) - { - while (memoryNode.Next.Stamp == 0) - { - memoryNode.Unlink(); - _memoryNodes[index].Stamp--; - if (--counts[index] == 0) - { - break; - } - } - } - } - } - - #endregion - - #region Private Methods - - private Pointer AllocateUnitsRare(uint index) - { - if (_glueCount == 0) - { - GlueFreeBlocks(); - if (_memoryNodes[index].Available) - { - return _memoryNodes[index].Remove(); - } - } - - uint oldIndex = index; - do - { - if (++oldIndex == INDEX_COUNT) - { - _glueCount--; - oldIndex = INDEX_TO_UNITS[index] * UNIT_SIZE; - return (_baseUnit - _text > oldIndex) ? (_baseUnit -= oldIndex) : Pointer.ZERO; - } - } while (!_memoryNodes[oldIndex].Available); - - Pointer allocatedBlock = _memoryNodes[oldIndex].Remove(); - SplitBlock(allocatedBlock, oldIndex, index); - return allocatedBlock; - } - - private void SplitBlock(Pointer pointer, uint oldIndex, uint newIndex) - { - uint unitCountDifference = (uint)(INDEX_TO_UNITS[oldIndex] - INDEX_TO_UNITS[newIndex]); - Pointer newPointer = pointer + INDEX_TO_UNITS[newIndex] * UNIT_SIZE; - - uint index = UNITS_TO_INDEX[unitCountDifference - 1]; - if (INDEX_TO_UNITS[index] != unitCountDifference) - { - uint unitCount = INDEX_TO_UNITS[--index]; - _memoryNodes[index].Insert(newPointer, unitCount); - newPointer += unitCount * UNIT_SIZE; - unitCountDifference -= unitCount; - } - - _memoryNodes[UNITS_TO_INDEX[unitCountDifference - 1]].Insert( - newPointer, - unitCountDifference - ); - } - - private void GlueFreeBlocks() - { - MemoryNode memoryNode = new MemoryNode(LOCAL_OFFSET, _memory); - memoryNode.Stamp = 0; - memoryNode.Next = MemoryNode.ZERO; - memoryNode.UnitCount = 0; - - MemoryNode memoryNode0; - MemoryNode memoryNode1; - MemoryNode memoryNode2; - - if (_lowUnit != _highUnit) - { - _lowUnit[0] = 0; - } - - // Find all unused memory nodes. - - memoryNode1 = memoryNode; - for (uint index = 0; index < INDEX_COUNT; index++) - { - while (_memoryNodes[index].Available) - { - memoryNode0 = _memoryNodes[index].Remove(); - if (memoryNode0.UnitCount != 0) - { - while ( - (memoryNode2 = memoryNode0 + memoryNode0.UnitCount).Stamp - == uint.MaxValue - ) - { - memoryNode0.UnitCount = memoryNode0.UnitCount + memoryNode2.UnitCount; - memoryNode2.UnitCount = 0; - } - memoryNode1.Link(memoryNode0); - memoryNode1 = memoryNode0; - } - } - } - - // Coalesce the memory represented by the unused memory nodes. - - while (memoryNode.Available) - { - memoryNode0 = memoryNode.Remove(); - uint unitCount = memoryNode0.UnitCount; - if (unitCount != 0) - { - for (; unitCount > 128; unitCount -= 128, memoryNode0 += 128) - { - _memoryNodes[INDEX_COUNT - 1].Insert(memoryNode0, 128); - } - - uint index = UNITS_TO_INDEX[unitCount - 1]; - if (INDEX_TO_UNITS[index] != unitCount) - { - uint unitCountDifference = unitCount - INDEX_TO_UNITS[--index]; - _memoryNodes[unitCountDifference - 1].Insert( - memoryNode0 + (unitCount - unitCountDifference), - unitCountDifference - ); - } - - _memoryNodes[index].Insert(memoryNode0, INDEX_TO_UNITS[index]); - } - } - - _glueCount = 1 << 13; - } - - private void CopyUnits(Pointer target, Pointer source, uint unitCount) - { - do - { - target[0] = source[0]; - target[1] = source[1]; - target[2] = source[2]; - target[3] = source[3]; - target[4] = source[4]; - target[5] = source[5]; - target[6] = source[6]; - target[7] = source[7]; - target[8] = source[8]; - target[9] = source[9]; - target[10] = source[10]; - target[11] = source[11]; - target += UNIT_SIZE; - source += UNIT_SIZE; - } while (--unitCount != 0); - } - - #endregion + Pointer allocatedBlock = _memoryNodes[oldIndex].Remove(); + SplitBlock(allocatedBlock, oldIndex, index); + return allocatedBlock; } + + private void SplitBlock(Pointer pointer, uint oldIndex, uint newIndex) + { + var unitCountDifference = (uint)(INDEX_TO_UNITS[oldIndex] - INDEX_TO_UNITS[newIndex]); + var newPointer = pointer + (INDEX_TO_UNITS[newIndex] * UNIT_SIZE); + + uint index = UNITS_TO_INDEX[unitCountDifference - 1]; + if (INDEX_TO_UNITS[index] != unitCountDifference) + { + uint unitCount = INDEX_TO_UNITS[--index]; + _memoryNodes[index].Insert(newPointer, unitCount); + newPointer += unitCount * UNIT_SIZE; + unitCountDifference -= unitCount; + } + + _memoryNodes[UNITS_TO_INDEX[unitCountDifference - 1]].Insert( + newPointer, + unitCountDifference + ); + } + + private void GlueFreeBlocks() + { + var memoryNode = new MemoryNode(LOCAL_OFFSET, _memory); + memoryNode.Stamp = 0; + memoryNode.Next = MemoryNode.ZERO; + memoryNode.UnitCount = 0; + + MemoryNode memoryNode0; + MemoryNode memoryNode1; + MemoryNode memoryNode2; + + if (_lowUnit != _highUnit) + { + _lowUnit[0] = 0; + } + + // Find all unused memory nodes. + + memoryNode1 = memoryNode; + for (uint index = 0; index < INDEX_COUNT; index++) + { + while (_memoryNodes[index].Available) + { + memoryNode0 = _memoryNodes[index].Remove(); + if (memoryNode0.UnitCount != 0) + { + while ( + (memoryNode2 = memoryNode0 + memoryNode0.UnitCount).Stamp + == uint.MaxValue + ) + { + memoryNode0.UnitCount += memoryNode2.UnitCount; + memoryNode2.UnitCount = 0; + } + memoryNode1.Link(memoryNode0); + memoryNode1 = memoryNode0; + } + } + } + + // Coalesce the memory represented by the unused memory nodes. + + while (memoryNode.Available) + { + memoryNode0 = memoryNode.Remove(); + var unitCount = memoryNode0.UnitCount; + if (unitCount != 0) + { + for (; unitCount > 128; unitCount -= 128, memoryNode0 += 128) + { + _memoryNodes[INDEX_COUNT - 1].Insert(memoryNode0, 128); + } + + uint index = UNITS_TO_INDEX[unitCount - 1]; + if (INDEX_TO_UNITS[index] != unitCount) + { + var unitCountDifference = unitCount - INDEX_TO_UNITS[--index]; + _memoryNodes[unitCountDifference - 1].Insert( + memoryNode0 + (unitCount - unitCountDifference), + unitCountDifference + ); + } + + _memoryNodes[index].Insert(memoryNode0, INDEX_TO_UNITS[index]); + } + } + + _glueCount = 1 << 13; + } + + private void CopyUnits(Pointer target, Pointer source, uint unitCount) + { + do + { + target[0] = source[0]; + target[1] = source[1]; + target[2] = source[2]; + target[3] = source[3]; + target[4] = source[4]; + target[5] = source[5]; + target[6] = source[6]; + target[7] = source[7]; + target[8] = source[8]; + target[9] = source[9]; + target[10] = source[10]; + target[11] = source[11]; + target += UNIT_SIZE; + source += UNIT_SIZE; + } while (--unitCount != 0); + } + + #endregion } diff --git a/src/SharpCompress/Compressors/PPMd/I1/Coder.cs b/src/SharpCompress/Compressors/PPMd/I1/Coder.cs index 7f398284..c1644521 100644 --- a/src/SharpCompress/Compressors/PPMd/I1/Coder.cs +++ b/src/SharpCompress/Compressors/PPMd/I1/Coder.cs @@ -4,107 +4,106 @@ using System.IO; #endregion -namespace SharpCompress.Compressors.PPMd.I1 +namespace SharpCompress.Compressors.PPMd.I1; + +/// +/// A simple range coder. +/// +/// +/// Note that in most cases fields are used rather than properties for performance reasons (for example, +/// is a field rather than a property). +/// +internal class Coder { - /// - /// A simple range coder. - /// - /// - /// Note that in most cases fields are used rather than properties for performance reasons (for example, - /// is a field rather than a property). - /// - internal class Coder + private const uint RANGE_TOP = 1 << 24; + private const uint RANGE_BOTTOM = 1 << 15; + private uint _low; + private uint _code; + private uint _range; + + public uint _lowCount; + public uint _highCount; + public uint _scale; + + public void RangeEncoderInitialize() { - private const uint RANGE_TOP = 1 << 24; - private const uint RANGE_BOTTOM = 1 << 15; - private uint _low; - private uint _code; - private uint _range; + _low = 0; + _range = uint.MaxValue; + } - public uint _lowCount; - public uint _highCount; - public uint _scale; - - public void RangeEncoderInitialize() + public void RangeEncoderNormalize(Stream stream) + { + while ( + (_low ^ (_low + _range)) < RANGE_TOP + || _range < RANGE_BOTTOM + && ((_range = (uint)-_low & (RANGE_BOTTOM - 1)) != 0 || true) + ) { - _low = 0; - _range = uint.MaxValue; - } - - public void RangeEncoderNormalize(Stream stream) - { - while ( - (_low ^ (_low + _range)) < RANGE_TOP - || _range < RANGE_BOTTOM - && ((_range = (uint)-_low & (RANGE_BOTTOM - 1)) != 0 || true) - ) - { - stream.WriteByte((byte)(_low >> 24)); - _range <<= 8; - _low <<= 8; - } - } - - public void RangeEncodeSymbol() - { - _low += _lowCount * (_range /= _scale); - _range *= _highCount - _lowCount; - } - - public void RangeShiftEncodeSymbol(int rangeShift) - { - _low += _lowCount * (_range >>= rangeShift); - _range *= _highCount - _lowCount; - } - - public void RangeEncoderFlush(Stream stream) - { - for (uint index = 0; index < 4; index++) - { - stream.WriteByte((byte)(_low >> 24)); - _low <<= 8; - } - } - - public void RangeDecoderInitialize(Stream stream) - { - _low = 0; - _code = 0; - _range = uint.MaxValue; - for (uint index = 0; index < 4; index++) - { - _code = (_code << 8) | (byte)stream.ReadByte(); - } - } - - public void RangeDecoderNormalize(Stream stream) - { - while ( - (_low ^ (_low + _range)) < RANGE_TOP - || _range < RANGE_BOTTOM - && ((_range = (uint)-_low & (RANGE_BOTTOM - 1)) != 0 || true) - ) - { - _code = (_code << 8) | (byte)stream.ReadByte(); - _range <<= 8; - _low <<= 8; - } - } - - public uint RangeGetCurrentCount() - { - return (_code - _low) / (_range /= _scale); - } - - public uint RangeGetCurrentShiftCount(int rangeShift) - { - return (_code - _low) / (_range >>= rangeShift); - } - - public void RangeRemoveSubrange() - { - _low += _range * _lowCount; - _range *= _highCount - _lowCount; + stream.WriteByte((byte)(_low >> 24)); + _range <<= 8; + _low <<= 8; } } + + public void RangeEncodeSymbol() + { + _low += _lowCount * (_range /= _scale); + _range *= _highCount - _lowCount; + } + + public void RangeShiftEncodeSymbol(int rangeShift) + { + _low += _lowCount * (_range >>= rangeShift); + _range *= _highCount - _lowCount; + } + + public void RangeEncoderFlush(Stream stream) + { + for (uint index = 0; index < 4; index++) + { + stream.WriteByte((byte)(_low >> 24)); + _low <<= 8; + } + } + + public void RangeDecoderInitialize(Stream stream) + { + _low = 0; + _code = 0; + _range = uint.MaxValue; + for (uint index = 0; index < 4; index++) + { + _code = (_code << 8) | (byte)stream.ReadByte(); + } + } + + public void RangeDecoderNormalize(Stream stream) + { + while ( + (_low ^ (_low + _range)) < RANGE_TOP + || _range < RANGE_BOTTOM + && ((_range = (uint)-_low & (RANGE_BOTTOM - 1)) != 0 || true) + ) + { + _code = (_code << 8) | (byte)stream.ReadByte(); + _range <<= 8; + _low <<= 8; + } + } + + public uint RangeGetCurrentCount() + { + return (_code - _low) / (_range /= _scale); + } + + public uint RangeGetCurrentShiftCount(int rangeShift) + { + return (_code - _low) / (_range >>= rangeShift); + } + + public void RangeRemoveSubrange() + { + _low += _range * _lowCount; + _range *= _highCount - _lowCount; + } } diff --git a/src/SharpCompress/Compressors/PPMd/I1/MemoryNode.cs b/src/SharpCompress/Compressors/PPMd/I1/MemoryNode.cs index 1c6429ad..e9c64e53 100644 --- a/src/SharpCompress/Compressors/PPMd/I1/MemoryNode.cs +++ b/src/SharpCompress/Compressors/PPMd/I1/MemoryNode.cs @@ -1,254 +1,252 @@ #nullable disable -namespace SharpCompress.Compressors.PPMd.I1 +namespace SharpCompress.Compressors.PPMd.I1; + +/// +/// A structure containing a single address. The address represents a location in the +/// array. That location in the array contains information itself describing a section +/// of the array (ie. a block of memory). +/// +/// +/// +/// This must be a structure rather than a class because several places in the associated code assume that +/// is a value type (meaning that assignment creates a completely new copy of +/// the instance rather than just copying a reference to the same instance). +/// +/// +/// MemoryNode +/// 4 Stamp +/// 4 Next +/// 4 UnitCount +/// +/// +/// Note that is a field rather than a property for performance reasons. +/// +/// +internal struct MemoryNode { + public uint _address; + public byte[] _memory; + public static readonly MemoryNode ZERO = new MemoryNode(0, null); + public const int SIZE = 12; + /// - /// A structure containing a single address. The address represents a location in the - /// array. That location in the array contains information itself describing a section - /// of the array (ie. a block of memory). + /// Initializes a new instance of the structure. /// - /// - /// - /// This must be a structure rather than a class because several places in the associated code assume that - /// is a value type (meaning that assignment creates a completely new copy of - /// the instance rather than just copying a reference to the same instance). - /// - /// - /// MemoryNode - /// 4 Stamp - /// 4 Next - /// 4 UnitCount - /// - /// - /// Note that is a field rather than a property for performance reasons. - /// - /// - internal struct MemoryNode + public MemoryNode(uint address, byte[] memory) { - public uint _address; - public byte[] _memory; - public static readonly MemoryNode ZERO = new MemoryNode(0, null); - public const int SIZE = 12; + _address = address; + _memory = memory; + } - /// - /// Initializes a new instance of the structure. - /// - public MemoryNode(uint address, byte[] memory) + /// + /// Gets or sets the stamp. + /// + public uint Stamp + { + get => + _memory[_address] + | (((uint)_memory[_address + 1]) << 8) + | (((uint)_memory[_address + 2]) << 16) + | (((uint)_memory[_address + 3]) << 24); + set { - _address = address; - _memory = memory; - } - - /// - /// Gets or sets the stamp. - /// - public uint Stamp - { - get => - _memory[_address] - | ((uint)_memory[_address + 1]) << 8 - | ((uint)_memory[_address + 2]) << 16 - | ((uint)_memory[_address + 3]) << 24; - set - { - _memory[_address] = (byte)value; - _memory[_address + 1] = (byte)(value >> 8); - _memory[_address + 2] = (byte)(value >> 16); - _memory[_address + 3] = (byte)(value >> 24); - } - } - - /// - /// Gets or sets the next memory node. - /// - public MemoryNode Next - { - get => - new MemoryNode( - _memory[_address + 4] - | ((uint)_memory[_address + 5]) << 8 - | ((uint)_memory[_address + 6]) << 16 - | ((uint)_memory[_address + 7]) << 24, - _memory - ); - set - { - _memory[_address + 4] = (byte)value._address; - _memory[_address + 5] = (byte)(value._address >> 8); - _memory[_address + 6] = (byte)(value._address >> 16); - _memory[_address + 7] = (byte)(value._address >> 24); - } - } - - /// - /// Gets or sets the unit count. - /// - public uint UnitCount - { - get => - _memory[_address + 8] - | ((uint)_memory[_address + 9]) << 8 - | ((uint)_memory[_address + 10]) << 16 - | ((uint)_memory[_address + 11]) << 24; - set - { - _memory[_address + 8] = (byte)value; - _memory[_address + 9] = (byte)(value >> 8); - _memory[_address + 10] = (byte)(value >> 16); - _memory[_address + 11] = (byte)(value >> 24); - } - } - - /// - /// Gets whether there is a next memory node available. - /// - public bool Available => Next._address != 0; - - /// - /// Link in the provided memory node. - /// - /// - public void Link(MemoryNode memoryNode) - { - memoryNode.Next = Next; - Next = memoryNode; - } - - /// - /// Unlink this memory node. - /// - public void Unlink() - { - Next = Next.Next; - } - - /// - /// Insert the memory node into the linked list. - /// - /// - /// - public void Insert(MemoryNode memoryNode, uint unitCount) - { - Link(memoryNode); - memoryNode.Stamp = uint.MaxValue; - memoryNode.UnitCount = unitCount; - Stamp++; - } - - /// - /// Remove this memory node from the linked list. - /// - /// - public MemoryNode Remove() - { - MemoryNode next = Next; - Unlink(); - Stamp--; - return next; - } - - /// - /// Allow a pointer to be implicitly converted to a memory node. - /// - /// - /// - public static implicit operator MemoryNode(Pointer pointer) - { - return new MemoryNode(pointer._address, pointer._memory); - } - - /// - /// Allow pointer-like addition on a memory node. - /// - /// - /// - /// - public static MemoryNode operator +(MemoryNode memoryNode, int offset) - { - memoryNode._address = (uint)(memoryNode._address + offset * SIZE); - return memoryNode; - } - - /// - /// Allow pointer-like addition on a memory node. - /// - /// - /// - /// - public static MemoryNode operator +(MemoryNode memoryNode, uint offset) - { - memoryNode._address += offset * SIZE; - return memoryNode; - } - - /// - /// Allow pointer-like subtraction on a memory node. - /// - /// - /// - /// - public static MemoryNode operator -(MemoryNode memoryNode, int offset) - { - memoryNode._address = (uint)(memoryNode._address - offset * SIZE); - return memoryNode; - } - - /// - /// Allow pointer-like subtraction on a memory node. - /// - /// - /// - /// - public static MemoryNode operator -(MemoryNode memoryNode, uint offset) - { - memoryNode._address -= offset * SIZE; - return memoryNode; - } - - /// - /// Compare two memory nodes. - /// - /// - /// - /// - public static bool operator ==(MemoryNode memoryNode1, MemoryNode memoryNode2) - { - return memoryNode1._address == memoryNode2._address; - } - - /// - /// Compare two memory nodes. - /// - /// - /// - /// - public static bool operator !=(MemoryNode memoryNode1, MemoryNode memoryNode2) - { - return memoryNode1._address != memoryNode2._address; - } - - /// - /// Indicates whether this instance and a specified object are equal. - /// - /// true if obj and this instance are the same type and represent the same value; otherwise, false. - /// Another object to compare to. - public override bool Equals(object obj) - { - if (obj is MemoryNode) - { - MemoryNode memoryNode = (MemoryNode)obj; - return memoryNode._address == _address; - } - return base.Equals(obj); - } - - /// - /// Returns the hash code for this instance. - /// - /// A 32-bit signed integer that is the hash code for this instance. - public override int GetHashCode() - { - return _address.GetHashCode(); + _memory[_address] = (byte)value; + _memory[_address + 1] = (byte)(value >> 8); + _memory[_address + 2] = (byte)(value >> 16); + _memory[_address + 3] = (byte)(value >> 24); } } + + /// + /// Gets or sets the next memory node. + /// + public MemoryNode Next + { + get => + new MemoryNode( + _memory[_address + 4] + | (((uint)_memory[_address + 5]) << 8) + | (((uint)_memory[_address + 6]) << 16) + | (((uint)_memory[_address + 7]) << 24), + _memory + ); + set + { + _memory[_address + 4] = (byte)value._address; + _memory[_address + 5] = (byte)(value._address >> 8); + _memory[_address + 6] = (byte)(value._address >> 16); + _memory[_address + 7] = (byte)(value._address >> 24); + } + } + + /// + /// Gets or sets the unit count. + /// + public uint UnitCount + { + get => + _memory[_address + 8] + | (((uint)_memory[_address + 9]) << 8) + | (((uint)_memory[_address + 10]) << 16) + | (((uint)_memory[_address + 11]) << 24); + set + { + _memory[_address + 8] = (byte)value; + _memory[_address + 9] = (byte)(value >> 8); + _memory[_address + 10] = (byte)(value >> 16); + _memory[_address + 11] = (byte)(value >> 24); + } + } + + /// + /// Gets whether there is a next memory node available. + /// + public bool Available => Next._address != 0; + + /// + /// Link in the provided memory node. + /// + /// + public void Link(MemoryNode memoryNode) + { + memoryNode.Next = Next; + Next = memoryNode; + } + + /// + /// Unlink this memory node. + /// + public void Unlink() + { + Next = Next.Next; + } + + /// + /// Insert the memory node into the linked list. + /// + /// + /// + public void Insert(MemoryNode memoryNode, uint unitCount) + { + Link(memoryNode); + memoryNode.Stamp = uint.MaxValue; + memoryNode.UnitCount = unitCount; + Stamp++; + } + + /// + /// Remove this memory node from the linked list. + /// + /// + public MemoryNode Remove() + { + var next = Next; + Unlink(); + Stamp--; + return next; + } + + /// + /// Allow a pointer to be implicitly converted to a memory node. + /// + /// + /// + public static implicit operator MemoryNode(Pointer pointer) + { + return new MemoryNode(pointer._address, pointer._memory); + } + + /// + /// Allow pointer-like addition on a memory node. + /// + /// + /// + /// + public static MemoryNode operator +(MemoryNode memoryNode, int offset) + { + memoryNode._address = (uint)(memoryNode._address + (offset * SIZE)); + return memoryNode; + } + + /// + /// Allow pointer-like addition on a memory node. + /// + /// + /// + /// + public static MemoryNode operator +(MemoryNode memoryNode, uint offset) + { + memoryNode._address += offset * SIZE; + return memoryNode; + } + + /// + /// Allow pointer-like subtraction on a memory node. + /// + /// + /// + /// + public static MemoryNode operator -(MemoryNode memoryNode, int offset) + { + memoryNode._address = (uint)(memoryNode._address - (offset * SIZE)); + return memoryNode; + } + + /// + /// Allow pointer-like subtraction on a memory node. + /// + /// + /// + /// + public static MemoryNode operator -(MemoryNode memoryNode, uint offset) + { + memoryNode._address -= offset * SIZE; + return memoryNode; + } + + /// + /// Compare two memory nodes. + /// + /// + /// + /// + public static bool operator ==(MemoryNode memoryNode1, MemoryNode memoryNode2) + { + return memoryNode1._address == memoryNode2._address; + } + + /// + /// Compare two memory nodes. + /// + /// + /// + /// + public static bool operator !=(MemoryNode memoryNode1, MemoryNode memoryNode2) + { + return memoryNode1._address != memoryNode2._address; + } + + /// + /// Indicates whether this instance and a specified object are equal. + /// + /// true if obj and this instance are the same type and represent the same value; otherwise, false. + /// Another object to compare to. + public override bool Equals(object obj) + { + if (obj is MemoryNode memoryNode) + { + return memoryNode._address == _address; + } + return base.Equals(obj); + } + + /// + /// Returns the hash code for this instance. + /// + /// A 32-bit signed integer that is the hash code for this instance. + public override int GetHashCode() + { + return _address.GetHashCode(); + } } diff --git a/src/SharpCompress/Compressors/PPMd/I1/Model.cs b/src/SharpCompress/Compressors/PPMd/I1/Model.cs index d7f67b8b..aebfcae8 100644 --- a/src/SharpCompress/Compressors/PPMd/I1/Model.cs +++ b/src/SharpCompress/Compressors/PPMd/I1/Model.cs @@ -6,960 +6,959 @@ using System.IO; // This is a port of Dmitry Shkarin's PPMd Variant I Revision 1. // Ported by Michael Bone (mjbone03@yahoo.com.au). -namespace SharpCompress.Compressors.PPMd.I1 +namespace SharpCompress.Compressors.PPMd.I1; + +/// +/// The model. +/// +internal partial class Model { - /// - /// The model. - /// - internal partial class Model + public const uint SIGNATURE = 0x84acaf8fU; + public const char VARIANT = 'I'; + public const int MAXIMUM_ORDER = 16; // maximum allowed model order + + private const byte UPPER_FREQUENCY = 5; + private const byte INTERVAL_BIT_COUNT = 7; + private const byte PERIOD_BIT_COUNT = 7; + private const byte TOTAL_BIT_COUNT = INTERVAL_BIT_COUNT + PERIOD_BIT_COUNT; + private const uint INTERVAL = 1 << INTERVAL_BIT_COUNT; + private const uint BINARY_SCALE = 1 << TOTAL_BIT_COUNT; + private const uint MAXIMUM_FREQUENCY = 124; + private const uint ORDER_BOUND = 9; + + private readonly See2Context[,] _see2Contexts; + private readonly See2Context _emptySee2Context; + private PpmContext _maximumContext; + private readonly ushort[,] _binarySummary = new ushort[25, 64]; // binary SEE-contexts + private readonly byte[] _numberStatisticsToBinarySummaryIndex = new byte[256]; + private readonly byte[] _probabilities = new byte[260]; + private readonly byte[] _characterMask = new byte[256]; + private byte _escapeCount; + private int _modelOrder; + private int _orderFall; + private int _initialEscape; + private int _initialRunLength; + private int _runLength; + private byte _previousSuccess; + private byte _numberMasked; + private ModelRestorationMethod _method; + private PpmState _foundState; // found next state transition + + private Allocator _allocator; + private Coder _coder; + private PpmContext _minimumContext; + private byte _numberStatistics; + private readonly PpmState[] _decodeStates = new PpmState[256]; + + private static readonly ushort[] INITIAL_BINARY_ESCAPES = { - public const uint SIGNATURE = 0x84acaf8fU; - public const char VARIANT = 'I'; - public const int MAXIMUM_ORDER = 16; // maximum allowed model order + 0x3CDD, + 0x1F3F, + 0x59BF, + 0x48F3, + 0x64A1, + 0x5ABC, + 0x6632, + 0x6051 + }; - private const byte UPPER_FREQUENCY = 5; - private const byte INTERVAL_BIT_COUNT = 7; - private const byte PERIOD_BIT_COUNT = 7; - private const byte TOTAL_BIT_COUNT = INTERVAL_BIT_COUNT + PERIOD_BIT_COUNT; - private const uint INTERVAL = 1 << INTERVAL_BIT_COUNT; - private const uint BINARY_SCALE = 1 << TOTAL_BIT_COUNT; - private const uint MAXIMUM_FREQUENCY = 124; - private const uint ORDER_BOUND = 9; + private static ReadOnlySpan EXPONENTIAL_ESCAPES => + new byte[] { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 }; - private readonly See2Context[,] _see2Contexts; - private readonly See2Context _emptySee2Context; - private PpmContext _maximumContext; - private readonly ushort[,] _binarySummary = new ushort[25, 64]; // binary SEE-contexts - private readonly byte[] _numberStatisticsToBinarySummaryIndex = new byte[256]; - private readonly byte[] _probabilities = new byte[260]; - private readonly byte[] _characterMask = new byte[256]; - private byte _escapeCount; - private int _modelOrder; - private int _orderFall; - private int _initialEscape; - private int _initialRunLength; - private int _runLength; - private byte _previousSuccess; - private byte _numberMasked; - private ModelRestorationMethod _method; - private PpmState _foundState; // found next state transition + #region Public Methods - private Allocator _allocator; - private Coder _coder; - private PpmContext _minimumContext; - private byte _numberStatistics; - private readonly PpmState[] _decodeStates = new PpmState[256]; + public Model() + { + // Construct the conversion table for number statistics. Initially it will contain the following values. + // + // 0 2 4 4 4 4 4 4 4 4 4 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 + // 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 + // 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 + // 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 + // 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 + // 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 + // 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 + // 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 - private static readonly ushort[] INITIAL_BINARY_ESCAPES = + _numberStatisticsToBinarySummaryIndex[0] = 2 * 0; + _numberStatisticsToBinarySummaryIndex[1] = 2 * 1; + for (var index = 2; index < 11; index++) { - 0x3CDD, - 0x1F3F, - 0x59BF, - 0x48F3, - 0x64A1, - 0x5ABC, - 0x6632, - 0x6051 - }; - - private static ReadOnlySpan EXPONENTIAL_ESCAPES => - new byte[] { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 }; - - #region Public Methods - - public Model() + _numberStatisticsToBinarySummaryIndex[index] = 2 * 2; + } + for (var index = 11; index < 256; index++) { - // Construct the conversion table for number statistics. Initially it will contain the following values. - // - // 0 2 4 4 4 4 4 4 4 4 4 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 - // 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 - // 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 - // 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 - // 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 - // 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 - // 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 - // 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 - - _numberStatisticsToBinarySummaryIndex[0] = 2 * 0; - _numberStatisticsToBinarySummaryIndex[1] = 2 * 1; - for (int index = 2; index < 11; index++) - { - _numberStatisticsToBinarySummaryIndex[index] = 2 * 2; - } - for (int index = 11; index < 256; index++) - { - _numberStatisticsToBinarySummaryIndex[index] = 2 * 3; - } - - // Construct the probability table. Initially it will contain the following values (depending on the value of - // the upper frequency). - // - // 00 01 02 03 04 05 06 06 07 07 07 08 08 08 08 09 09 09 09 09 10 10 10 10 10 10 11 11 11 11 11 11 - // 11 12 12 12 12 12 12 12 12 13 13 13 13 13 13 13 13 13 14 14 14 14 14 14 14 14 14 14 15 15 15 15 - // 15 15 15 15 15 15 15 16 16 16 16 16 16 16 16 16 16 16 16 17 17 17 17 17 17 17 17 17 17 17 17 17 - // 18 18 18 18 18 18 18 18 18 18 18 18 18 18 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 20 20 20 - // 20 20 20 20 20 20 20 20 20 20 20 20 20 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 22 22 - // 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 - // 23 23 23 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 25 25 25 25 25 25 25 25 25 - // 25 25 25 25 25 25 25 25 25 25 25 25 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 - // 26 26 27 27 - - uint count = 1; - uint step = 1; - uint probability = UPPER_FREQUENCY; - - for (int index = 0; index < UPPER_FREQUENCY; index++) - { - _probabilities[index] = (byte)index; - } - - for (int index = UPPER_FREQUENCY; index < 260; index++) - { - _probabilities[index] = (byte)probability; - count--; - if (count == 0) - { - step++; - count = step; - probability++; - } - } - - // Create the context array. - - _see2Contexts = new See2Context[24, 32]; - for (int index1 = 0; index1 < 24; index1++) - { - for (int index2 = 0; index2 < 32; index2++) - { - _see2Contexts[index1, index2] = new See2Context(); - } - } - - // Set the signature (identifying the algorithm). - - _emptySee2Context = new See2Context(); - _emptySee2Context._summary = (ushort)(SIGNATURE & 0x0000ffff); - _emptySee2Context._shift = (byte)((SIGNATURE >> 16) & 0x000000ff); - _emptySee2Context._count = (byte)(SIGNATURE >> 24); + _numberStatisticsToBinarySummaryIndex[index] = 2 * 3; } - /// - /// Encode (ie. compress) a given source stream, writing the encoded result to the target stream. - /// - public void Encode(Stream target, Stream source, PpmdProperties properties) + // Construct the probability table. Initially it will contain the following values (depending on the value of + // the upper frequency). + // + // 00 01 02 03 04 05 06 06 07 07 07 08 08 08 08 09 09 09 09 09 10 10 10 10 10 10 11 11 11 11 11 11 + // 11 12 12 12 12 12 12 12 12 13 13 13 13 13 13 13 13 13 14 14 14 14 14 14 14 14 14 14 15 15 15 15 + // 15 15 15 15 15 15 15 16 16 16 16 16 16 16 16 16 16 16 16 17 17 17 17 17 17 17 17 17 17 17 17 17 + // 18 18 18 18 18 18 18 18 18 18 18 18 18 18 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 20 20 20 + // 20 20 20 20 20 20 20 20 20 20 20 20 20 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 22 22 + // 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 + // 23 23 23 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 25 25 25 25 25 25 25 25 25 + // 25 25 25 25 25 25 25 25 25 25 25 25 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 + // 26 26 27 27 + + uint count = 1; + uint step = 1; + uint probability = UPPER_FREQUENCY; + + for (var index = 0; index < UPPER_FREQUENCY; index++) { - if (target is null) - { - throw new ArgumentNullException(nameof(target)); - } - - if (source is null) - { - throw new ArgumentNullException(nameof(source)); - } - - EncodeStart(properties); - EncodeBlock(target, source, true); + _probabilities[index] = (byte)index; } - internal Coder EncodeStart(PpmdProperties properties) + for (int index = UPPER_FREQUENCY; index < 260; index++) { - _allocator = properties._allocator; - _coder = new Coder(); - _coder.RangeEncoderInitialize(); - StartModel(properties.ModelOrder, properties.RestorationMethod); - return _coder; - } - - internal void EncodeBlock(Stream target, Stream source, bool final) - { - while (true) + _probabilities[index] = (byte)probability; + count--; + if (count == 0) { - _minimumContext = _maximumContext; - _numberStatistics = _minimumContext.NumberStatistics; - - int c = source.ReadByte(); - if (c < 0 && !final) - { - return; - } - - if (_numberStatistics != 0) - { - EncodeSymbol1(c, _minimumContext); - _coder.RangeEncodeSymbol(); - } - else - { - EncodeBinarySymbol(c, _minimumContext); - _coder.RangeShiftEncodeSymbol(TOTAL_BIT_COUNT); - } - - while (_foundState == PpmState.ZERO) - { - _coder.RangeEncoderNormalize(target); - do - { - _orderFall++; - _minimumContext = _minimumContext.Suffix; - if (_minimumContext == PpmContext.ZERO) - { - goto StopEncoding; - } - } while (_minimumContext.NumberStatistics == _numberMasked); - EncodeSymbol2(c, _minimumContext); - _coder.RangeEncodeSymbol(); - } - - if (_orderFall == 0 && (Pointer)_foundState.Successor >= _allocator._baseUnit) - { - _maximumContext = _foundState.Successor; - } - else - { - UpdateModel(_minimumContext); - if (_escapeCount == 0) - { - ClearMask(); - } - } - - _coder.RangeEncoderNormalize(target); - } - - StopEncoding: - _coder.RangeEncoderFlush(target); - } - - /// - /// Dencode (ie. decompress) a given source stream, writing the decoded result to the target stream. - /// - public void Decode(Stream target, Stream source, PpmdProperties properties) - { - if (target is null) - { - throw new ArgumentNullException(nameof(target)); - } - - if (source is null) - { - throw new ArgumentNullException(nameof(source)); - } - - DecodeStart(source, properties); - byte[] buffer = new byte[65536]; - int read; - while ((read = DecodeBlock(source, buffer, 0, buffer.Length)) != 0) - { - target.Write(buffer, 0, read); + step++; + count = step; + probability++; } } - internal Coder DecodeStart(Stream source, PpmdProperties properties) + // Create the context array. + + _see2Contexts = new See2Context[24, 32]; + for (var index1 = 0; index1 < 24; index1++) + { + for (var index2 = 0; index2 < 32; index2++) + { + _see2Contexts[index1, index2] = new See2Context(); + } + } + + // Set the signature (identifying the algorithm). + + _emptySee2Context = new See2Context(); + _emptySee2Context._summary = (ushort)(SIGNATURE & 0x0000ffff); + _emptySee2Context._shift = (byte)((SIGNATURE >> 16) & 0x000000ff); + _emptySee2Context._count = (byte)(SIGNATURE >> 24); + } + + /// + /// Encode (ie. compress) a given source stream, writing the encoded result to the target stream. + /// + public void Encode(Stream target, Stream source, PpmdProperties properties) + { + if (target is null) + { + throw new ArgumentNullException(nameof(target)); + } + + if (source is null) + { + throw new ArgumentNullException(nameof(source)); + } + + EncodeStart(properties); + EncodeBlock(target, source, true); + } + + internal Coder EncodeStart(PpmdProperties properties) + { + _allocator = properties._allocator; + _coder = new Coder(); + _coder.RangeEncoderInitialize(); + StartModel(properties.ModelOrder, properties.RestorationMethod); + return _coder; + } + + internal void EncodeBlock(Stream target, Stream source, bool final) + { + while (true) { - _allocator = properties._allocator; - _coder = new Coder(); - _coder.RangeDecoderInitialize(source); - StartModel(properties.ModelOrder, properties.RestorationMethod); _minimumContext = _maximumContext; _numberStatistics = _minimumContext.NumberStatistics; - return _coder; - } - internal int DecodeBlock(Stream source, byte[] buffer, int offset, int count) - { - if (_minimumContext == PpmContext.ZERO) + var c = source.ReadByte(); + if (c < 0 && !final) { - return 0; - } - - int total = 0; - while (total < count) - { - if (_numberStatistics != 0) - { - DecodeSymbol1(_minimumContext); - } - else - { - DecodeBinarySymbol(_minimumContext); - } - - _coder.RangeRemoveSubrange(); - - while (_foundState == PpmState.ZERO) - { - _coder.RangeDecoderNormalize(source); - do - { - _orderFall++; - _minimumContext = _minimumContext.Suffix; - if (_minimumContext == PpmContext.ZERO) - { - goto StopDecoding; - } - } while (_minimumContext.NumberStatistics == _numberMasked); - DecodeSymbol2(_minimumContext); - _coder.RangeRemoveSubrange(); - } - - buffer[offset] = _foundState.Symbol; - offset++; - total++; - - if (_orderFall == 0 && (Pointer)_foundState.Successor >= _allocator._baseUnit) - { - _maximumContext = _foundState.Successor; - } - else - { - UpdateModel(_minimumContext); - if (_escapeCount == 0) - { - ClearMask(); - } - } - - _minimumContext = _maximumContext; - _numberStatistics = _minimumContext.NumberStatistics; - _coder.RangeDecoderNormalize(source); - } - - StopDecoding: - return total; - } - - #endregion - - #region Private Methods - - /// - /// Initialise the model (unless the model order is set to 1 in which case the model should be cleared so that - /// the statistics are carried over, allowing "solid" mode compression). - /// - private void StartModel(int modelOrder, ModelRestorationMethod modelRestorationMethod) - { - Array.Clear(_characterMask, 0, _characterMask.Length); - _escapeCount = 1; - - // Compress in "solid" mode if the model order value is set to 1 (this will examine the current PPM context - // structures to determine the value of orderFall). - - if (modelOrder < 2) - { - _orderFall = _modelOrder; - for ( - PpmContext context = _maximumContext; - context.Suffix != PpmContext.ZERO; - context = context.Suffix - ) - { - _orderFall--; - } return; } - _modelOrder = modelOrder; - _orderFall = modelOrder; - _method = modelRestorationMethod; - _allocator.Initialize(); - _initialRunLength = -((modelOrder < 12) ? modelOrder : 12) - 1; - _runLength = _initialRunLength; - - // Allocate the context structure. - - _maximumContext = _allocator.AllocateContext(); - _maximumContext.Suffix = PpmContext.ZERO; - _maximumContext.NumberStatistics = 255; - _maximumContext.SummaryFrequency = (ushort)(_maximumContext.NumberStatistics + 2); - _maximumContext.Statistics = _allocator.AllocateUnits(256 / 2); - - // allocates enough space for 256 PPM states (each is 6 bytes) - - _previousSuccess = 0; - for (int index = 0; index < 256; index++) + if (_numberStatistics != 0) { - PpmState state = _maximumContext.Statistics[index]; - state.Symbol = (byte)index; - state.Frequency = 1; - state.Successor = PpmContext.ZERO; - } - - uint probability = 0; - for (int index1 = 0; probability < 25; probability++) - { - while (_probabilities[index1] == probability) - { - index1++; - } - for (int index2 = 0; index2 < 8; index2++) - { - _binarySummary[probability, index2] = (ushort)( - BINARY_SCALE - INITIAL_BINARY_ESCAPES[index2] / (index1 + 1) - ); - } - for (int index2 = 8; index2 < 64; index2 += 8) - { - for (int index3 = 0; index3 < 8; index3++) - { - _binarySummary[probability, index2 + index3] = _binarySummary[ - probability, - index3 - ]; - } - } - } - - probability = 0; - for (uint index1 = 0; probability < 24; probability++) - { - while (_probabilities[index1 + 3] == probability + 3) - { - index1++; - } - for (int index2 = 0; index2 < 32; index2++) - { - _see2Contexts[probability, index2].Initialize(2 * index1 + 5); - } - } - } - - private void UpdateModel(PpmContext minimumContext) - { - PpmState state = PpmState.ZERO; - PpmContext successor; - PpmContext currentContext = _maximumContext; - uint numberStatistics; - uint ns1; - uint cf; - uint sf; - uint s0; - uint foundStateFrequency = _foundState.Frequency; - byte foundStateSymbol = _foundState.Symbol; - byte symbol; - byte flag; - - PpmContext foundStateSuccessor = _foundState.Successor; - PpmContext context = minimumContext.Suffix; - - if ((foundStateFrequency < MAXIMUM_FREQUENCY / 4) && (context != PpmContext.ZERO)) - { - if (context.NumberStatistics != 0) - { - state = context.Statistics; - if (state.Symbol != foundStateSymbol) - { - do - { - symbol = state[1].Symbol; - state++; - } while (symbol != foundStateSymbol); - if (state[0].Frequency >= state[-1].Frequency) - { - Swap(state[0], state[-1]); - state--; - } - } - cf = (uint)((state.Frequency < MAXIMUM_FREQUENCY - 9) ? 2 : 0); - state.Frequency += (byte)cf; - context.SummaryFrequency += (byte)cf; - } - else - { - state = context.FirstState; - state.Frequency += (byte)((state.Frequency < 32) ? 1 : 0); - } - } - - if (_orderFall == 0 && foundStateSuccessor != PpmContext.ZERO) - { - _foundState.Successor = CreateSuccessors(true, state, minimumContext); - if (_foundState.Successor == PpmContext.ZERO) - { - goto RestartModel; - } - _maximumContext = _foundState.Successor; - return; - } - - _allocator._text[0] = foundStateSymbol; - _allocator._text++; - successor = _allocator._text; - - if (_allocator._text >= _allocator._baseUnit) - { - goto RestartModel; - } - - if (foundStateSuccessor != PpmContext.ZERO) - { - if (foundStateSuccessor < _allocator._baseUnit) - { - foundStateSuccessor = CreateSuccessors(false, state, minimumContext); - } + EncodeSymbol1(c, _minimumContext); + _coder.RangeEncodeSymbol(); } else { - foundStateSuccessor = ReduceOrder(state, minimumContext); + EncodeBinarySymbol(c, _minimumContext); + _coder.RangeShiftEncodeSymbol(TOTAL_BIT_COUNT); } - if (foundStateSuccessor == PpmContext.ZERO) + while (_foundState == PpmState.ZERO) + { + _coder.RangeEncoderNormalize(target); + do + { + _orderFall++; + _minimumContext = _minimumContext.Suffix; + if (_minimumContext == PpmContext.ZERO) + { + goto StopEncoding; + } + } while (_minimumContext.NumberStatistics == _numberMasked); + EncodeSymbol2(c, _minimumContext); + _coder.RangeEncodeSymbol(); + } + + if (_orderFall == 0 && (Pointer)_foundState.Successor >= _allocator._baseUnit) + { + _maximumContext = _foundState.Successor; + } + else + { + UpdateModel(_minimumContext); + if (_escapeCount == 0) + { + ClearMask(); + } + } + + _coder.RangeEncoderNormalize(target); + } + + StopEncoding: + _coder.RangeEncoderFlush(target); + } + + /// + /// Dencode (ie. decompress) a given source stream, writing the decoded result to the target stream. + /// + public void Decode(Stream target, Stream source, PpmdProperties properties) + { + if (target is null) + { + throw new ArgumentNullException(nameof(target)); + } + + if (source is null) + { + throw new ArgumentNullException(nameof(source)); + } + + DecodeStart(source, properties); + var buffer = new byte[65536]; + int read; + while ((read = DecodeBlock(source, buffer, 0, buffer.Length)) != 0) + { + target.Write(buffer, 0, read); + } + } + + internal Coder DecodeStart(Stream source, PpmdProperties properties) + { + _allocator = properties._allocator; + _coder = new Coder(); + _coder.RangeDecoderInitialize(source); + StartModel(properties.ModelOrder, properties.RestorationMethod); + _minimumContext = _maximumContext; + _numberStatistics = _minimumContext.NumberStatistics; + return _coder; + } + + internal int DecodeBlock(Stream source, byte[] buffer, int offset, int count) + { + if (_minimumContext == PpmContext.ZERO) + { + return 0; + } + + var total = 0; + while (total < count) + { + if (_numberStatistics != 0) + { + DecodeSymbol1(_minimumContext); + } + else + { + DecodeBinarySymbol(_minimumContext); + } + + _coder.RangeRemoveSubrange(); + + while (_foundState == PpmState.ZERO) + { + _coder.RangeDecoderNormalize(source); + do + { + _orderFall++; + _minimumContext = _minimumContext.Suffix; + if (_minimumContext == PpmContext.ZERO) + { + goto StopDecoding; + } + } while (_minimumContext.NumberStatistics == _numberMasked); + DecodeSymbol2(_minimumContext); + _coder.RangeRemoveSubrange(); + } + + buffer[offset] = _foundState.Symbol; + offset++; + total++; + + if (_orderFall == 0 && (Pointer)_foundState.Successor >= _allocator._baseUnit) + { + _maximumContext = _foundState.Successor; + } + else + { + UpdateModel(_minimumContext); + if (_escapeCount == 0) + { + ClearMask(); + } + } + + _minimumContext = _maximumContext; + _numberStatistics = _minimumContext.NumberStatistics; + _coder.RangeDecoderNormalize(source); + } + + StopDecoding: + return total; + } + + #endregion + + #region Private Methods + + /// + /// Initialise the model (unless the model order is set to 1 in which case the model should be cleared so that + /// the statistics are carried over, allowing "solid" mode compression). + /// + private void StartModel(int modelOrder, ModelRestorationMethod modelRestorationMethod) + { + Array.Clear(_characterMask, 0, _characterMask.Length); + _escapeCount = 1; + + // Compress in "solid" mode if the model order value is set to 1 (this will examine the current PPM context + // structures to determine the value of orderFall). + + if (modelOrder < 2) + { + _orderFall = _modelOrder; + for ( + var context = _maximumContext; + context.Suffix != PpmContext.ZERO; + context = context.Suffix + ) + { + _orderFall--; + } + return; + } + + _modelOrder = modelOrder; + _orderFall = modelOrder; + _method = modelRestorationMethod; + _allocator.Initialize(); + _initialRunLength = -((modelOrder < 12) ? modelOrder : 12) - 1; + _runLength = _initialRunLength; + + // Allocate the context structure. + + _maximumContext = _allocator.AllocateContext(); + _maximumContext.Suffix = PpmContext.ZERO; + _maximumContext.NumberStatistics = 255; + _maximumContext.SummaryFrequency = (ushort)(_maximumContext.NumberStatistics + 2); + _maximumContext.Statistics = _allocator.AllocateUnits(256 / 2); + + // allocates enough space for 256 PPM states (each is 6 bytes) + + _previousSuccess = 0; + for (var index = 0; index < 256; index++) + { + var state = _maximumContext.Statistics[index]; + state.Symbol = (byte)index; + state.Frequency = 1; + state.Successor = PpmContext.ZERO; + } + + uint probability = 0; + for (var index1 = 0; probability < 25; probability++) + { + while (_probabilities[index1] == probability) + { + index1++; + } + for (var index2 = 0; index2 < 8; index2++) + { + _binarySummary[probability, index2] = (ushort)( + BINARY_SCALE - (INITIAL_BINARY_ESCAPES[index2] / (index1 + 1)) + ); + } + for (var index2 = 8; index2 < 64; index2 += 8) + { + for (var index3 = 0; index3 < 8; index3++) + { + _binarySummary[probability, index2 + index3] = _binarySummary[ + probability, + index3 + ]; + } + } + } + + probability = 0; + for (uint index1 = 0; probability < 24; probability++) + { + while (_probabilities[index1 + 3] == probability + 3) + { + index1++; + } + for (var index2 = 0; index2 < 32; index2++) + { + _see2Contexts[probability, index2].Initialize((2 * index1) + 5); + } + } + } + + private void UpdateModel(PpmContext minimumContext) + { + var state = PpmState.ZERO; + PpmContext successor; + var currentContext = _maximumContext; + uint numberStatistics; + uint ns1; + uint cf; + uint sf; + uint s0; + uint foundStateFrequency = _foundState.Frequency; + var foundStateSymbol = _foundState.Symbol; + byte symbol; + byte flag; + + var foundStateSuccessor = _foundState.Successor; + var context = minimumContext.Suffix; + + if ((foundStateFrequency < MAXIMUM_FREQUENCY / 4) && (context != PpmContext.ZERO)) + { + if (context.NumberStatistics != 0) + { + state = context.Statistics; + if (state.Symbol != foundStateSymbol) + { + do + { + symbol = state[1].Symbol; + state++; + } while (symbol != foundStateSymbol); + if (state[0].Frequency >= state[-1].Frequency) + { + Swap(state[0], state[-1]); + state--; + } + } + cf = (uint)((state.Frequency < MAXIMUM_FREQUENCY - 9) ? 2 : 0); + state.Frequency += (byte)cf; + context.SummaryFrequency += (byte)cf; + } + else + { + state = context.FirstState; + state.Frequency += (byte)((state.Frequency < 32) ? 1 : 0); + } + } + + if (_orderFall == 0 && foundStateSuccessor != PpmContext.ZERO) + { + _foundState.Successor = CreateSuccessors(true, state, minimumContext); + if (_foundState.Successor == PpmContext.ZERO) { goto RestartModel; } + _maximumContext = _foundState.Successor; + return; + } - if (--_orderFall == 0) - { - successor = foundStateSuccessor; - _allocator._text -= (_maximumContext != minimumContext) ? 1 : 0; - } - else if (_method > ModelRestorationMethod.Freeze) - { - successor = foundStateSuccessor; - _allocator._text = _allocator._heap; - _orderFall = 0; - } + _allocator._text[0] = foundStateSymbol; + _allocator._text++; + successor = _allocator._text; - numberStatistics = minimumContext.NumberStatistics; - s0 = minimumContext.SummaryFrequency - numberStatistics - foundStateFrequency; - flag = (byte)((foundStateSymbol >= 0x40) ? 0x08 : 0x00); - for (; currentContext != minimumContext; currentContext = currentContext.Suffix) + if (_allocator._text >= _allocator._baseUnit) + { + goto RestartModel; + } + + if (foundStateSuccessor != PpmContext.ZERO) + { + if (foundStateSuccessor < _allocator._baseUnit) { - ns1 = currentContext.NumberStatistics; - if (ns1 != 0) + foundStateSuccessor = CreateSuccessors(false, state, minimumContext); + } + } + else + { + foundStateSuccessor = ReduceOrder(state, minimumContext); + } + + if (foundStateSuccessor == PpmContext.ZERO) + { + goto RestartModel; + } + + if (--_orderFall == 0) + { + successor = foundStateSuccessor; + _allocator._text -= (_maximumContext != minimumContext) ? 1 : 0; + } + else if (_method > ModelRestorationMethod.Freeze) + { + successor = foundStateSuccessor; + _allocator._text = _allocator._heap; + _orderFall = 0; + } + + numberStatistics = minimumContext.NumberStatistics; + s0 = minimumContext.SummaryFrequency - numberStatistics - foundStateFrequency; + flag = (byte)((foundStateSymbol >= 0x40) ? 0x08 : 0x00); + for (; currentContext != minimumContext; currentContext = currentContext.Suffix) + { + ns1 = currentContext.NumberStatistics; + if (ns1 != 0) + { + if ((ns1 & 1) != 0) { - if ((ns1 & 1) != 0) - { - state = _allocator.ExpandUnits(currentContext.Statistics, (ns1 + 1) >> 1); - if (state == PpmState.ZERO) - { - goto RestartModel; - } - currentContext.Statistics = state; - } - currentContext.SummaryFrequency += (ushort)( - (3 * ns1 + 1 < numberStatistics) ? 1 : 0 - ); - } - else - { - state = _allocator.AllocateUnits(1); + state = _allocator.ExpandUnits(currentContext.Statistics, (ns1 + 1) >> 1); if (state == PpmState.ZERO) { goto RestartModel; } - Copy(state, currentContext.FirstState); currentContext.Statistics = state; - if (state.Frequency < MAXIMUM_FREQUENCY / 4 - 1) - { - state.Frequency += state.Frequency; - } - else - { - state.Frequency = (byte)(MAXIMUM_FREQUENCY - 4); - } - currentContext.SummaryFrequency = (ushort)( - state.Frequency + _initialEscape + ((numberStatistics > 2) ? 1 : 0) - ); } - - cf = (uint)(2 * foundStateFrequency * (currentContext.SummaryFrequency + 6)); - sf = s0 + currentContext.SummaryFrequency; - - if (cf < 6 * sf) + currentContext.SummaryFrequency += (ushort)( + ((3 * ns1) + 1 < numberStatistics) ? 1 : 0 + ); + } + else + { + state = _allocator.AllocateUnits(1); + if (state == PpmState.ZERO) { - cf = (uint)(1 + ((cf > sf) ? 1 : 0) + ((cf >= 4 * sf) ? 1 : 0)); - currentContext.SummaryFrequency += 4; + goto RestartModel; + } + Copy(state, currentContext.FirstState); + currentContext.Statistics = state; + if (state.Frequency < (MAXIMUM_FREQUENCY / 4) - 1) + { + state.Frequency += state.Frequency; } else { - cf = (uint)( - 4 - + ((cf > 9 * sf) ? 1 : 0) - + ((cf > 12 * sf) ? 1 : 0) - + ((cf > 15 * sf) ? 1 : 0) - ); - currentContext.SummaryFrequency += (ushort)cf; + state.Frequency = (byte)(MAXIMUM_FREQUENCY - 4); } - - state = currentContext.Statistics + (++currentContext.NumberStatistics); - state.Successor = successor; - state.Symbol = foundStateSymbol; - state.Frequency = (byte)cf; - currentContext.Flags |= flag; + currentContext.SummaryFrequency = (ushort)( + state.Frequency + _initialEscape + ((numberStatistics > 2) ? 1 : 0) + ); } - _maximumContext = foundStateSuccessor; - return; + cf = (uint)(2 * foundStateFrequency * (currentContext.SummaryFrequency + 6)); + sf = s0 + currentContext.SummaryFrequency; - RestartModel: - RestoreModel(currentContext, minimumContext, foundStateSuccessor); + if (cf < 6 * sf) + { + cf = (uint)(1 + ((cf > sf) ? 1 : 0) + ((cf >= 4 * sf) ? 1 : 0)); + currentContext.SummaryFrequency += 4; + } + else + { + cf = (uint)( + 4 + + ((cf > 9 * sf) ? 1 : 0) + + ((cf > 12 * sf) ? 1 : 0) + + ((cf > 15 * sf) ? 1 : 0) + ); + currentContext.SummaryFrequency += (ushort)cf; + } + + state = currentContext.Statistics + (++currentContext.NumberStatistics); + state.Successor = successor; + state.Symbol = foundStateSymbol; + state.Frequency = (byte)cf; + currentContext.Flags |= flag; } - private PpmContext CreateSuccessors(bool skip, PpmState state, PpmContext context) + _maximumContext = foundStateSuccessor; + return; + + RestartModel: + RestoreModel(currentContext, minimumContext, foundStateSuccessor); + } + + private PpmContext CreateSuccessors(bool skip, PpmState state, PpmContext context) + { + var upBranch = _foundState.Successor; + var states = new PpmState[MAXIMUM_ORDER]; + uint stateIndex = 0; + var symbol = _foundState.Symbol; + + if (!skip) { - PpmContext upBranch = _foundState.Successor; - PpmState[] states = new PpmState[MAXIMUM_ORDER]; - uint stateIndex = 0; - byte symbol = _foundState.Symbol; - - if (!skip) + states[stateIndex++] = _foundState; + if (context.Suffix == PpmContext.ZERO) { - states[stateIndex++] = _foundState; - if (context.Suffix == PpmContext.ZERO) - { - goto NoLoop; - } + goto NoLoop; + } + } + + var gotoLoopEntry = false; + if (state != PpmState.ZERO) + { + context = context.Suffix; + gotoLoopEntry = true; + } + + do + { + if (gotoLoopEntry) + { + gotoLoopEntry = false; + goto LoopEntry; } - bool gotoLoopEntry = false; - if (state != PpmState.ZERO) - { - context = context.Suffix; - gotoLoopEntry = true; - } - - do - { - if (gotoLoopEntry) - { - gotoLoopEntry = false; - goto LoopEntry; - } - - context = context.Suffix; - if (context.NumberStatistics != 0) - { - byte temporary; - state = context.Statistics; - if (state.Symbol != symbol) - { - do - { - temporary = state[1].Symbol; - state++; - } while (temporary != symbol); - } - temporary = (byte)((state.Frequency < MAXIMUM_FREQUENCY - 9) ? 1 : 0); - state.Frequency += temporary; - context.SummaryFrequency += temporary; - } - else - { - state = context.FirstState; - state.Frequency += (byte)( - ((context.Suffix.NumberStatistics == 0) ? 1 : 0) - & ((state.Frequency < 24) ? 1 : 0) - ); - } - - LoopEntry: - if (state.Successor != upBranch) - { - context = state.Successor; - break; - } - states[stateIndex++] = state; - } while (context.Suffix != PpmContext.ZERO); - - NoLoop: - if (stateIndex == 0) - { - return context; - } - - byte localNumberStatistics = 0; - byte localFlags = (byte)((symbol >= 0x40) ? 0x10 : 0x00); - symbol = upBranch.NumberStatistics; - byte localSymbol = symbol; - byte localFrequency; - PpmContext localSuccessor = ((Pointer)upBranch) + 1; - localFlags |= (byte)((symbol >= 0x40) ? 0x08 : 0x00); - + context = context.Suffix; if (context.NumberStatistics != 0) { + byte temporary; state = context.Statistics; if (state.Symbol != symbol) { - byte temporary; do { temporary = state[1].Symbol; state++; } while (temporary != symbol); } - uint cf = (uint)(state.Frequency - 1); - uint s0 = (uint)(context.SummaryFrequency - context.NumberStatistics - cf); - localFrequency = (byte)( - 1 + ((2 * cf <= s0) ? (uint)((5 * cf > s0) ? 1 : 0) : ((cf + 2 * s0 - 3) / s0)) + temporary = (byte)((state.Frequency < MAXIMUM_FREQUENCY - 9) ? 1 : 0); + state.Frequency += temporary; + context.SummaryFrequency += temporary; + } + else + { + state = context.FirstState; + state.Frequency += (byte)( + ((context.Suffix.NumberStatistics == 0) ? 1 : 0) + & ((state.Frequency < 24) ? 1 : 0) + ); + } + + LoopEntry: + if (state.Successor != upBranch) + { + context = state.Successor; + break; + } + states[stateIndex++] = state; + } while (context.Suffix != PpmContext.ZERO); + + NoLoop: + if (stateIndex == 0) + { + return context; + } + + byte localNumberStatistics = 0; + var localFlags = (byte)((symbol >= 0x40) ? 0x10 : 0x00); + symbol = upBranch.NumberStatistics; + var localSymbol = symbol; + byte localFrequency; + PpmContext localSuccessor = ((Pointer)upBranch) + 1; + localFlags |= (byte)((symbol >= 0x40) ? 0x08 : 0x00); + + if (context.NumberStatistics != 0) + { + state = context.Statistics; + if (state.Symbol != symbol) + { + byte temporary; + do + { + temporary = state[1].Symbol; + state++; + } while (temporary != symbol); + } + var cf = (uint)(state.Frequency - 1); + var s0 = (uint)(context.SummaryFrequency - context.NumberStatistics - cf); + localFrequency = (byte)( + 1 + ((2 * cf <= s0) ? (uint)((5 * cf > s0) ? 1 : 0) : ((cf + (2 * s0) - 3) / s0)) + ); + } + else + { + localFrequency = context.FirstStateFrequency; + } + + do + { + PpmContext currentContext = _allocator.AllocateContext(); + if (currentContext == PpmContext.ZERO) + { + return PpmContext.ZERO; + } + currentContext.NumberStatistics = localNumberStatistics; + currentContext.Flags = localFlags; + currentContext.FirstStateSymbol = localSymbol; + currentContext.FirstStateFrequency = localFrequency; + currentContext.FirstStateSuccessor = localSuccessor; + currentContext.Suffix = context; + context = currentContext; + states[--stateIndex].Successor = context; + } while (stateIndex != 0); + + return context; + } + + private PpmContext ReduceOrder(PpmState state, PpmContext context) + { + PpmState currentState; + var states = new PpmState[MAXIMUM_ORDER]; + uint stateIndex = 0; + var currentContext = context; + PpmContext upBranch = _allocator._text; + byte temporary; + var symbol = _foundState.Symbol; + + states[stateIndex++] = _foundState; + _foundState.Successor = upBranch; + _orderFall++; + + var gotoLoopEntry = false; + if (state != PpmState.ZERO) + { + context = context.Suffix; + gotoLoopEntry = true; + } + + while (true) + { + if (gotoLoopEntry) + { + gotoLoopEntry = false; + goto LoopEntry; + } + + if (context.Suffix == PpmContext.ZERO) + { + if (_method > ModelRestorationMethod.Freeze) + { + do + { + states[--stateIndex].Successor = context; + } while (stateIndex != 0); + _allocator._text = _allocator._heap + 1; + _orderFall = 1; + } + return context; + } + + context = context.Suffix; + if (context.NumberStatistics != 0) + { + state = context.Statistics; + if (state.Symbol != symbol) + { + do + { + temporary = state[1].Symbol; + state++; + } while (temporary != symbol); + } + temporary = (byte)((state.Frequency < MAXIMUM_FREQUENCY - 9) ? 2 : 0); + state.Frequency += temporary; + context.SummaryFrequency += temporary; + } + else + { + state = context.FirstState; + state.Frequency += (byte)((state.Frequency < 32) ? 1 : 0); + } + + LoopEntry: + if (state.Successor != PpmContext.ZERO) + { + break; + } + states[stateIndex++] = state; + state.Successor = upBranch; + _orderFall++; + } + + if (_method > ModelRestorationMethod.Freeze) + { + context = state.Successor; + do + { + states[--stateIndex].Successor = context; + } while (stateIndex != 0); + _allocator._text = _allocator._heap + 1; + _orderFall = 1; + return context; + } + if (state.Successor <= upBranch) + { + currentState = _foundState; + _foundState = state; + state.Successor = CreateSuccessors(false, PpmState.ZERO, context); + _foundState = currentState; + } + + if (_orderFall == 1 && currentContext == _maximumContext) + { + _foundState.Successor = state.Successor; + _allocator._text--; + } + + return state.Successor; + } + + private void RestoreModel( + PpmContext context, + PpmContext minimumContext, + PpmContext foundStateSuccessor + ) + { + PpmContext currentContext; + + _allocator._text = _allocator._heap; + for ( + currentContext = _maximumContext; + currentContext != context; + currentContext = currentContext.Suffix + ) + { + if (--currentContext.NumberStatistics == 0) + { + currentContext.Flags = (byte)( + (currentContext.Flags & 0x10) + + ((currentContext.Statistics.Symbol >= 0x40) ? 0x08 : 0x00) + ); + var state = currentContext.Statistics; + Copy(currentContext.FirstState, state); + _allocator.SpecialFreeUnits(state); + currentContext.FirstStateFrequency = (byte)( + (currentContext.FirstStateFrequency + 11) >> 3 ); } else { - localFrequency = context.FirstStateFrequency; + Refresh( + (uint)((currentContext.NumberStatistics + 3) >> 1), + false, + currentContext + ); + } + } + + for (; currentContext != minimumContext; currentContext = currentContext.Suffix) + { + if (currentContext.NumberStatistics == 0) + { + currentContext.FirstStateFrequency -= (byte)( + currentContext.FirstStateFrequency >> 1 + ); + } + else if ( + (currentContext.SummaryFrequency += 4) + > 128 + (4 * currentContext.NumberStatistics) + ) + { + Refresh( + (uint)((currentContext.NumberStatistics + 2) >> 1), + true, + currentContext + ); + } + } + + if (_method > ModelRestorationMethod.Freeze) + { + _maximumContext = foundStateSuccessor; + _allocator._glueCount += (uint)( + ((_allocator._memoryNodes[1].Stamp & 1) == 0) ? 1 : 0 + ); + } + else if (_method == ModelRestorationMethod.Freeze) + { + while (_maximumContext.Suffix != PpmContext.ZERO) + { + _maximumContext = _maximumContext.Suffix; + } + + RemoveBinaryContexts(0, _maximumContext); + _method++; + _allocator._glueCount = 0; + _orderFall = _modelOrder; + } + else if ( + _method == ModelRestorationMethod.Restart + || _allocator.GetMemoryUsed() < (_allocator._allocatorSize >> 1) + ) + { + StartModel(_modelOrder, _method); + _escapeCount = 0; + } + else + { + while (_maximumContext.Suffix != PpmContext.ZERO) + { + _maximumContext = _maximumContext.Suffix; } do { - PpmContext currentContext = _allocator.AllocateContext(); - if (currentContext == PpmContext.ZERO) - { - return PpmContext.ZERO; - } - currentContext.NumberStatistics = localNumberStatistics; - currentContext.Flags = localFlags; - currentContext.FirstStateSymbol = localSymbol; - currentContext.FirstStateFrequency = localFrequency; - currentContext.FirstStateSuccessor = localSuccessor; - currentContext.Suffix = context; - context = currentContext; - states[--stateIndex].Successor = context; - } while (stateIndex != 0); + CutOff(0, _maximumContext); + _allocator.ExpandText(); + } while (_allocator.GetMemoryUsed() > 3 * (_allocator._allocatorSize >> 2)); - return context; + _allocator._glueCount = 0; + _orderFall = _modelOrder; } - - private PpmContext ReduceOrder(PpmState state, PpmContext context) - { - PpmState currentState; - PpmState[] states = new PpmState[MAXIMUM_ORDER]; - uint stateIndex = 0; - PpmContext currentContext = context; - PpmContext upBranch = _allocator._text; - byte temporary; - byte symbol = _foundState.Symbol; - - states[stateIndex++] = _foundState; - _foundState.Successor = upBranch; - _orderFall++; - - bool gotoLoopEntry = false; - if (state != PpmState.ZERO) - { - context = context.Suffix; - gotoLoopEntry = true; - } - - while (true) - { - if (gotoLoopEntry) - { - gotoLoopEntry = false; - goto LoopEntry; - } - - if (context.Suffix == PpmContext.ZERO) - { - if (_method > ModelRestorationMethod.Freeze) - { - do - { - states[--stateIndex].Successor = context; - } while (stateIndex != 0); - _allocator._text = _allocator._heap + 1; - _orderFall = 1; - } - return context; - } - - context = context.Suffix; - if (context.NumberStatistics != 0) - { - state = context.Statistics; - if (state.Symbol != symbol) - { - do - { - temporary = state[1].Symbol; - state++; - } while (temporary != symbol); - } - temporary = (byte)((state.Frequency < MAXIMUM_FREQUENCY - 9) ? 2 : 0); - state.Frequency += temporary; - context.SummaryFrequency += temporary; - } - else - { - state = context.FirstState; - state.Frequency += (byte)((state.Frequency < 32) ? 1 : 0); - } - - LoopEntry: - if (state.Successor != PpmContext.ZERO) - { - break; - } - states[stateIndex++] = state; - state.Successor = upBranch; - _orderFall++; - } - - if (_method > ModelRestorationMethod.Freeze) - { - context = state.Successor; - do - { - states[--stateIndex].Successor = context; - } while (stateIndex != 0); - _allocator._text = _allocator._heap + 1; - _orderFall = 1; - return context; - } - if (state.Successor <= upBranch) - { - currentState = _foundState; - _foundState = state; - state.Successor = CreateSuccessors(false, PpmState.ZERO, context); - _foundState = currentState; - } - - if (_orderFall == 1 && currentContext == _maximumContext) - { - _foundState.Successor = state.Successor; - _allocator._text--; - } - - return state.Successor; - } - - private void RestoreModel( - PpmContext context, - PpmContext minimumContext, - PpmContext foundStateSuccessor - ) - { - PpmContext currentContext; - - _allocator._text = _allocator._heap; - for ( - currentContext = _maximumContext; - currentContext != context; - currentContext = currentContext.Suffix - ) - { - if (--currentContext.NumberStatistics == 0) - { - currentContext.Flags = (byte)( - (currentContext.Flags & 0x10) - + ((currentContext.Statistics.Symbol >= 0x40) ? 0x08 : 0x00) - ); - PpmState state = currentContext.Statistics; - Copy(currentContext.FirstState, state); - _allocator.SpecialFreeUnits(state); - currentContext.FirstStateFrequency = (byte)( - (currentContext.FirstStateFrequency + 11) >> 3 - ); - } - else - { - Refresh( - (uint)((currentContext.NumberStatistics + 3) >> 1), - false, - currentContext - ); - } - } - - for (; currentContext != minimumContext; currentContext = currentContext.Suffix) - { - if (currentContext.NumberStatistics == 0) - { - currentContext.FirstStateFrequency -= (byte)( - currentContext.FirstStateFrequency >> 1 - ); - } - else if ( - (currentContext.SummaryFrequency += 4) - > 128 + 4 * currentContext.NumberStatistics - ) - { - Refresh( - (uint)((currentContext.NumberStatistics + 2) >> 1), - true, - currentContext - ); - } - } - - if (_method > ModelRestorationMethod.Freeze) - { - _maximumContext = foundStateSuccessor; - _allocator._glueCount += (uint)( - ((_allocator._memoryNodes[1].Stamp & 1) == 0) ? 1 : 0 - ); - } - else if (_method == ModelRestorationMethod.Freeze) - { - while (_maximumContext.Suffix != PpmContext.ZERO) - { - _maximumContext = _maximumContext.Suffix; - } - - RemoveBinaryContexts(0, _maximumContext); - _method = _method + 1; - _allocator._glueCount = 0; - _orderFall = _modelOrder; - } - else if ( - _method == ModelRestorationMethod.Restart - || _allocator.GetMemoryUsed() < (_allocator._allocatorSize >> 1) - ) - { - StartModel(_modelOrder, _method); - _escapeCount = 0; - } - else - { - while (_maximumContext.Suffix != PpmContext.ZERO) - { - _maximumContext = _maximumContext.Suffix; - } - - do - { - CutOff(0, _maximumContext); - _allocator.ExpandText(); - } while (_allocator.GetMemoryUsed() > 3 * (_allocator._allocatorSize >> 2)); - - _allocator._glueCount = 0; - _orderFall = _modelOrder; - } - } - - private static void Swap(PpmState state1, PpmState state2) - { - byte swapSymbol = state1.Symbol; - byte swapFrequency = state1.Frequency; - PpmContext swapSuccessor = state1.Successor; - - state1.Symbol = state2.Symbol; - state1.Frequency = state2.Frequency; - state1.Successor = state2.Successor; - - state2.Symbol = swapSymbol; - state2.Frequency = swapFrequency; - state2.Successor = swapSuccessor; - } - - private static void Copy(PpmState state1, PpmState state2) - { - state1.Symbol = state2.Symbol; - state1.Frequency = state2.Frequency; - state1.Successor = state2.Successor; - } - - private static int Mean(int sum, int shift, int round) - { - return (sum + (1 << (shift - round))) >> shift; - } - - private void ClearMask() - { - _escapeCount = 1; - Array.Clear(_characterMask, 0, _characterMask.Length); - } - - #endregion } + + private static void Swap(PpmState state1, PpmState state2) + { + var swapSymbol = state1.Symbol; + var swapFrequency = state1.Frequency; + var swapSuccessor = state1.Successor; + + state1.Symbol = state2.Symbol; + state1.Frequency = state2.Frequency; + state1.Successor = state2.Successor; + + state2.Symbol = swapSymbol; + state2.Frequency = swapFrequency; + state2.Successor = swapSuccessor; + } + + private static void Copy(PpmState state1, PpmState state2) + { + state1.Symbol = state2.Symbol; + state1.Frequency = state2.Frequency; + state1.Successor = state2.Successor; + } + + private static int Mean(int sum, int shift, int round) + { + return (sum + (1 << (shift - round))) >> shift; + } + + private void ClearMask() + { + _escapeCount = 1; + Array.Clear(_characterMask, 0, _characterMask.Length); + } + + #endregion } diff --git a/src/SharpCompress/Compressors/PPMd/I1/ModelRestorationMethod.cs b/src/SharpCompress/Compressors/PPMd/I1/ModelRestorationMethod.cs index 9e89d9da..0a504c99 100644 --- a/src/SharpCompress/Compressors/PPMd/I1/ModelRestorationMethod.cs +++ b/src/SharpCompress/Compressors/PPMd/I1/ModelRestorationMethod.cs @@ -4,26 +4,25 @@ #endregion -namespace SharpCompress.Compressors.PPMd.I1 +namespace SharpCompress.Compressors.PPMd.I1; + +/// +/// The method used to adjust the model when the memory limit is reached. +/// +internal enum ModelRestorationMethod { /// - /// The method used to adjust the model when the memory limit is reached. + /// Restart the model from scratch (this is the default). /// - internal enum ModelRestorationMethod - { - /// - /// Restart the model from scratch (this is the default). - /// - Restart = 0, + Restart = 0, - /// - /// Cut off the model (nearly twice as slow). - /// - CutOff = 1, + /// + /// Cut off the model (nearly twice as slow). + /// + CutOff = 1, - /// - /// Freeze the context tree (in some cases may result in poor compression). - /// - Freeze = 2 - } + /// + /// Freeze the context tree (in some cases may result in poor compression). + /// + Freeze = 2 } diff --git a/src/SharpCompress/Compressors/PPMd/I1/Pointer.cs b/src/SharpCompress/Compressors/PPMd/I1/Pointer.cs index 05748848..791a556d 100644 --- a/src/SharpCompress/Compressors/PPMd/I1/Pointer.cs +++ b/src/SharpCompress/Compressors/PPMd/I1/Pointer.cs @@ -2,380 +2,378 @@ using System; -namespace SharpCompress.Compressors.PPMd.I1 +namespace SharpCompress.Compressors.PPMd.I1; + +/// +/// A structure containing a single address representing a position in the array. This +/// is intended to mimic the behaviour of a pointer in C/C++. +/// +/// +/// +/// This must be a structure rather than a class because several places in the associated code assume that +/// is a value type (meaning that assignment creates a completely new copy of the +/// instance rather than just copying a reference to the same instance). +/// +/// +/// Note that is a field rather than a property for performance reasons. +/// +/// +internal struct Pointer { + public uint _address; + public byte[] _memory; + public static readonly Pointer ZERO = new Pointer(0, null); + public const int SIZE = 1; + /// - /// A structure containing a single address representing a position in the array. This - /// is intended to mimic the behaviour of a pointer in C/C++. + /// Initializes a new instance of the structure. /// - /// - /// - /// This must be a structure rather than a class because several places in the associated code assume that - /// is a value type (meaning that assignment creates a completely new copy of the - /// instance rather than just copying a reference to the same instance). - /// - /// - /// Note that is a field rather than a property for performance reasons. - /// - /// - internal struct Pointer + public Pointer(uint address, byte[] memory) { - public uint _address; - public byte[] _memory; - public static readonly Pointer ZERO = new Pointer(0, null); - public const int SIZE = 1; + _address = address; + _memory = memory; + } - /// - /// Initializes a new instance of the structure. - /// - public Pointer(uint address, byte[] memory) - { - _address = address; - _memory = memory; - } - - /// - /// Gets or sets the byte at the given . - /// - /// - /// - public byte this[int offset] - { - get - { -#if DEBUG - if (_address == 0) - { - throw new InvalidOperationException( - "The pointer being indexed is a null pointer." - ); - } -#endif - return _memory[_address + offset]; - } - set - { -#if DEBUG - if (_address == 0) - { - throw new InvalidOperationException( - "The pointer being indexed is a null pointer." - ); - } -#endif - _memory[_address + offset] = value; - } - } - - /// - /// Allow a to be implicitly converted to a . - /// - /// - /// - public static implicit operator Pointer(MemoryNode memoryNode) - { - return new Pointer(memoryNode._address, memoryNode._memory); - } - - /// - /// Allow a to be implicitly converted to a . - /// - /// - /// - public static implicit operator Pointer(Model.PpmContext context) - { - return new Pointer(context._address, context._memory); - } - - /// - /// Allow a to be implicitly converted to a . - /// - /// - /// - public static implicit operator Pointer(PpmState state) - { - return new Pointer(state._address, state._memory); - } - - /// - /// Increase the address of a pointer by the given number of bytes. - /// - /// - /// - /// - public static Pointer operator +(Pointer pointer, int offset) + /// + /// Gets or sets the byte at the given . + /// + /// + /// + public byte this[int offset] + { + get { #if DEBUG - if (pointer._address == 0) - { - throw new InvalidOperationException("The pointer is a null pointer."); - } -#endif - pointer._address = (uint)(pointer._address + offset); - return pointer; - } - - /// - /// Increase the address of a pointer by the given number of bytes. - /// - /// - /// - /// - public static Pointer operator +(Pointer pointer, uint offset) - { -#if DEBUG - if (pointer._address == 0) - { - throw new InvalidOperationException("The pointer is a null pointer."); - } -#endif - pointer._address += offset; - return pointer; - } - - /// - /// Increment the address of a pointer. - /// - /// - /// - public static Pointer operator ++(Pointer pointer) - { -#if DEBUG - if (pointer._address == 0) + if (_address == 0) { throw new InvalidOperationException( - "The pointer being incremented is a null pointer." + "The pointer being indexed is a null pointer." ); } #endif - pointer._address++; - return pointer; + return _memory[_address + offset]; } - - /// - /// Decrease the address of a pointer by the given number of bytes. - /// - /// - /// - /// - public static Pointer operator -(Pointer pointer, int offset) + set { #if DEBUG - if (pointer._address == 0) - { - throw new InvalidOperationException("The pointer is a null pointer."); - } -#endif - pointer._address = (uint)(pointer._address - offset); - return pointer; - } - - /// - /// Decrease the address of a pointer by the given number of bytes. - /// - /// - /// - /// - public static Pointer operator -(Pointer pointer, uint offset) - { -#if DEBUG - if (pointer._address == 0) - { - throw new InvalidOperationException("The pointer is a null pointer."); - } -#endif - pointer._address -= offset; - return pointer; - } - - /// - /// Decrement the address of a pointer. - /// - /// - /// - public static Pointer operator --(Pointer pointer) - { -#if DEBUG - if (pointer._address == 0) + if (_address == 0) { throw new InvalidOperationException( - "The pointer being decremented is a null pointer." + "The pointer being indexed is a null pointer." ); } #endif - pointer._address--; - return pointer; - } - - /// - /// Subtract two pointers. - /// - /// - /// - /// The number of bytes between the two pointers. - public static uint operator -(Pointer pointer1, Pointer pointer2) - { -#if DEBUG - if (pointer1._address == 0) - { - throw new InvalidOperationException( - "The pointer to the left of the subtraction operator is a null pointer." - ); - } - if (pointer2._address == 0) - { - throw new InvalidOperationException( - "The pointer to the right of the subtraction operator is a null pointer." - ); - } -#endif - return pointer1._address - pointer2._address; - } - - /// - /// Compare pointers. - /// - /// - /// - /// - public static bool operator <(Pointer pointer1, Pointer pointer2) - { -#if DEBUG - if (pointer1._address == 0) - { - throw new InvalidOperationException( - "The pointer to the left of the less than operator is a null pointer." - ); - } - if (pointer2._address == 0) - { - throw new InvalidOperationException( - "The pointer to the right of the less than operator is a null pointer." - ); - } -#endif - return pointer1._address < pointer2._address; - } - - /// - /// Compare two pointers. - /// - /// - /// - /// - public static bool operator <=(Pointer pointer1, Pointer pointer2) - { -#if DEBUG - if (pointer1._address == 0) - { - throw new InvalidOperationException( - "The pointer to the left of the less than or equal to operator is a null pointer." - ); - } - if (pointer2._address == 0) - { - throw new InvalidOperationException( - "The pointer to the right of the less than or equal to operator is a null pointer." - ); - } -#endif - return pointer1._address <= pointer2._address; - } - - /// - /// Compare two pointers. - /// - /// - /// - /// - public static bool operator >(Pointer pointer1, Pointer pointer2) - { -#if DEBUG - if (pointer1._address == 0) - { - throw new InvalidOperationException( - "The pointer to the left of the greater than operator is a null pointer." - ); - } - if (pointer2._address == 0) - { - throw new InvalidOperationException( - "The pointer to the right of the greater than operator is a null pointer." - ); - } -#endif - return pointer1._address > pointer2._address; - } - - /// - /// Compare two pointers. - /// - /// - /// - /// - public static bool operator >=(Pointer pointer1, Pointer pointer2) - { -#if DEBUG - if (pointer1._address == 0) - { - throw new InvalidOperationException( - "The pointer to the left of the greater than or equal to operator is a null pointer." - ); - } - if (pointer2._address == 0) - { - throw new InvalidOperationException( - "The pointer to the right of the greater than or equal to operator is a null pointer." - ); - } -#endif - return pointer1._address >= pointer2._address; - } - - /// - /// Compare two pointers. - /// - /// - /// - /// - public static bool operator ==(Pointer pointer1, Pointer pointer2) - { - return pointer1._address == pointer2._address; - } - - /// - /// Compare two pointers. - /// - /// - /// - /// - public static bool operator !=(Pointer pointer1, Pointer pointer2) - { - return pointer1._address != pointer2._address; - } - - /// - /// Indicates whether this instance and a specified object are equal. - /// - /// true if obj and this instance are the same type and represent the same value; otherwise, false. - /// Another object to compare to. - public override bool Equals(object obj) - { - if (obj is Pointer) - { - Pointer pointer = (Pointer)obj; - return pointer._address == _address; - } - return base.Equals(obj); - } - - /// - /// Returns the hash code for this instance. - /// - /// A 32-bit signed integer that is the hash code for this instance. - public override int GetHashCode() - { - return _address.GetHashCode(); + _memory[_address + offset] = value; } } + + /// + /// Allow a to be implicitly converted to a . + /// + /// + /// + public static implicit operator Pointer(MemoryNode memoryNode) + { + return new Pointer(memoryNode._address, memoryNode._memory); + } + + /// + /// Allow a to be implicitly converted to a . + /// + /// + /// + public static implicit operator Pointer(Model.PpmContext context) + { + return new Pointer(context._address, context._memory); + } + + /// + /// Allow a to be implicitly converted to a . + /// + /// + /// + public static implicit operator Pointer(PpmState state) + { + return new Pointer(state._address, state._memory); + } + + /// + /// Increase the address of a pointer by the given number of bytes. + /// + /// + /// + /// + public static Pointer operator +(Pointer pointer, int offset) + { +#if DEBUG + if (pointer._address == 0) + { + throw new InvalidOperationException("The pointer is a null pointer."); + } +#endif + pointer._address = (uint)(pointer._address + offset); + return pointer; + } + + /// + /// Increase the address of a pointer by the given number of bytes. + /// + /// + /// + /// + public static Pointer operator +(Pointer pointer, uint offset) + { +#if DEBUG + if (pointer._address == 0) + { + throw new InvalidOperationException("The pointer is a null pointer."); + } +#endif + pointer._address += offset; + return pointer; + } + + /// + /// Increment the address of a pointer. + /// + /// + /// + public static Pointer operator ++(Pointer pointer) + { +#if DEBUG + if (pointer._address == 0) + { + throw new InvalidOperationException( + "The pointer being incremented is a null pointer." + ); + } +#endif + pointer._address++; + return pointer; + } + + /// + /// Decrease the address of a pointer by the given number of bytes. + /// + /// + /// + /// + public static Pointer operator -(Pointer pointer, int offset) + { +#if DEBUG + if (pointer._address == 0) + { + throw new InvalidOperationException("The pointer is a null pointer."); + } +#endif + pointer._address = (uint)(pointer._address - offset); + return pointer; + } + + /// + /// Decrease the address of a pointer by the given number of bytes. + /// + /// + /// + /// + public static Pointer operator -(Pointer pointer, uint offset) + { +#if DEBUG + if (pointer._address == 0) + { + throw new InvalidOperationException("The pointer is a null pointer."); + } +#endif + pointer._address -= offset; + return pointer; + } + + /// + /// Decrement the address of a pointer. + /// + /// + /// + public static Pointer operator --(Pointer pointer) + { +#if DEBUG + if (pointer._address == 0) + { + throw new InvalidOperationException( + "The pointer being decremented is a null pointer." + ); + } +#endif + pointer._address--; + return pointer; + } + + /// + /// Subtract two pointers. + /// + /// + /// + /// The number of bytes between the two pointers. + public static uint operator -(Pointer pointer1, Pointer pointer2) + { +#if DEBUG + if (pointer1._address == 0) + { + throw new InvalidOperationException( + "The pointer to the left of the subtraction operator is a null pointer." + ); + } + if (pointer2._address == 0) + { + throw new InvalidOperationException( + "The pointer to the right of the subtraction operator is a null pointer." + ); + } +#endif + return pointer1._address - pointer2._address; + } + + /// + /// Compare pointers. + /// + /// + /// + /// + public static bool operator <(Pointer pointer1, Pointer pointer2) + { +#if DEBUG + if (pointer1._address == 0) + { + throw new InvalidOperationException( + "The pointer to the left of the less than operator is a null pointer." + ); + } + if (pointer2._address == 0) + { + throw new InvalidOperationException( + "The pointer to the right of the less than operator is a null pointer." + ); + } +#endif + return pointer1._address < pointer2._address; + } + + /// + /// Compare two pointers. + /// + /// + /// + /// + public static bool operator <=(Pointer pointer1, Pointer pointer2) + { +#if DEBUG + if (pointer1._address == 0) + { + throw new InvalidOperationException( + "The pointer to the left of the less than or equal to operator is a null pointer." + ); + } + if (pointer2._address == 0) + { + throw new InvalidOperationException( + "The pointer to the right of the less than or equal to operator is a null pointer." + ); + } +#endif + return pointer1._address <= pointer2._address; + } + + /// + /// Compare two pointers. + /// + /// + /// + /// + public static bool operator >(Pointer pointer1, Pointer pointer2) + { +#if DEBUG + if (pointer1._address == 0) + { + throw new InvalidOperationException( + "The pointer to the left of the greater than operator is a null pointer." + ); + } + if (pointer2._address == 0) + { + throw new InvalidOperationException( + "The pointer to the right of the greater than operator is a null pointer." + ); + } +#endif + return pointer1._address > pointer2._address; + } + + /// + /// Compare two pointers. + /// + /// + /// + /// + public static bool operator >=(Pointer pointer1, Pointer pointer2) + { +#if DEBUG + if (pointer1._address == 0) + { + throw new InvalidOperationException( + "The pointer to the left of the greater than or equal to operator is a null pointer." + ); + } + if (pointer2._address == 0) + { + throw new InvalidOperationException( + "The pointer to the right of the greater than or equal to operator is a null pointer." + ); + } +#endif + return pointer1._address >= pointer2._address; + } + + /// + /// Compare two pointers. + /// + /// + /// + /// + public static bool operator ==(Pointer pointer1, Pointer pointer2) + { + return pointer1._address == pointer2._address; + } + + /// + /// Compare two pointers. + /// + /// + /// + /// + public static bool operator !=(Pointer pointer1, Pointer pointer2) + { + return pointer1._address != pointer2._address; + } + + /// + /// Indicates whether this instance and a specified object are equal. + /// + /// true if obj and this instance are the same type and represent the same value; otherwise, false. + /// Another object to compare to. + public override bool Equals(object obj) + { + if (obj is Pointer pointer) + { + return pointer._address == _address; + } + return base.Equals(obj); + } + + /// + /// Returns the hash code for this instance. + /// + /// A 32-bit signed integer that is the hash code for this instance. + public override int GetHashCode() + { + return _address.GetHashCode(); + } } diff --git a/src/SharpCompress/Compressors/PPMd/I1/PpmContext.cs b/src/SharpCompress/Compressors/PPMd/I1/PpmContext.cs index 35d020b6..3e122032 100644 --- a/src/SharpCompress/Compressors/PPMd/I1/PpmContext.cs +++ b/src/SharpCompress/Compressors/PPMd/I1/PpmContext.cs @@ -1,796 +1,764 @@ #nullable disable -namespace SharpCompress.Compressors.PPMd.I1 +namespace SharpCompress.Compressors.PPMd.I1; + +/// +/// The PPM context structure. This is tightly coupled with . +/// +/// +/// +/// This must be a structure rather than a class because several places in the associated code assume that +/// is a value type (meaning that assignment creates a completely new copy of +/// the instance rather than just copying a reference to the same instance). +/// +/// +internal partial class Model { /// - /// The PPM context structure. This is tightly coupled with . + /// The structure which represents the current PPM context. This is 12 bytes in size. /// - /// - /// - /// This must be a structure rather than a class because several places in the associated code assume that - /// is a value type (meaning that assignment creates a completely new copy of - /// the instance rather than just copying a reference to the same instance). - /// - /// - internal partial class Model + internal struct PpmContext { + public uint _address; + public byte[] _memory; + public static readonly PpmContext ZERO = new PpmContext(0, null); + public const int SIZE = 12; + /// - /// The structure which represents the current PPM context. This is 12 bytes in size. + /// Initializes a new instance of the structure. /// - internal struct PpmContext + public PpmContext(uint address, byte[] memory) { - public uint _address; - public byte[] _memory; - public static readonly PpmContext ZERO = new PpmContext(0, null); - public const int SIZE = 12; + _address = address; + _memory = memory; + } - /// - /// Initializes a new instance of the structure. - /// - public PpmContext(uint address, byte[] memory) + /// + /// Gets or sets the number statistics. + /// + public byte NumberStatistics + { + get => _memory[_address]; + set => _memory[_address] = value; + } + + /// + /// Gets or sets the flags. + /// + public byte Flags + { + get => _memory[_address + 1]; + set => _memory[_address + 1] = value; + } + + /// + /// Gets or sets the summary frequency. + /// + public ushort SummaryFrequency + { + get => (ushort)(_memory[_address + 2] | (_memory[_address + 3] << 8)); + set { - _address = address; - _memory = memory; - } - - /// - /// Gets or sets the number statistics. - /// - public byte NumberStatistics - { - get => _memory[_address]; - set => _memory[_address] = value; - } - - /// - /// Gets or sets the flags. - /// - public byte Flags - { - get => _memory[_address + 1]; - set => _memory[_address + 1] = value; - } - - /// - /// Gets or sets the summary frequency. - /// - public ushort SummaryFrequency - { - get => (ushort)(_memory[_address + 2] | _memory[_address + 3] << 8); - set - { - _memory[_address + 2] = (byte)value; - _memory[_address + 3] = (byte)(value >> 8); - } - } - - /// - /// Gets or sets the statistics. - /// - public PpmState Statistics - { - get => - new PpmState( - _memory[_address + 4] - | ((uint)_memory[_address + 5]) << 8 - | ((uint)_memory[_address + 6]) << 16 - | ((uint)_memory[_address + 7]) << 24, - _memory - ); - set - { - _memory[_address + 4] = (byte)value._address; - _memory[_address + 5] = (byte)(value._address >> 8); - _memory[_address + 6] = (byte)(value._address >> 16); - _memory[_address + 7] = (byte)(value._address >> 24); - } - } - - /// - /// Gets or sets the suffix. - /// - public PpmContext Suffix - { - get => - new PpmContext( - _memory[_address + 8] - | ((uint)_memory[_address + 9]) << 8 - | ((uint)_memory[_address + 10]) << 16 - | ((uint)_memory[_address + 11]) << 24, - _memory - ); - set - { - _memory[_address + 8] = (byte)value._address; - _memory[_address + 9] = (byte)(value._address >> 8); - _memory[_address + 10] = (byte)(value._address >> 16); - _memory[_address + 11] = (byte)(value._address >> 24); - } - } - - /// - /// The first PPM state associated with the PPM context. - /// - /// - /// - /// The first PPM state overlaps this PPM context instance (the context.SummaryFrequency and context.Statistics members - /// of PpmContext use 6 bytes and so can therefore fit into the space used by the Symbol, Frequency and - /// Successor members of PpmState, since they also add up to 6 bytes). - /// - /// - /// PpmContext (context.SummaryFrequency and context.Statistics use 6 bytes) - /// 1 context.NumberStatistics - /// 1 context.Flags - /// 2 context.SummaryFrequency - /// 4 context.Statistics (pointer to PpmState) - /// 4 context.Suffix (pointer to PpmContext) - /// - /// - /// PpmState (total of 6 bytes) - /// 1 Symbol - /// 1 Frequency - /// 4 Successor (pointer to PpmContext) - /// - /// - /// - public PpmState FirstState => new PpmState(_address + 2, _memory); - - /// - /// Gets or sets the symbol of the first PPM state. This is provided for convenience. The same - /// information can be obtained using the Symbol property on the PPM state provided by the - /// property. - /// - public byte FirstStateSymbol - { - get => _memory[_address + 2]; - set => _memory[_address + 2] = value; - } - - /// - /// Gets or sets the frequency of the first PPM state. This is provided for convenience. The same - /// information can be obtained using the Frequency property on the PPM state provided by the - ///context.FirstState property. - /// - public byte FirstStateFrequency - { - get => _memory[_address + 3]; - set => _memory[_address + 3] = value; - } - - /// - /// Gets or sets the successor of the first PPM state. This is provided for convenience. The same - /// information can be obtained using the Successor property on the PPM state provided by the - /// - public PpmContext FirstStateSuccessor - { - get => - new PpmContext( - _memory[_address + 4] - | ((uint)_memory[_address + 5]) << 8 - | ((uint)_memory[_address + 6]) << 16 - | ((uint)_memory[_address + 7]) << 24, - _memory - ); - set - { - _memory[_address + 4] = (byte)value._address; - _memory[_address + 5] = (byte)(value._address >> 8); - _memory[_address + 6] = (byte)(value._address >> 16); - _memory[_address + 7] = (byte)(value._address >> 24); - } - } - - /// - /// Allow a pointer to be implicitly converted to a PPM context. - /// - /// - /// - public static implicit operator PpmContext(Pointer pointer) - { - return new PpmContext(pointer._address, pointer._memory); - } - - /// - /// Allow pointer-like addition on a PPM context. - /// - /// - /// - /// - public static PpmContext operator +(PpmContext context, int offset) - { - context._address = (uint)(context._address + offset * SIZE); - return context; - } - - /// - /// Allow pointer-like subtraction on a PPM context. - /// - /// - /// - /// - public static PpmContext operator -(PpmContext context, int offset) - { - context._address = (uint)(context._address - offset * SIZE); - return context; - } - - /// - /// Compare two PPM contexts. - /// - /// - /// - /// - public static bool operator <=(PpmContext context1, PpmContext context2) - { - return context1._address <= context2._address; - } - - /// - /// Compare two PPM contexts. - /// - /// - /// - /// - public static bool operator >=(PpmContext context1, PpmContext context2) - { - return context1._address >= context2._address; - } - - /// - /// Compare two PPM contexts. - /// - /// - /// - /// - public static bool operator ==(PpmContext context1, PpmContext context2) - { - return context1._address == context2._address; - } - - /// - /// Compare two PPM contexts. - /// - /// - /// - /// - public static bool operator !=(PpmContext context1, PpmContext context2) - { - return context1._address != context2._address; - } - - /// - /// Indicates whether this instance and a specified object are equal. - /// - /// true if obj and this instance are the same type and represent the same value; otherwise, false. - /// Another object to compare to. - public override bool Equals(object obj) - { - if (obj is PpmContext) - { - PpmContext context = (PpmContext)obj; - return context._address == _address; - } - return base.Equals(obj); - } - - /// - /// Returns the hash code for this instance. - /// - /// A 32-bit signed integer that is the hash code for this instance. - public override int GetHashCode() - { - return _address.GetHashCode(); + _memory[_address + 2] = (byte)value; + _memory[_address + 3] = (byte)(value >> 8); } } - private void EncodeBinarySymbol(int symbol, PpmContext context) + /// + /// Gets or sets the statistics. + /// + public PpmState Statistics { - PpmState state = context.FirstState; - int index1 = _probabilities[state.Frequency - 1]; - int index2 = - _numberStatisticsToBinarySummaryIndex[context.Suffix.NumberStatistics] - + _previousSuccess - + context.Flags - + ((_runLength >> 26) & 0x20); - - if (state.Symbol == symbol) - { - _foundState = state; - state.Frequency += (byte)((state.Frequency < 196) ? 1 : 0); - _coder._lowCount = 0; - _coder._highCount = _binarySummary[index1, index2]; - _binarySummary[index1, index2] += (ushort)( - INTERVAL - Mean(_binarySummary[index1, index2], PERIOD_BIT_COUNT, 2) + get => + new PpmState( + _memory[_address + 4] + | (((uint)_memory[_address + 5]) << 8) + | (((uint)_memory[_address + 6]) << 16) + | (((uint)_memory[_address + 7]) << 24), + _memory ); - _previousSuccess = 1; - _runLength++; - } - else + set { - _coder._lowCount = _binarySummary[index1, index2]; - _binarySummary[index1, index2] -= (ushort)Mean( - _binarySummary[index1, index2], - PERIOD_BIT_COUNT, - 2 - ); - _coder._highCount = BINARY_SCALE; - _initialEscape = EXPONENTIAL_ESCAPES[_binarySummary[index1, index2] >> 10]; - _characterMask[state.Symbol] = _escapeCount; - _previousSuccess = 0; - _numberMasked = 0; - _foundState = PpmState.ZERO; + _memory[_address + 4] = (byte)value._address; + _memory[_address + 5] = (byte)(value._address >> 8); + _memory[_address + 6] = (byte)(value._address >> 16); + _memory[_address + 7] = (byte)(value._address >> 24); } } - private void EncodeSymbol1(int symbol, PpmContext context) + /// + /// Gets or sets the suffix. + /// + public PpmContext Suffix { - uint lowCount; - uint index = context.Statistics.Symbol; - PpmState state = context.Statistics; - _coder._scale = context.SummaryFrequency; - if (index == symbol) + get => + new PpmContext( + _memory[_address + 8] + | (((uint)_memory[_address + 9]) << 8) + | (((uint)_memory[_address + 10]) << 16) + | (((uint)_memory[_address + 11]) << 24), + _memory + ); + set { - _coder._highCount = state.Frequency; - _previousSuccess = (byte)((2 * _coder._highCount >= _coder._scale) ? 1 : 0); - _foundState = state; - _foundState.Frequency += 4; - context.SummaryFrequency += 4; - _runLength += _previousSuccess; - if (state.Frequency > MAXIMUM_FREQUENCY) - { - Rescale(context); - } - _coder._lowCount = 0; - return; + _memory[_address + 8] = (byte)value._address; + _memory[_address + 9] = (byte)(value._address >> 8); + _memory[_address + 10] = (byte)(value._address >> 16); + _memory[_address + 11] = (byte)(value._address >> 24); } + } - lowCount = state.Frequency; - index = context.NumberStatistics; + /// + /// The first PPM state associated with the PPM context. + /// + /// + /// + /// The first PPM state overlaps this PPM context instance (the context.SummaryFrequency and context.Statistics members + /// of PpmContext use 6 bytes and so can therefore fit into the space used by the Symbol, Frequency and + /// Successor members of PpmState, since they also add up to 6 bytes). + /// + /// + /// PpmContext (context.SummaryFrequency and context.Statistics use 6 bytes) + /// 1 context.NumberStatistics + /// 1 context.Flags + /// 2 context.SummaryFrequency + /// 4 context.Statistics (pointer to PpmState) + /// 4 context.Suffix (pointer to PpmContext) + /// + /// + /// PpmState (total of 6 bytes) + /// 1 Symbol + /// 1 Frequency + /// 4 Successor (pointer to PpmContext) + /// + /// + /// + public PpmState FirstState => new PpmState(_address + 2, _memory); + + /// + /// Gets or sets the symbol of the first PPM state. This is provided for convenience. The same + /// information can be obtained using the Symbol property on the PPM state provided by the + /// property. + /// + public byte FirstStateSymbol + { + get => _memory[_address + 2]; + set => _memory[_address + 2] = value; + } + + /// + /// Gets or sets the frequency of the first PPM state. This is provided for convenience. The same + /// information can be obtained using the Frequency property on the PPM state provided by the + ///context.FirstState property. + /// + public byte FirstStateFrequency + { + get => _memory[_address + 3]; + set => _memory[_address + 3] = value; + } + + /// + /// Gets or sets the successor of the first PPM state. This is provided for convenience. The same + /// information can be obtained using the Successor property on the PPM state provided by the + /// + public PpmContext FirstStateSuccessor + { + get => + new PpmContext( + _memory[_address + 4] + | (((uint)_memory[_address + 5]) << 8) + | (((uint)_memory[_address + 6]) << 16) + | (((uint)_memory[_address + 7]) << 24), + _memory + ); + set + { + _memory[_address + 4] = (byte)value._address; + _memory[_address + 5] = (byte)(value._address >> 8); + _memory[_address + 6] = (byte)(value._address >> 16); + _memory[_address + 7] = (byte)(value._address >> 24); + } + } + + /// + /// Allow a pointer to be implicitly converted to a PPM context. + /// + /// + /// + public static implicit operator PpmContext(Pointer pointer) + { + return new PpmContext(pointer._address, pointer._memory); + } + + /// + /// Allow pointer-like addition on a PPM context. + /// + /// + /// + /// + public static PpmContext operator +(PpmContext context, int offset) + { + context._address = (uint)(context._address + (offset * SIZE)); + return context; + } + + /// + /// Allow pointer-like subtraction on a PPM context. + /// + /// + /// + /// + public static PpmContext operator -(PpmContext context, int offset) + { + context._address = (uint)(context._address - (offset * SIZE)); + return context; + } + + /// + /// Compare two PPM contexts. + /// + /// + /// + /// + public static bool operator <=(PpmContext context1, PpmContext context2) + { + return context1._address <= context2._address; + } + + /// + /// Compare two PPM contexts. + /// + /// + /// + /// + public static bool operator >=(PpmContext context1, PpmContext context2) + { + return context1._address >= context2._address; + } + + /// + /// Compare two PPM contexts. + /// + /// + /// + /// + public static bool operator ==(PpmContext context1, PpmContext context2) + { + return context1._address == context2._address; + } + + /// + /// Compare two PPM contexts. + /// + /// + /// + /// + public static bool operator !=(PpmContext context1, PpmContext context2) + { + return context1._address != context2._address; + } + + /// + /// Indicates whether this instance and a specified object are equal. + /// + /// true if obj and this instance are the same type and represent the same value; otherwise, false. + /// Another object to compare to. + public override bool Equals(object obj) + { + if (obj is PpmContext context) + { + return context._address == _address; + } + return base.Equals(obj); + } + + /// + /// Returns the hash code for this instance. + /// + /// A 32-bit signed integer that is the hash code for this instance. + public override int GetHashCode() + { + return _address.GetHashCode(); + } + } + + private void EncodeBinarySymbol(int symbol, PpmContext context) + { + var state = context.FirstState; + int index1 = _probabilities[state.Frequency - 1]; + var index2 = + _numberStatisticsToBinarySummaryIndex[context.Suffix.NumberStatistics] + + _previousSuccess + + context.Flags + + ((_runLength >> 26) & 0x20); + + if (state.Symbol == symbol) + { + _foundState = state; + state.Frequency += (byte)((state.Frequency < 196) ? 1 : 0); + _coder._lowCount = 0; + _coder._highCount = _binarySummary[index1, index2]; + _binarySummary[index1, index2] += (ushort)( + INTERVAL - Mean(_binarySummary[index1, index2], PERIOD_BIT_COUNT, 2) + ); + _previousSuccess = 1; + _runLength++; + } + else + { + _coder._lowCount = _binarySummary[index1, index2]; + _binarySummary[index1, index2] -= (ushort)Mean( + _binarySummary[index1, index2], + PERIOD_BIT_COUNT, + 2 + ); + _coder._highCount = BINARY_SCALE; + _initialEscape = EXPONENTIAL_ESCAPES[_binarySummary[index1, index2] >> 10]; + _characterMask[state.Symbol] = _escapeCount; _previousSuccess = 0; - while ((++state).Symbol != symbol) - { - lowCount += state.Frequency; - if (--index == 0) - { - _coder._lowCount = lowCount; - _characterMask[state.Symbol] = _escapeCount; - _numberMasked = context.NumberStatistics; - index = context.NumberStatistics; - _foundState = PpmState.ZERO; - do - { - _characterMask[(--state).Symbol] = _escapeCount; - } while (--index != 0); - _coder._highCount = _coder._scale; - return; - } - } - _coder._highCount = (_coder._lowCount = lowCount) + state.Frequency; - Update1(state, context); + _numberMasked = 0; + _foundState = PpmState.ZERO; } + } - private void EncodeSymbol2(int symbol, PpmContext context) - { - See2Context see2Context = MakeEscapeFrequency(context); - uint currentSymbol; - uint lowCount = 0; - uint index = (uint)(context.NumberStatistics - _numberMasked); - PpmState state = context.Statistics - 1; - - do - { - do - { - currentSymbol = state[1].Symbol; - state++; - } while (_characterMask[currentSymbol] == _escapeCount); - _characterMask[currentSymbol] = _escapeCount; - if (currentSymbol == symbol) - { - goto SymbolFound; - } - lowCount += state.Frequency; - } while (--index != 0); - - _coder._lowCount = lowCount; - _coder._scale += _coder._lowCount; - _coder._highCount = _coder._scale; - see2Context._summary += (ushort)_coder._scale; - _numberMasked = context.NumberStatistics; - return; - - SymbolFound: - _coder._lowCount = lowCount; - lowCount += state.Frequency; - _coder._highCount = lowCount; - for (PpmState p1 = state; --index != 0; ) - { - do - { - currentSymbol = p1[1].Symbol; - p1++; - } while (_characterMask[currentSymbol] == _escapeCount); - lowCount += p1.Frequency; - } - _coder._scale += lowCount; - see2Context.Update(); - Update2(state, context); - } - - private void DecodeBinarySymbol(PpmContext context) - { - PpmState state = context.FirstState; - int index1 = _probabilities[state.Frequency - 1]; - int index2 = - _numberStatisticsToBinarySummaryIndex[context.Suffix.NumberStatistics] - + _previousSuccess - + context.Flags - + ((_runLength >> 26) & 0x20); - - if (_coder.RangeGetCurrentShiftCount(TOTAL_BIT_COUNT) < _binarySummary[index1, index2]) - { - _foundState = state; - state.Frequency += (byte)((state.Frequency < 196) ? 1 : 0); - _coder._lowCount = 0; - _coder._highCount = _binarySummary[index1, index2]; - _binarySummary[index1, index2] += (ushort)( - INTERVAL - Mean(_binarySummary[index1, index2], PERIOD_BIT_COUNT, 2) - ); - _previousSuccess = 1; - _runLength++; - } - else - { - _coder._lowCount = _binarySummary[index1, index2]; - _binarySummary[index1, index2] -= (ushort)Mean( - _binarySummary[index1, index2], - PERIOD_BIT_COUNT, - 2 - ); - _coder._highCount = BINARY_SCALE; - _initialEscape = EXPONENTIAL_ESCAPES[_binarySummary[index1, index2] >> 10]; - _characterMask[state.Symbol] = _escapeCount; - _previousSuccess = 0; - _numberMasked = 0; - _foundState = PpmState.ZERO; - } - } - - private void DecodeSymbol1(PpmContext context) - { - uint index; - uint count; - uint highCount = context.Statistics.Frequency; - PpmState state = context.Statistics; - _coder._scale = context.SummaryFrequency; - - count = _coder.RangeGetCurrentCount(); - if (count < highCount) - { - _coder._highCount = highCount; - _previousSuccess = (byte)((2 * _coder._highCount >= _coder._scale) ? 1 : 0); - _foundState = state; - highCount += 4; - _foundState.Frequency = (byte)highCount; - context.SummaryFrequency += 4; - _runLength += _previousSuccess; - if (highCount > MAXIMUM_FREQUENCY) - { - Rescale(context); - } - _coder._lowCount = 0; - return; - } - - index = context.NumberStatistics; - _previousSuccess = 0; - while ((highCount += (++state).Frequency) <= count) - { - if (--index == 0) - { - _coder._lowCount = highCount; - _characterMask[state.Symbol] = _escapeCount; - _numberMasked = context.NumberStatistics; - index = context.NumberStatistics; - _foundState = PpmState.ZERO; - do - { - _characterMask[(--state).Symbol] = _escapeCount; - } while (--index != 0); - _coder._highCount = _coder._scale; - return; - } - } - _coder._highCount = highCount; - _coder._lowCount = _coder._highCount - state.Frequency; - Update1(state, context); - } - - private void DecodeSymbol2(PpmContext context) - { - See2Context see2Context = MakeEscapeFrequency(context); - uint currentSymbol; - uint count; - uint highCount = 0; - uint index = (uint)(context.NumberStatistics - _numberMasked); - uint stateIndex = 0; - PpmState state = context.Statistics - 1; - - do - { - do - { - currentSymbol = state[1].Symbol; - state++; - } while (_characterMask[currentSymbol] == _escapeCount); - highCount += state.Frequency; - _decodeStates[stateIndex++] = state; - - // note that decodeStates is a static array that is re-used on each call to this method (for performance reasons) - } while (--index != 0); - - _coder._scale += highCount; - count = _coder.RangeGetCurrentCount(); - stateIndex = 0; - state = _decodeStates[stateIndex]; - if (count < highCount) - { - highCount = 0; - while ((highCount += state.Frequency) <= count) - { - state = _decodeStates[++stateIndex]; - } - _coder._highCount = highCount; - _coder._lowCount = _coder._highCount - state.Frequency; - see2Context.Update(); - Update2(state, context); - } - else - { - _coder._lowCount = highCount; - _coder._highCount = _coder._scale; - index = (uint)(context.NumberStatistics - _numberMasked); - _numberMasked = context.NumberStatistics; - do - { - _characterMask[_decodeStates[stateIndex].Symbol] = _escapeCount; - stateIndex++; - } while (--index != 0); - see2Context._summary += (ushort)_coder._scale; - } - } - - private void Update1(PpmState state, PpmContext context) - { - _foundState = state; - _foundState.Frequency += 4; - context.SummaryFrequency += 4; - if (state[0].Frequency > state[-1].Frequency) - { - Swap(state[0], state[-1]); - _foundState = --state; - if (state.Frequency > MAXIMUM_FREQUENCY) - { - Rescale(context); - } - } - } - - private void Update2(PpmState state, PpmContext context) + private void EncodeSymbol1(int symbol, PpmContext context) + { + uint lowCount; + uint index = context.Statistics.Symbol; + var state = context.Statistics; + _coder._scale = context.SummaryFrequency; + if (index == symbol) { + _coder._highCount = state.Frequency; + _previousSuccess = (byte)((2 * _coder._highCount >= _coder._scale) ? 1 : 0); _foundState = state; _foundState.Frequency += 4; context.SummaryFrequency += 4; + _runLength += _previousSuccess; if (state.Frequency > MAXIMUM_FREQUENCY) { Rescale(context); } - _escapeCount++; - _runLength = _initialRunLength; + _coder._lowCount = 0; + return; } - private See2Context MakeEscapeFrequency(PpmContext context) + lowCount = state.Frequency; + index = context.NumberStatistics; + _previousSuccess = 0; + while ((++state).Symbol != symbol) { - uint numberStatistics = (uint)2 * context.NumberStatistics; - See2Context see2Context; - - if (context.NumberStatistics != 0xff) + lowCount += state.Frequency; + if (--index == 0) { - // Note that context.Flags is always in the range 0 .. 28 (this ensures that the index used for the second - // dimension of the see2Contexts array is always in the range 0 .. 31). - - numberStatistics = context.Suffix.NumberStatistics; - int index1 = _probabilities[context.NumberStatistics + 2] - 3; - int index2 = - ((context.SummaryFrequency > 11 * (context.NumberStatistics + 1)) ? 1 : 0) - + ((2 * context.NumberStatistics < numberStatistics + _numberMasked) ? 2 : 0) - + context.Flags; - see2Context = _see2Contexts[index1, index2]; - _coder._scale = see2Context.Mean(); + _coder._lowCount = lowCount; + _characterMask[state.Symbol] = _escapeCount; + _numberMasked = context.NumberStatistics; + index = context.NumberStatistics; + _foundState = PpmState.ZERO; + do + { + _characterMask[(--state).Symbol] = _escapeCount; + } while (--index != 0); + _coder._highCount = _coder._scale; + return; } - else - { - see2Context = _emptySee2Context; - _coder._scale = 1; - } - - return see2Context; } + _coder._highCount = (_coder._lowCount = lowCount) + state.Frequency; + Update1(state, context); + } - private void Rescale(PpmContext context) + private void EncodeSymbol2(int symbol, PpmContext context) + { + var see2Context = MakeEscapeFrequency(context); + uint currentSymbol; + uint lowCount = 0; + var index = (uint)(context.NumberStatistics - _numberMasked); + var state = context.Statistics - 1; + + do { - uint oldUnitCount; - int adder; - uint escapeFrequency; - uint index = context.NumberStatistics; - - byte localSymbol; - byte localFrequency; - PpmContext localSuccessor; - PpmState p1; - PpmState state; - - for (state = _foundState; state != context.Statistics; state--) - { - Swap(state[0], state[-1]); - } - - state.Frequency += 4; - context.SummaryFrequency += 4; - escapeFrequency = (uint)(context.SummaryFrequency - state.Frequency); - adder = (_orderFall != 0 || _method > ModelRestorationMethod.Freeze) ? 1 : 0; - state.Frequency = (byte)((state.Frequency + adder) >> 1); - context.SummaryFrequency = state.Frequency; - do { - escapeFrequency -= (++state).Frequency; - state.Frequency = (byte)((state.Frequency + adder) >> 1); - context.SummaryFrequency += state.Frequency; - if (state[0].Frequency > state[-1].Frequency) - { - p1 = state; - localSymbol = p1.Symbol; - localFrequency = p1.Frequency; - localSuccessor = p1.Successor; - do - { - Copy(p1[0], p1[-1]); - } while (localFrequency > (--p1)[-1].Frequency); - p1.Symbol = localSymbol; - p1.Frequency = localFrequency; - p1.Successor = localSuccessor; - } - } while (--index != 0); - - if (state.Frequency == 0) + currentSymbol = state[1].Symbol; + state++; + } while (_characterMask[currentSymbol] == _escapeCount); + _characterMask[currentSymbol] = _escapeCount; + if (currentSymbol == symbol) { - do - { - index++; - } while ((--state).Frequency == 0); - - escapeFrequency += index; - oldUnitCount = (uint)((context.NumberStatistics + 2) >> 1); - context.NumberStatistics -= (byte)index; - if (context.NumberStatistics == 0) - { - localSymbol = context.Statistics.Symbol; - localFrequency = context.Statistics.Frequency; - localSuccessor = context.Statistics.Successor; - localFrequency = (byte)( - (2 * localFrequency + escapeFrequency - 1) / escapeFrequency - ); - if (localFrequency > MAXIMUM_FREQUENCY / 3) - { - localFrequency = (byte)(MAXIMUM_FREQUENCY / 3); - } - _allocator.FreeUnits(context.Statistics, oldUnitCount); - context.FirstStateSymbol = localSymbol; - context.FirstStateFrequency = localFrequency; - context.FirstStateSuccessor = localSuccessor; - context.Flags = (byte)( - (context.Flags & 0x10) + ((localSymbol >= 0x40) ? 0x08 : 0x00) - ); - _foundState = context.FirstState; - return; - } - - context.Statistics = _allocator.ShrinkUnits( - context.Statistics, - oldUnitCount, - (uint)((context.NumberStatistics + 2) >> 1) - ); - context.Flags &= 0xf7; - index = context.NumberStatistics; - state = context.Statistics; - context.Flags |= (byte)((state.Symbol >= 0x40) ? 0x08 : 0x00); - do - { - context.Flags |= (byte)(((++state).Symbol >= 0x40) ? 0x08 : 0x00); - } while (--index != 0); + goto SymbolFound; } + lowCount += state.Frequency; + } while (--index != 0); - escapeFrequency -= (escapeFrequency >> 1); - context.SummaryFrequency += (ushort)escapeFrequency; - context.Flags |= 0x04; - _foundState = context.Statistics; + _coder._lowCount = lowCount; + _coder._scale += _coder._lowCount; + _coder._highCount = _coder._scale; + see2Context._summary += (ushort)_coder._scale; + _numberMasked = context.NumberStatistics; + return; + + SymbolFound: + _coder._lowCount = lowCount; + lowCount += state.Frequency; + _coder._highCount = lowCount; + for (var p1 = state; --index != 0;) + { + do + { + currentSymbol = p1[1].Symbol; + p1++; + } while (_characterMask[currentSymbol] == _escapeCount); + lowCount += p1.Frequency; + } + _coder._scale += lowCount; + see2Context.Update(); + Update2(state, context); + } + + private void DecodeBinarySymbol(PpmContext context) + { + var state = context.FirstState; + int index1 = _probabilities[state.Frequency - 1]; + var index2 = + _numberStatisticsToBinarySummaryIndex[context.Suffix.NumberStatistics] + + _previousSuccess + + context.Flags + + ((_runLength >> 26) & 0x20); + + if (_coder.RangeGetCurrentShiftCount(TOTAL_BIT_COUNT) < _binarySummary[index1, index2]) + { + _foundState = state; + state.Frequency += (byte)((state.Frequency < 196) ? 1 : 0); + _coder._lowCount = 0; + _coder._highCount = _binarySummary[index1, index2]; + _binarySummary[index1, index2] += (ushort)( + INTERVAL - Mean(_binarySummary[index1, index2], PERIOD_BIT_COUNT, 2) + ); + _previousSuccess = 1; + _runLength++; + } + else + { + _coder._lowCount = _binarySummary[index1, index2]; + _binarySummary[index1, index2] -= (ushort)Mean( + _binarySummary[index1, index2], + PERIOD_BIT_COUNT, + 2 + ); + _coder._highCount = BINARY_SCALE; + _initialEscape = EXPONENTIAL_ESCAPES[_binarySummary[index1, index2] >> 10]; + _characterMask[state.Symbol] = _escapeCount; + _previousSuccess = 0; + _numberMasked = 0; + _foundState = PpmState.ZERO; + } + } + + private void DecodeSymbol1(PpmContext context) + { + uint index; + uint count; + uint highCount = context.Statistics.Frequency; + var state = context.Statistics; + _coder._scale = context.SummaryFrequency; + + count = _coder.RangeGetCurrentCount(); + if (count < highCount) + { + _coder._highCount = highCount; + _previousSuccess = (byte)((2 * _coder._highCount >= _coder._scale) ? 1 : 0); + _foundState = state; + highCount += 4; + _foundState.Frequency = (byte)highCount; + context.SummaryFrequency += 4; + _runLength += _previousSuccess; + if (highCount > MAXIMUM_FREQUENCY) + { + Rescale(context); + } + _coder._lowCount = 0; + return; } - private void Refresh(uint oldUnitCount, bool scale, PpmContext context) + index = context.NumberStatistics; + _previousSuccess = 0; + while ((highCount += (++state).Frequency) <= count) { - int index = context.NumberStatistics; - int escapeFrequency; - int scaleValue = (scale ? 1 : 0); + if (--index == 0) + { + _coder._lowCount = highCount; + _characterMask[state.Symbol] = _escapeCount; + _numberMasked = context.NumberStatistics; + index = context.NumberStatistics; + _foundState = PpmState.ZERO; + do + { + _characterMask[(--state).Symbol] = _escapeCount; + } while (--index != 0); + _coder._highCount = _coder._scale; + return; + } + } + _coder._highCount = highCount; + _coder._lowCount = _coder._highCount - state.Frequency; + Update1(state, context); + } + + private void DecodeSymbol2(PpmContext context) + { + var see2Context = MakeEscapeFrequency(context); + uint currentSymbol; + uint count; + uint highCount = 0; + var index = (uint)(context.NumberStatistics - _numberMasked); + uint stateIndex = 0; + var state = context.Statistics - 1; + + do + { + do + { + currentSymbol = state[1].Symbol; + state++; + } while (_characterMask[currentSymbol] == _escapeCount); + highCount += state.Frequency; + _decodeStates[stateIndex++] = state; + + // note that decodeStates is a static array that is re-used on each call to this method (for performance reasons) + } while (--index != 0); + + _coder._scale += highCount; + count = _coder.RangeGetCurrentCount(); + stateIndex = 0; + state = _decodeStates[stateIndex]; + if (count < highCount) + { + highCount = 0; + while ((highCount += state.Frequency) <= count) + { + state = _decodeStates[++stateIndex]; + } + _coder._highCount = highCount; + _coder._lowCount = _coder._highCount - state.Frequency; + see2Context.Update(); + Update2(state, context); + } + else + { + _coder._lowCount = highCount; + _coder._highCount = _coder._scale; + index = (uint)(context.NumberStatistics - _numberMasked); + _numberMasked = context.NumberStatistics; + do + { + _characterMask[_decodeStates[stateIndex].Symbol] = _escapeCount; + stateIndex++; + } while (--index != 0); + see2Context._summary += (ushort)_coder._scale; + } + } + + private void Update1(PpmState state, PpmContext context) + { + _foundState = state; + _foundState.Frequency += 4; + context.SummaryFrequency += 4; + if (state[0].Frequency > state[-1].Frequency) + { + Swap(state[0], state[-1]); + _foundState = --state; + if (state.Frequency > MAXIMUM_FREQUENCY) + { + Rescale(context); + } + } + } + + private void Update2(PpmState state, PpmContext context) + { + _foundState = state; + _foundState.Frequency += 4; + context.SummaryFrequency += 4; + if (state.Frequency > MAXIMUM_FREQUENCY) + { + Rescale(context); + } + _escapeCount++; + _runLength = _initialRunLength; + } + + private See2Context MakeEscapeFrequency(PpmContext context) + { + var numberStatistics = (uint)2 * context.NumberStatistics; + See2Context see2Context; + + if (context.NumberStatistics != 0xff) + { + // Note that context.Flags is always in the range 0 .. 28 (this ensures that the index used for the second + // dimension of the see2Contexts array is always in the range 0 .. 31). + + numberStatistics = context.Suffix.NumberStatistics; + var index1 = _probabilities[context.NumberStatistics + 2] - 3; + var index2 = + ((context.SummaryFrequency > 11 * (context.NumberStatistics + 1)) ? 1 : 0) + + ((2 * context.NumberStatistics < numberStatistics + _numberMasked) ? 2 : 0) + + context.Flags; + see2Context = _see2Contexts[index1, index2]; + _coder._scale = see2Context.Mean(); + } + else + { + see2Context = _emptySee2Context; + _coder._scale = 1; + } + + return see2Context; + } + + private void Rescale(PpmContext context) + { + uint oldUnitCount; + int adder; + uint escapeFrequency; + uint index = context.NumberStatistics; + + byte localSymbol; + byte localFrequency; + PpmContext localSuccessor; + PpmState p1; + PpmState state; + + for (state = _foundState; state != context.Statistics; state--) + { + Swap(state[0], state[-1]); + } + + state.Frequency += 4; + context.SummaryFrequency += 4; + escapeFrequency = (uint)(context.SummaryFrequency - state.Frequency); + adder = (_orderFall != 0 || _method > ModelRestorationMethod.Freeze) ? 1 : 0; + state.Frequency = (byte)((state.Frequency + adder) >> 1); + context.SummaryFrequency = state.Frequency; + + do + { + escapeFrequency -= (++state).Frequency; + state.Frequency = (byte)((state.Frequency + adder) >> 1); + context.SummaryFrequency += state.Frequency; + if (state[0].Frequency > state[-1].Frequency) + { + p1 = state; + localSymbol = p1.Symbol; + localFrequency = p1.Frequency; + localSuccessor = p1.Successor; + do + { + Copy(p1[0], p1[-1]); + } while (localFrequency > (--p1)[-1].Frequency); + p1.Symbol = localSymbol; + p1.Frequency = localFrequency; + p1.Successor = localSuccessor; + } + } while (--index != 0); + + if (state.Frequency == 0) + { + do + { + index++; + } while ((--state).Frequency == 0); + + escapeFrequency += index; + oldUnitCount = (uint)((context.NumberStatistics + 2) >> 1); + context.NumberStatistics -= (byte)index; + if (context.NumberStatistics == 0) + { + localSymbol = context.Statistics.Symbol; + localFrequency = context.Statistics.Frequency; + localSuccessor = context.Statistics.Successor; + localFrequency = (byte)( + ((2 * localFrequency) + escapeFrequency - 1) / escapeFrequency + ); + if (localFrequency > MAXIMUM_FREQUENCY / 3) + { + localFrequency = (byte)(MAXIMUM_FREQUENCY / 3); + } + _allocator.FreeUnits(context.Statistics, oldUnitCount); + context.FirstStateSymbol = localSymbol; + context.FirstStateFrequency = localFrequency; + context.FirstStateSuccessor = localSuccessor; + context.Flags = (byte)( + (context.Flags & 0x10) + ((localSymbol >= 0x40) ? 0x08 : 0x00) + ); + _foundState = context.FirstState; + return; + } context.Statistics = _allocator.ShrinkUnits( context.Statistics, oldUnitCount, - (uint)((index + 2) >> 1) + (uint)((context.NumberStatistics + 2) >> 1) ); - PpmState statistics = context.Statistics; - context.Flags = (byte)( - (context.Flags & (0x10 + (scale ? 0x04 : 0x00))) - + ((statistics.Symbol >= 0x40) ? 0x08 : 0x00) - ); - escapeFrequency = context.SummaryFrequency - statistics.Frequency; - statistics.Frequency = (byte)((statistics.Frequency + scaleValue) >> scaleValue); - context.SummaryFrequency = statistics.Frequency; - + context.Flags &= 0xf7; + index = context.NumberStatistics; + state = context.Statistics; + context.Flags |= (byte)((state.Symbol >= 0x40) ? 0x08 : 0x00); do { - escapeFrequency -= (++statistics).Frequency; - statistics.Frequency = (byte)((statistics.Frequency + scaleValue) >> scaleValue); - context.SummaryFrequency += statistics.Frequency; - context.Flags |= (byte)((statistics.Symbol >= 0x40) ? 0x08 : 0x00); + context.Flags |= (byte)(((++state).Symbol >= 0x40) ? 0x08 : 0x00); } while (--index != 0); - - escapeFrequency = (escapeFrequency + scaleValue) >> scaleValue; - context.SummaryFrequency += (ushort)escapeFrequency; } - private PpmContext CutOff(int order, PpmContext context) + escapeFrequency -= (escapeFrequency >> 1); + context.SummaryFrequency += (ushort)escapeFrequency; + context.Flags |= 0x04; + _foundState = context.Statistics; + } + + private void Refresh(uint oldUnitCount, bool scale, PpmContext context) + { + int index = context.NumberStatistics; + int escapeFrequency; + var scaleValue = (scale ? 1 : 0); + + context.Statistics = _allocator.ShrinkUnits( + context.Statistics, + oldUnitCount, + (uint)((index + 2) >> 1) + ); + var statistics = context.Statistics; + context.Flags = (byte)( + (context.Flags & (0x10 + (scale ? 0x04 : 0x00))) + + ((statistics.Symbol >= 0x40) ? 0x08 : 0x00) + ); + escapeFrequency = context.SummaryFrequency - statistics.Frequency; + statistics.Frequency = (byte)((statistics.Frequency + scaleValue) >> scaleValue); + context.SummaryFrequency = statistics.Frequency; + + do { - int index; - PpmState state; + escapeFrequency -= (++statistics).Frequency; + statistics.Frequency = (byte)((statistics.Frequency + scaleValue) >> scaleValue); + context.SummaryFrequency += statistics.Frequency; + context.Flags |= (byte)((statistics.Symbol >= 0x40) ? 0x08 : 0x00); + } while (--index != 0); - if (context.NumberStatistics == 0) + escapeFrequency = (escapeFrequency + scaleValue) >> scaleValue; + context.SummaryFrequency += (ushort)escapeFrequency; + } + + private PpmContext CutOff(int order, PpmContext context) + { + int index; + PpmState state; + + if (context.NumberStatistics == 0) + { + state = context.FirstState; + if ((Pointer)state.Successor >= _allocator._baseUnit) { - state = context.FirstState; - if ((Pointer)state.Successor >= _allocator._baseUnit) - { - if (order < _modelOrder) - { - state.Successor = CutOff(order + 1, state.Successor); - } - else - { - state.Successor = PpmContext.ZERO; - } - - if (state.Successor == PpmContext.ZERO && order > ORDER_BOUND) - { - _allocator.SpecialFreeUnits(context); - return PpmContext.ZERO; - } - - return context; - } - _allocator.SpecialFreeUnits(context); - return PpmContext.ZERO; - } - - uint unitCount = (uint)((context.NumberStatistics + 2) >> 1); - context.Statistics = _allocator.MoveUnitsUp(context.Statistics, unitCount); - index = context.NumberStatistics; - for (state = context.Statistics + index; state >= context.Statistics; state--) - { - if (state.Successor < _allocator._baseUnit) - { - state.Successor = PpmContext.ZERO; - Swap(state, context.Statistics[index--]); - } - else if (order < _modelOrder) + if (order < _modelOrder) { state.Successor = CutOff(order + 1, state.Successor); } @@ -798,77 +766,107 @@ namespace SharpCompress.Compressors.PPMd.I1 { state.Successor = PpmContext.ZERO; } - } - if (index != context.NumberStatistics && order != 0) - { - context.NumberStatistics = (byte)index; - state = context.Statistics; - if (index < 0) + if (state.Successor == PpmContext.ZERO && order > ORDER_BOUND) { - _allocator.FreeUnits(state, unitCount); _allocator.SpecialFreeUnits(context); return PpmContext.ZERO; } - if (index == 0) - { - context.Flags = (byte)( - (context.Flags & 0x10) + ((state.Symbol >= 0x40) ? 0x08 : 0x00) - ); - Copy(context.FirstState, state); - _allocator.FreeUnits(state, unitCount); - context.FirstStateFrequency = (byte)((context.FirstStateFrequency + 11) >> 3); - } - else - { - Refresh(unitCount, context.SummaryFrequency > 16 * index, context); - } - } - return context; - } - - private PpmContext RemoveBinaryContexts(int order, PpmContext context) - { - if (context.NumberStatistics == 0) - { - PpmState state = context.FirstState; - if ((Pointer)state.Successor >= _allocator._baseUnit && order < _modelOrder) - { - state.Successor = RemoveBinaryContexts(order + 1, state.Successor); - } - else - { - state.Successor = PpmContext.ZERO; - } - if ( - (state.Successor == PpmContext.ZERO) - && (context.Suffix.NumberStatistics == 0 || context.Suffix.Flags == 0xff) - ) - { - _allocator.FreeUnits(context, 1); - return PpmContext.ZERO; - } return context; } + _allocator.SpecialFreeUnits(context); + return PpmContext.ZERO; + } - for ( - PpmState state = context.Statistics + context.NumberStatistics; - state >= context.Statistics; - state-- + var unitCount = (uint)((context.NumberStatistics + 2) >> 1); + context.Statistics = _allocator.MoveUnitsUp(context.Statistics, unitCount); + index = context.NumberStatistics; + for (state = context.Statistics + index; state >= context.Statistics; state--) + { + if (state.Successor < _allocator._baseUnit) + { + state.Successor = PpmContext.ZERO; + Swap(state, context.Statistics[index--]); + } + else if (order < _modelOrder) + { + state.Successor = CutOff(order + 1, state.Successor); + } + else + { + state.Successor = PpmContext.ZERO; + } + } + + if (index != context.NumberStatistics && order != 0) + { + context.NumberStatistics = (byte)index; + state = context.Statistics; + if (index < 0) + { + _allocator.FreeUnits(state, unitCount); + _allocator.SpecialFreeUnits(context); + return PpmContext.ZERO; + } + if (index == 0) + { + context.Flags = (byte)( + (context.Flags & 0x10) + ((state.Symbol >= 0x40) ? 0x08 : 0x00) + ); + Copy(context.FirstState, state); + _allocator.FreeUnits(state, unitCount); + context.FirstStateFrequency = (byte)((context.FirstStateFrequency + 11) >> 3); + } + else + { + Refresh(unitCount, context.SummaryFrequency > 16 * index, context); + } + } + + return context; + } + + private PpmContext RemoveBinaryContexts(int order, PpmContext context) + { + if (context.NumberStatistics == 0) + { + var state = context.FirstState; + if ((Pointer)state.Successor >= _allocator._baseUnit && order < _modelOrder) + { + state.Successor = RemoveBinaryContexts(order + 1, state.Successor); + } + else + { + state.Successor = PpmContext.ZERO; + } + if ( + (state.Successor == PpmContext.ZERO) + && (context.Suffix.NumberStatistics == 0 || context.Suffix.Flags == 0xff) ) { - if ((Pointer)state.Successor >= _allocator._baseUnit && order < _modelOrder) - { - state.Successor = RemoveBinaryContexts(order + 1, state.Successor); - } - else - { - state.Successor = PpmContext.ZERO; - } + _allocator.FreeUnits(context, 1); + return PpmContext.ZERO; } - return context; } + + for ( + var state = context.Statistics + context.NumberStatistics; + state >= context.Statistics; + state-- + ) + { + if ((Pointer)state.Successor >= _allocator._baseUnit && order < _modelOrder) + { + state.Successor = RemoveBinaryContexts(order + 1, state.Successor); + } + else + { + state.Successor = PpmContext.ZERO; + } + } + + return context; } } diff --git a/src/SharpCompress/Compressors/PPMd/I1/PpmState.cs b/src/SharpCompress/Compressors/PPMd/I1/PpmState.cs index de88fea1..6ed4f9a5 100644 --- a/src/SharpCompress/Compressors/PPMd/I1/PpmState.cs +++ b/src/SharpCompress/Compressors/PPMd/I1/PpmState.cs @@ -1,206 +1,204 @@ #nullable disable -namespace SharpCompress.Compressors.PPMd.I1 +namespace SharpCompress.Compressors.PPMd.I1; + +/// +/// PPM state. +/// +/// +/// +/// This must be a structure rather than a class because several places in the associated code assume that +/// is a value type (meaning that assignment creates a completely new copy of the +/// instance rather than just copying a reference to the same instance). +/// +/// +/// Note that is a field rather than a property for performance reasons. +/// +/// +internal struct PpmState { + public uint _address; + public byte[] _memory; + public static readonly PpmState ZERO = new PpmState(0, null); + public const int SIZE = 6; + /// - /// PPM state. + /// Initializes a new instance of the structure. /// - /// - /// - /// This must be a structure rather than a class because several places in the associated code assume that - /// is a value type (meaning that assignment creates a completely new copy of the - /// instance rather than just copying a reference to the same instance). - /// - /// - /// Note that is a field rather than a property for performance reasons. - /// - /// - internal struct PpmState + public PpmState(uint address, byte[] memory) { - public uint _address; - public byte[] _memory; - public static readonly PpmState ZERO = new PpmState(0, null); - public const int SIZE = 6; + _address = address; + _memory = memory; + } - /// - /// Initializes a new instance of the structure. - /// - public PpmState(uint address, byte[] memory) + /// + /// Gets or sets the symbol. + /// + public byte Symbol + { + get => _memory[_address]; + set => _memory[_address] = value; + } + + /// + /// Gets or sets the frequency. + /// + public byte Frequency + { + get => _memory[_address + 1]; + set => _memory[_address + 1] = value; + } + + /// + /// Gets or sets the successor. + /// + public Model.PpmContext Successor + { + get => + new Model.PpmContext( + _memory[_address + 2] + | (((uint)_memory[_address + 3]) << 8) + | (((uint)_memory[_address + 4]) << 16) + | (((uint)_memory[_address + 5]) << 24), + _memory + ); + set { - _address = address; - _memory = memory; - } - - /// - /// Gets or sets the symbol. - /// - public byte Symbol - { - get => _memory[_address]; - set => _memory[_address] = value; - } - - /// - /// Gets or sets the frequency. - /// - public byte Frequency - { - get => _memory[_address + 1]; - set => _memory[_address + 1] = value; - } - - /// - /// Gets or sets the successor. - /// - public Model.PpmContext Successor - { - get => - new Model.PpmContext( - _memory[_address + 2] - | ((uint)_memory[_address + 3]) << 8 - | ((uint)_memory[_address + 4]) << 16 - | ((uint)_memory[_address + 5]) << 24, - _memory - ); - set - { - _memory[_address + 2] = (byte)value._address; - _memory[_address + 3] = (byte)(value._address >> 8); - _memory[_address + 4] = (byte)(value._address >> 16); - _memory[_address + 5] = (byte)(value._address >> 24); - } - } - - /// - /// Gets the at the relative to this - /// . - /// - /// - /// - public PpmState this[int offset] => new PpmState((uint)(_address + offset * SIZE), _memory); - - /// - /// Allow a pointer to be implicitly converted to a PPM state. - /// - /// - /// - public static implicit operator PpmState(Pointer pointer) - { - return new PpmState(pointer._address, pointer._memory); - } - - /// - /// Allow pointer-like addition on a PPM state. - /// - /// - /// - /// - public static PpmState operator +(PpmState state, int offset) - { - state._address = (uint)(state._address + offset * SIZE); - return state; - } - - /// - /// Allow pointer-like incrementing on a PPM state. - /// - /// - /// - public static PpmState operator ++(PpmState state) - { - state._address += SIZE; - return state; - } - - /// - /// Allow pointer-like subtraction on a PPM state. - /// - /// - /// - /// - public static PpmState operator -(PpmState state, int offset) - { - state._address = (uint)(state._address - offset * SIZE); - return state; - } - - /// - /// Allow pointer-like decrementing on a PPM state. - /// - /// - /// - public static PpmState operator --(PpmState state) - { - state._address -= SIZE; - return state; - } - - /// - /// Compare two PPM states. - /// - /// - /// - /// - public static bool operator <=(PpmState state1, PpmState state2) - { - return state1._address <= state2._address; - } - - /// - /// Compare two PPM states. - /// - /// - /// - /// - public static bool operator >=(PpmState state1, PpmState state2) - { - return state1._address >= state2._address; - } - - /// - /// Compare two PPM states. - /// - /// - /// - /// - public static bool operator ==(PpmState state1, PpmState state2) - { - return state1._address == state2._address; - } - - /// - /// Compare two PPM states. - /// - /// - /// - /// - public static bool operator !=(PpmState state1, PpmState state2) - { - return state1._address != state2._address; - } - - /// - /// Indicates whether this instance and a specified object are equal. - /// - /// true if obj and this instance are the same type and represent the same value; otherwise, false. - /// Another object to compare to. - public override bool Equals(object obj) - { - if (obj is PpmState) - { - PpmState state = (PpmState)obj; - return state._address == _address; - } - return base.Equals(obj); - } - - /// - /// Returns the hash code for this instance. - /// - /// A 32-bit signed integer that is the hash code for this instance. - public override int GetHashCode() - { - return _address.GetHashCode(); + _memory[_address + 2] = (byte)value._address; + _memory[_address + 3] = (byte)(value._address >> 8); + _memory[_address + 4] = (byte)(value._address >> 16); + _memory[_address + 5] = (byte)(value._address >> 24); } } + + /// + /// Gets the at the relative to this + /// . + /// + /// + /// + public PpmState this[int offset] => new PpmState((uint)(_address + (offset * SIZE)), _memory); + + /// + /// Allow a pointer to be implicitly converted to a PPM state. + /// + /// + /// + public static implicit operator PpmState(Pointer pointer) + { + return new PpmState(pointer._address, pointer._memory); + } + + /// + /// Allow pointer-like addition on a PPM state. + /// + /// + /// + /// + public static PpmState operator +(PpmState state, int offset) + { + state._address = (uint)(state._address + (offset * SIZE)); + return state; + } + + /// + /// Allow pointer-like incrementing on a PPM state. + /// + /// + /// + public static PpmState operator ++(PpmState state) + { + state._address += SIZE; + return state; + } + + /// + /// Allow pointer-like subtraction on a PPM state. + /// + /// + /// + /// + public static PpmState operator -(PpmState state, int offset) + { + state._address = (uint)(state._address - (offset * SIZE)); + return state; + } + + /// + /// Allow pointer-like decrementing on a PPM state. + /// + /// + /// + public static PpmState operator --(PpmState state) + { + state._address -= SIZE; + return state; + } + + /// + /// Compare two PPM states. + /// + /// + /// + /// + public static bool operator <=(PpmState state1, PpmState state2) + { + return state1._address <= state2._address; + } + + /// + /// Compare two PPM states. + /// + /// + /// + /// + public static bool operator >=(PpmState state1, PpmState state2) + { + return state1._address >= state2._address; + } + + /// + /// Compare two PPM states. + /// + /// + /// + /// + public static bool operator ==(PpmState state1, PpmState state2) + { + return state1._address == state2._address; + } + + /// + /// Compare two PPM states. + /// + /// + /// + /// + public static bool operator !=(PpmState state1, PpmState state2) + { + return state1._address != state2._address; + } + + /// + /// Indicates whether this instance and a specified object are equal. + /// + /// true if obj and this instance are the same type and represent the same value; otherwise, false. + /// Another object to compare to. + public override bool Equals(object obj) + { + if (obj is PpmState state) + { + return state._address == _address; + } + return base.Equals(obj); + } + + /// + /// Returns the hash code for this instance. + /// + /// A 32-bit signed integer that is the hash code for this instance. + public override int GetHashCode() + { + return _address.GetHashCode(); + } } diff --git a/src/SharpCompress/Compressors/PPMd/I1/See2Context.cs b/src/SharpCompress/Compressors/PPMd/I1/See2Context.cs index 68e09cca..bc52e432 100644 --- a/src/SharpCompress/Compressors/PPMd/I1/See2Context.cs +++ b/src/SharpCompress/Compressors/PPMd/I1/See2Context.cs @@ -4,52 +4,51 @@ #endregion -namespace SharpCompress.Compressors.PPMd.I1 +namespace SharpCompress.Compressors.PPMd.I1; + +/// +/// SEE2 (secondary escape estimation) contexts for PPM contexts with masked symbols. +/// +/// +/// +/// This must be a class rather than a structure because MakeEscapeFrequency returns a See2Context +/// instance from the see2Contexts array. The caller (for example, EncodeSymbol2) then updates the +/// returned See2Context instance and expects the updates to be reflected in the see2Contexts array. +/// This would not happen if this were a structure. +/// +/// +/// Note that in most cases fields are used rather than properties for performance reasons (for example, +/// is a field rather than a property). +/// +/// +internal class See2Context { - /// - /// SEE2 (secondary escape estimation) contexts for PPM contexts with masked symbols. - /// - /// - /// - /// This must be a class rather than a structure because MakeEscapeFrequency returns a See2Context - /// instance from the see2Contexts array. The caller (for example, EncodeSymbol2) then updates the - /// returned See2Context instance and expects the updates to be reflected in the see2Contexts array. - /// This would not happen if this were a structure. - /// - /// - /// Note that in most cases fields are used rather than properties for performance reasons (for example, - /// is a field rather than a property). - /// - /// - internal class See2Context + private const byte PERIOD_BIT_COUNT = 7; + + public ushort _summary; + public byte _shift; + public byte _count; + + public void Initialize(uint initialValue) { - private const byte PERIOD_BIT_COUNT = 7; + _shift = PERIOD_BIT_COUNT - 4; + _summary = (ushort)(initialValue << _shift); + _count = 7; + } - public ushort _summary; - public byte _shift; - public byte _count; + public uint Mean() + { + var value = (uint)(_summary >> _shift); + _summary = (ushort)(_summary - value); + return (uint)(value + ((value == 0) ? 1 : 0)); + } - public void Initialize(uint initialValue) + public void Update() + { + if (_shift < PERIOD_BIT_COUNT && --_count == 0) { - _shift = PERIOD_BIT_COUNT - 4; - _summary = (ushort)(initialValue << _shift); - _count = 7; - } - - public uint Mean() - { - uint value = (uint)(_summary >> _shift); - _summary = (ushort)(_summary - value); - return (uint)(value + ((value == 0) ? 1 : 0)); - } - - public void Update() - { - if (_shift < PERIOD_BIT_COUNT && --_count == 0) - { - _summary += _summary; - _count = (byte)(3 << _shift++); - } + _summary += _summary; + _count = (byte)(3 << _shift++); } } } diff --git a/src/SharpCompress/Compressors/PPMd/PpmdProperties.cs b/src/SharpCompress/Compressors/PPMd/PpmdProperties.cs index 326b6019..e75d88b8 100644 --- a/src/SharpCompress/Compressors/PPMd/PpmdProperties.cs +++ b/src/SharpCompress/Compressors/PPMd/PpmdProperties.cs @@ -1,83 +1,82 @@ -using System; +using System; using System.Buffers.Binary; using SharpCompress.Compressors.PPMd.I1; -namespace SharpCompress.Compressors.PPMd +namespace SharpCompress.Compressors.PPMd; + +public class PpmdProperties { - public class PpmdProperties + private int _allocatorSize; + internal Allocator? _allocator; + + public PpmdProperties() : this(16 << 20, 6) { } + + public PpmdProperties(int allocatorSize, int modelOrder) + : this(allocatorSize, modelOrder, ModelRestorationMethod.Restart) { } + + internal PpmdProperties( + int allocatorSize, + int modelOrder, + ModelRestorationMethod modelRestorationMethod + ) { - private int _allocatorSize; - internal Allocator? _allocator; + AllocatorSize = allocatorSize; + ModelOrder = modelOrder; + RestorationMethod = modelRestorationMethod; + } - public PpmdProperties() : this(16 << 20, 6) { } + public int ModelOrder { get; } + public PpmdVersion Version { get; } = PpmdVersion.I1; + internal ModelRestorationMethod RestorationMethod { get; } - public PpmdProperties(int allocatorSize, int modelOrder) - : this(allocatorSize, modelOrder, ModelRestorationMethod.Restart) { } + public PpmdProperties(byte[] properties) : this(properties.AsSpan()) { } - internal PpmdProperties( - int allocatorSize, - int modelOrder, - ModelRestorationMethod modelRestorationMethod - ) + public PpmdProperties(ReadOnlySpan properties) + { + if (properties.Length == 2) { - AllocatorSize = allocatorSize; - ModelOrder = modelOrder; - RestorationMethod = modelRestorationMethod; + var props = BinaryPrimitives.ReadUInt16LittleEndian(properties); + AllocatorSize = (((props >> 4) & 0xff) + 1) << 20; + ModelOrder = (props & 0x0f) + 1; + RestorationMethod = (ModelRestorationMethod)(props >> 12); } - - public int ModelOrder { get; } - public PpmdVersion Version { get; } = PpmdVersion.I1; - internal ModelRestorationMethod RestorationMethod { get; } - - public PpmdProperties(byte[] properties) : this(properties.AsSpan()) { } - - public PpmdProperties(ReadOnlySpan properties) + else if (properties.Length == 5) { - if (properties.Length == 2) - { - ushort props = BinaryPrimitives.ReadUInt16LittleEndian(properties); - AllocatorSize = (((props >> 4) & 0xff) + 1) << 20; - ModelOrder = (props & 0x0f) + 1; - RestorationMethod = (ModelRestorationMethod)(props >> 12); - } - else if (properties.Length == 5) - { - Version = PpmdVersion.H7Z; - AllocatorSize = BinaryPrimitives.ReadInt32LittleEndian(properties.Slice(1)); - ModelOrder = properties[0]; - } + Version = PpmdVersion.H7Z; + AllocatorSize = BinaryPrimitives.ReadInt32LittleEndian(properties.Slice(1)); + ModelOrder = properties[0]; } + } - public int AllocatorSize + public int AllocatorSize + { + get => _allocatorSize; + set { - get => _allocatorSize; - set + _allocatorSize = value; + if (Version == PpmdVersion.I1) { - _allocatorSize = value; - if (Version == PpmdVersion.I1) - { - _allocator ??= new Allocator(); + _allocator ??= new Allocator(); - _allocator.Start(_allocatorSize); - } - } - } - - public byte[] Properties - { - get - { - byte[] bytes = new byte[2]; - BinaryPrimitives.WriteUInt16LittleEndian( - bytes, - (ushort)( - (ModelOrder - 1) - + (((AllocatorSize >> 20) - 1) << 4) - + ((ushort)RestorationMethod << 12) - ) - ); - return bytes; + _allocator.Start(_allocatorSize); } } } + + public byte[] Properties + { + get + { + var bytes = new byte[2]; + BinaryPrimitives.WriteUInt16LittleEndian( + bytes, + (ushort)( + (ModelOrder - 1) + + (((AllocatorSize >> 20) - 1) << 4) + + ((ushort)RestorationMethod << 12) + ) + ); + return bytes; + } + } } diff --git a/src/SharpCompress/Compressors/PPMd/PpmdStream.cs b/src/SharpCompress/Compressors/PPMd/PpmdStream.cs index 4e48d71a..43c9757f 100644 --- a/src/SharpCompress/Compressors/PPMd/PpmdStream.cs +++ b/src/SharpCompress/Compressors/PPMd/PpmdStream.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable using System; using System.IO; @@ -6,141 +6,140 @@ using SharpCompress.Compressors.LZMA.RangeCoder; using SharpCompress.Compressors.PPMd.H; using SharpCompress.Compressors.PPMd.I1; -namespace SharpCompress.Compressors.PPMd +namespace SharpCompress.Compressors.PPMd; + +public class PpmdStream : Stream { - public class PpmdStream : Stream + private readonly PpmdProperties _properties; + private readonly Stream _stream; + private readonly bool _compress; + private readonly Model _model; + private readonly ModelPpm _modelH; + private readonly Decoder _decoder; + private long _position; + private bool _isDisposed; + + public PpmdStream(PpmdProperties properties, Stream stream, bool compress) { - private readonly PpmdProperties _properties; - private readonly Stream _stream; - private readonly bool _compress; - private readonly Model _model; - private readonly ModelPpm _modelH; - private readonly Decoder _decoder; - private long _position; - private bool _isDisposed; + _properties = properties; + _stream = stream; + _compress = compress; - public PpmdStream(PpmdProperties properties, Stream stream, bool compress) + if (properties.Version == PpmdVersion.I1) { - _properties = properties; - _stream = stream; - _compress = compress; - - if (properties.Version == PpmdVersion.I1) + _model = new Model(); + if (compress) { - _model = new Model(); - if (compress) - { - _model.EncodeStart(properties); - } - else - { - _model.DecodeStart(stream, properties); - } + _model.EncodeStart(properties); } - if (properties.Version == PpmdVersion.H) + else { - _modelH = new ModelPpm(); - if (compress) - { - throw new NotImplementedException(); - } - _modelH.DecodeInit(stream, properties.ModelOrder, properties.AllocatorSize); - } - if (properties.Version == PpmdVersion.H7Z) - { - _modelH = new ModelPpm(); - if (compress) - { - throw new NotImplementedException(); - } - _modelH.DecodeInit(null, properties.ModelOrder, properties.AllocatorSize); - _decoder = new Decoder(); - _decoder.Init(stream); + _model.DecodeStart(stream, properties); } } - - public override bool CanRead => !_compress; - - public override bool CanSeek => false; - - public override bool CanWrite => _compress; - - public override void Flush() { } - - protected override void Dispose(bool isDisposing) + if (properties.Version == PpmdVersion.H) { - if (_isDisposed) + _modelH = new ModelPpm(); + if (compress) { - return; + throw new NotImplementedException(); } - _isDisposed = true; - if (isDisposing) - { - if (_compress) - { - _model.EncodeBlock(_stream, new MemoryStream(), true); - } - } - base.Dispose(isDisposing); + _modelH.DecodeInit(stream, properties.ModelOrder, properties.AllocatorSize); } - - public override long Length => throw new NotSupportedException(); - - public override long Position + if (properties.Version == PpmdVersion.H7Z) { - get => _position; - set => throw new NotSupportedException(); + _modelH = new ModelPpm(); + if (compress) + { + throw new NotImplementedException(); + } + _modelH.DecodeInit(null, properties.ModelOrder, properties.AllocatorSize); + _decoder = new Decoder(); + _decoder.Init(stream); } + } - public override int Read(byte[] buffer, int offset, int count) + public override bool CanRead => !_compress; + + public override bool CanSeek => false; + + public override bool CanWrite => _compress; + + public override void Flush() { } + + protected override void Dispose(bool isDisposing) + { + if (_isDisposed) + { + return; + } + _isDisposed = true; + if (isDisposing) { if (_compress) { - return 0; + _model.EncodeBlock(_stream, new MemoryStream(), true); } - int size = 0; - if (_properties.Version == PpmdVersion.I1) - { - size = _model.DecodeBlock(_stream, buffer, offset, count); - } - if (_properties.Version == PpmdVersion.H) - { - int c; - while (size < count && (c = _modelH.DecodeChar()) >= 0) - { - buffer[offset++] = (byte)c; - size++; - } - } - if (_properties.Version == PpmdVersion.H7Z) - { - int c; - while (size < count && (c = _modelH.DecodeChar(_decoder)) >= 0) - { - buffer[offset++] = (byte)c; - size++; - } - } - _position += size; - return size; } + base.Dispose(isDisposing); + } - public override long Seek(long offset, SeekOrigin origin) + public override long Length => throw new NotSupportedException(); + + public override long Position + { + get => _position; + set => throw new NotSupportedException(); + } + + public override int Read(byte[] buffer, int offset, int count) + { + if (_compress) { - throw new NotSupportedException(); + return 0; } - - public override void SetLength(long value) + var size = 0; + if (_properties.Version == PpmdVersion.I1) { - throw new NotSupportedException(); + size = _model.DecodeBlock(_stream, buffer, offset, count); } - - public override void Write(byte[] buffer, int offset, int count) + if (_properties.Version == PpmdVersion.H) { - if (_compress) + int c; + while (size < count && (c = _modelH.DecodeChar()) >= 0) { - _model.EncodeBlock(_stream, new MemoryStream(buffer, offset, count), false); + buffer[offset++] = (byte)c; + size++; } } + if (_properties.Version == PpmdVersion.H7Z) + { + int c; + while (size < count && (c = _modelH.DecodeChar(_decoder)) >= 0) + { + buffer[offset++] = (byte)c; + size++; + } + } + _position += size; + return size; + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } + + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + public override void Write(byte[] buffer, int offset, int count) + { + if (_compress) + { + _model.EncodeBlock(_stream, new MemoryStream(buffer, offset, count), false); + } } } diff --git a/src/SharpCompress/Compressors/PPMd/PpmdVersion.cs b/src/SharpCompress/Compressors/PPMd/PpmdVersion.cs index cd0d6f46..791034ac 100644 --- a/src/SharpCompress/Compressors/PPMd/PpmdVersion.cs +++ b/src/SharpCompress/Compressors/PPMd/PpmdVersion.cs @@ -1,9 +1,8 @@ -namespace SharpCompress.Compressors.PPMd +namespace SharpCompress.Compressors.PPMd; + +public enum PpmdVersion { - public enum PpmdVersion - { - H, - H7Z, - I1 - } + H, + H7Z, + I1 } diff --git a/src/SharpCompress/Compressors/Rar/IRarUnpack.cs b/src/SharpCompress/Compressors/Rar/IRarUnpack.cs index 0cc86a78..651e2c8a 100644 --- a/src/SharpCompress/Compressors/Rar/IRarUnpack.cs +++ b/src/SharpCompress/Compressors/Rar/IRarUnpack.cs @@ -1,18 +1,17 @@ -using System.IO; +using System.IO; using SharpCompress.Common.Rar.Headers; -namespace SharpCompress.Compressors.Rar +namespace SharpCompress.Compressors.Rar; + +internal interface IRarUnpack { - internal interface IRarUnpack - { - void DoUnpack(FileHeader fileHeader, Stream readStream, Stream writeStream); - void DoUnpack(); + void DoUnpack(FileHeader fileHeader, Stream readStream, Stream writeStream); + void DoUnpack(); - // eg u/i pause/resume button - bool Suspended { get; set; } + // eg u/i pause/resume button + bool Suspended { get; set; } - long DestSize { get; } - int Char { get; } - int PpmEscChar { get; set; } - } + long DestSize { get; } + int Char { get; } + int PpmEscChar { get; set; } } diff --git a/src/SharpCompress/Compressors/Rar/MultiVolumeReadOnlyStream.cs b/src/SharpCompress/Compressors/Rar/MultiVolumeReadOnlyStream.cs index db406df9..11a3f515 100644 --- a/src/SharpCompress/Compressors/Rar/MultiVolumeReadOnlyStream.cs +++ b/src/SharpCompress/Compressors/Rar/MultiVolumeReadOnlyStream.cs @@ -6,156 +6,155 @@ using System.IO; using SharpCompress.Common; using SharpCompress.Common.Rar; -namespace SharpCompress.Compressors.Rar +namespace SharpCompress.Compressors.Rar; + +internal sealed class MultiVolumeReadOnlyStream : Stream { - internal sealed class MultiVolumeReadOnlyStream : Stream + private long currentPosition; + private long maxPosition; + + private IEnumerator filePartEnumerator; + private Stream currentStream; + + private readonly IExtractionListener streamListener; + + private long currentPartTotalReadBytes; + private long currentEntryTotalReadBytes; + + internal MultiVolumeReadOnlyStream( + IEnumerable parts, + IExtractionListener streamListener + ) { - private long currentPosition; - private long maxPosition; + this.streamListener = streamListener; - private IEnumerator filePartEnumerator; - private Stream currentStream; + filePartEnumerator = parts.GetEnumerator(); + filePartEnumerator.MoveNext(); + InitializeNextFilePart(); + } - private readonly IExtractionListener streamListener; - - private long currentPartTotalReadBytes; - private long currentEntryTotalReadBytes; - - internal MultiVolumeReadOnlyStream( - IEnumerable parts, - IExtractionListener streamListener - ) + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (disposing) { - this.streamListener = streamListener; - - filePartEnumerator = parts.GetEnumerator(); - filePartEnumerator.MoveNext(); - InitializeNextFilePart(); - } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (disposing) + if (filePartEnumerator != null) { - if (filePartEnumerator != null) - { - filePartEnumerator.Dispose(); - filePartEnumerator = null; - } - currentStream = null; + filePartEnumerator.Dispose(); + filePartEnumerator = null; } - } - - private void InitializeNextFilePart() - { - maxPosition = filePartEnumerator.Current.FileHeader.CompressedSize; - currentPosition = 0; - currentStream = filePartEnumerator.Current.GetCompressedStream(); - - currentPartTotalReadBytes = 0; - - CurrentCrc = filePartEnumerator.Current.FileHeader.FileCrc; - - streamListener.FireFilePartExtractionBegin( - filePartEnumerator.Current.FilePartName, - filePartEnumerator.Current.FileHeader.CompressedSize, - filePartEnumerator.Current.FileHeader.UncompressedSize - ); - } - - public override int Read(byte[] buffer, int offset, int count) - { - int totalRead = 0; - int currentOffset = offset; - int currentCount = count; - while (currentCount > 0) - { - int readSize = currentCount; - if (currentCount > maxPosition - currentPosition) - { - readSize = (int)(maxPosition - currentPosition); - } - - int read = currentStream.Read(buffer, currentOffset, readSize); - if (read < 0) - { - throw new EndOfStreamException(); - } - - currentPosition += read; - currentOffset += read; - currentCount -= read; - totalRead += read; - if ( - ((maxPosition - currentPosition) == 0) - && filePartEnumerator.Current.FileHeader.IsSplitAfter - ) - { - if (filePartEnumerator.Current.FileHeader.R4Salt != null) - { - throw new InvalidFormatException( - "Sharpcompress currently does not support multi-volume decryption." - ); - } - string fileName = filePartEnumerator.Current.FileHeader.FileName; - if (!filePartEnumerator.MoveNext()) - { - throw new InvalidFormatException( - "Multi-part rar file is incomplete. Entry expects a new volume: " - + fileName - ); - } - InitializeNextFilePart(); - } - else - { - break; - } - } - currentPartTotalReadBytes += totalRead; - currentEntryTotalReadBytes += totalRead; - streamListener.FireCompressedBytesRead( - currentPartTotalReadBytes, - currentEntryTotalReadBytes - ); - return totalRead; - } - - public override bool CanRead => true; - - public override bool CanSeek => false; - - public override bool CanWrite => false; - - public uint CurrentCrc { get; private set; } - - public override void Flush() - { - throw new NotSupportedException(); - } - - public override long Length => throw new NotSupportedException(); - - public override long Position - { - get => throw new NotSupportedException(); - set => throw new NotSupportedException(); - } - - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } - - public override void SetLength(long value) - { - throw new NotSupportedException(); - } - - public override void Write(byte[] buffer, int offset, int count) - { - throw new NotSupportedException(); + currentStream = null; } } + + private void InitializeNextFilePart() + { + maxPosition = filePartEnumerator.Current.FileHeader.CompressedSize; + currentPosition = 0; + currentStream = filePartEnumerator.Current.GetCompressedStream(); + + currentPartTotalReadBytes = 0; + + CurrentCrc = filePartEnumerator.Current.FileHeader.FileCrc; + + streamListener.FireFilePartExtractionBegin( + filePartEnumerator.Current.FilePartName, + filePartEnumerator.Current.FileHeader.CompressedSize, + filePartEnumerator.Current.FileHeader.UncompressedSize + ); + } + + public override int Read(byte[] buffer, int offset, int count) + { + var totalRead = 0; + var currentOffset = offset; + var currentCount = count; + while (currentCount > 0) + { + var readSize = currentCount; + if (currentCount > maxPosition - currentPosition) + { + readSize = (int)(maxPosition - currentPosition); + } + + var read = currentStream.Read(buffer, currentOffset, readSize); + if (read < 0) + { + throw new EndOfStreamException(); + } + + currentPosition += read; + currentOffset += read; + currentCount -= read; + totalRead += read; + if ( + ((maxPosition - currentPosition) == 0) + && filePartEnumerator.Current.FileHeader.IsSplitAfter + ) + { + if (filePartEnumerator.Current.FileHeader.R4Salt != null) + { + throw new InvalidFormatException( + "Sharpcompress currently does not support multi-volume decryption." + ); + } + var fileName = filePartEnumerator.Current.FileHeader.FileName; + if (!filePartEnumerator.MoveNext()) + { + throw new InvalidFormatException( + "Multi-part rar file is incomplete. Entry expects a new volume: " + + fileName + ); + } + InitializeNextFilePart(); + } + else + { + break; + } + } + currentPartTotalReadBytes += totalRead; + currentEntryTotalReadBytes += totalRead; + streamListener.FireCompressedBytesRead( + currentPartTotalReadBytes, + currentEntryTotalReadBytes + ); + return totalRead; + } + + public override bool CanRead => true; + + public override bool CanSeek => false; + + public override bool CanWrite => false; + + public uint CurrentCrc { get; private set; } + + public override void Flush() + { + throw new NotSupportedException(); + } + + public override long Length => throw new NotSupportedException(); + + public override long Position + { + get => throw new NotSupportedException(); + set => throw new NotSupportedException(); + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } + + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + public override void Write(byte[] buffer, int offset, int count) + { + throw new NotSupportedException(); + } } diff --git a/src/SharpCompress/Compressors/Rar/RarCRC.cs b/src/SharpCompress/Compressors/Rar/RarCRC.cs index a7e565a4..75fd8187 100644 --- a/src/SharpCompress/Compressors/Rar/RarCRC.cs +++ b/src/SharpCompress/Compressors/Rar/RarCRC.cs @@ -1,48 +1,47 @@ using System; -namespace SharpCompress.Compressors.Rar +namespace SharpCompress.Compressors.Rar; + +internal static class RarCRC { - internal static class RarCRC + private static readonly uint[] crcTab; + + public static uint CheckCrc(uint startCrc, byte b) { - private static readonly uint[] crcTab; + return (crcTab[((int)startCrc ^ b) & 0xff] ^ (startCrc >> 8)); + } - public static uint CheckCrc(uint startCrc, byte b) + public static uint CheckCrc(uint startCrc, byte[] data, int offset, int count) + { + var size = Math.Min(data.Length - offset, count); + + for (var i = 0; i < size; i++) { - return (crcTab[((int)((int)startCrc ^ (int)b)) & 0xff] ^ (startCrc >> 8)); + startCrc = (crcTab[((int)startCrc ^ data[offset + i]) & 0xff] ^ (startCrc >> 8)); } + return (startCrc); + } - public static uint CheckCrc(uint startCrc, byte[] data, int offset, int count) + static RarCRC() + { { - int size = Math.Min(data.Length - offset, count); - - for (int i = 0; i < size; i++) + crcTab = new uint[256]; + for (uint i = 0; i < 256; i++) { - startCrc = (crcTab[((int)startCrc ^ data[offset + i]) & 0xff] ^ (startCrc >> 8)); - } - return (startCrc); - } - - static RarCRC() - { - { - crcTab = new uint[256]; - for (uint i = 0; i < 256; i++) + var c = i; + for (var j = 0; j < 8; j++) { - uint c = i; - for (int j = 0; j < 8; j++) + if ((c & 1) != 0) { - if ((c & 1) != 0) - { - c = c >> 1; - c ^= 0xEDB88320; - } - else - { - c = c >> 1; - } + c >>= 1; + c ^= 0xEDB88320; + } + else + { + c >>= 1; } - crcTab[i] = c; } + crcTab[i] = c; } } } diff --git a/src/SharpCompress/Compressors/Rar/RarCrcStream.cs b/src/SharpCompress/Compressors/Rar/RarCrcStream.cs index 120d8c3e..569799b8 100644 --- a/src/SharpCompress/Compressors/Rar/RarCrcStream.cs +++ b/src/SharpCompress/Compressors/Rar/RarCrcStream.cs @@ -1,47 +1,46 @@ using SharpCompress.Common; using SharpCompress.Common.Rar.Headers; -namespace SharpCompress.Compressors.Rar +namespace SharpCompress.Compressors.Rar; + +internal class RarCrcStream : RarStream { - internal class RarCrcStream : RarStream + private readonly MultiVolumeReadOnlyStream readStream; + private uint currentCrc; + + public RarCrcStream( + IRarUnpack unpack, + FileHeader fileHeader, + MultiVolumeReadOnlyStream readStream + ) : base(unpack, fileHeader, readStream) { - private readonly MultiVolumeReadOnlyStream readStream; - private uint currentCrc; + this.readStream = readStream; + ResetCrc(); + } - public RarCrcStream( - IRarUnpack unpack, - FileHeader fileHeader, - MultiVolumeReadOnlyStream readStream - ) : base(unpack, fileHeader, readStream) + public uint GetCrc() + { + return ~currentCrc; + } + + public void ResetCrc() + { + currentCrc = 0xffffffff; + } + + public override int Read(byte[] buffer, int offset, int count) + { + var result = base.Read(buffer, offset, count); + if (result != 0) { - this.readStream = readStream; - ResetCrc(); + currentCrc = RarCRC.CheckCrc(currentCrc, buffer, offset, result); + } + else if (GetCrc() != readStream.CurrentCrc && count != 0) + { + // NOTE: we use the last FileHeader in a multipart volume to check CRC + throw new InvalidFormatException("file crc mismatch"); } - public uint GetCrc() - { - return ~currentCrc; - } - - public void ResetCrc() - { - currentCrc = 0xffffffff; - } - - public override int Read(byte[] buffer, int offset, int count) - { - var result = base.Read(buffer, offset, count); - if (result != 0) - { - currentCrc = RarCRC.CheckCrc(currentCrc, buffer, offset, result); - } - else if (GetCrc() != readStream.CurrentCrc && count != 0) - { - // NOTE: we use the last FileHeader in a multipart volume to check CRC - throw new InvalidFormatException("file crc mismatch"); - } - - return result; - } + return result; } } diff --git a/src/SharpCompress/Compressors/Rar/RarStream.cs b/src/SharpCompress/Compressors/Rar/RarStream.cs index 9c470fbd..7bbc1700 100644 --- a/src/SharpCompress/Compressors/Rar/RarStream.cs +++ b/src/SharpCompress/Compressors/Rar/RarStream.cs @@ -4,138 +4,137 @@ using System; using System.IO; using SharpCompress.Common.Rar.Headers; -namespace SharpCompress.Compressors.Rar +namespace SharpCompress.Compressors.Rar; + +internal class RarStream : Stream { - internal class RarStream : Stream + private readonly IRarUnpack unpack; + private readonly FileHeader fileHeader; + private readonly Stream readStream; + + private bool fetch; + + private byte[] tmpBuffer = new byte[65536]; + private int tmpOffset; + private int tmpCount; + + private byte[] outBuffer; + private int outOffset; + private int outCount; + private int outTotal; + private bool isDisposed; + private long _position; + + public RarStream(IRarUnpack unpack, FileHeader fileHeader, Stream readStream) { - private readonly IRarUnpack unpack; - private readonly FileHeader fileHeader; - private readonly Stream readStream; + this.unpack = unpack; + this.fileHeader = fileHeader; + this.readStream = readStream; + fetch = true; + unpack.DoUnpack(fileHeader, readStream, this); + fetch = false; + _position = 0; + } - private bool fetch; - - private byte[] tmpBuffer = new byte[65536]; - private int tmpOffset; - private int tmpCount; - - private byte[] outBuffer; - private int outOffset; - private int outCount; - private int outTotal; - private bool isDisposed; - private long _position; - - public RarStream(IRarUnpack unpack, FileHeader fileHeader, Stream readStream) + protected override void Dispose(bool disposing) + { + if (!isDisposed) { - this.unpack = unpack; - this.fileHeader = fileHeader; - this.readStream = readStream; + isDisposed = true; + base.Dispose(disposing); + readStream.Dispose(); + } + } + + public override bool CanRead => true; + + public override bool CanSeek => false; + + public override bool CanWrite => false; + + public override void Flush() { } + + public override long Length => fileHeader.UncompressedSize; + + //commented out code always returned the length of the file + public override long Position + { + get => _position; /* fileHeader.UncompressedSize - unpack.DestSize;*/ + set => throw new NotSupportedException(); + } + + public override int Read(byte[] buffer, int offset, int count) + { + outTotal = 0; + if (tmpCount > 0) + { + var toCopy = tmpCount < count ? tmpCount : count; + Buffer.BlockCopy(tmpBuffer, tmpOffset, buffer, offset, toCopy); + tmpOffset += toCopy; + tmpCount -= toCopy; + offset += toCopy; + count -= toCopy; + outTotal += toCopy; + } + if (count > 0 && unpack.DestSize > 0) + { + outBuffer = buffer; + outOffset = offset; + outCount = count; fetch = true; - unpack.DoUnpack(fileHeader, readStream, this); + unpack.DoUnpack(); fetch = false; - _position = 0; } + _position += outTotal; + return outTotal; + } - protected override void Dispose(bool disposing) - { - if (!isDisposed) - { - isDisposed = true; - base.Dispose(disposing); - readStream.Dispose(); - } - } + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } - public override bool CanRead => true; + public override void SetLength(long value) + { + throw new NotSupportedException(); + } - public override bool CanSeek => false; - - public override bool CanWrite => false; - - public override void Flush() { } - - public override long Length => fileHeader.UncompressedSize; - - //commented out code always returned the length of the file - public override long Position - { - get => _position; /* fileHeader.UncompressedSize - unpack.DestSize;*/ - set => throw new NotSupportedException(); - } - - public override int Read(byte[] buffer, int offset, int count) - { - outTotal = 0; - if (tmpCount > 0) - { - int toCopy = tmpCount < count ? tmpCount : count; - Buffer.BlockCopy(tmpBuffer, tmpOffset, buffer, offset, toCopy); - tmpOffset += toCopy; - tmpCount -= toCopy; - offset += toCopy; - count -= toCopy; - outTotal += toCopy; - } - if (count > 0 && unpack.DestSize > 0) - { - outBuffer = buffer; - outOffset = offset; - outCount = count; - fetch = true; - unpack.DoUnpack(); - fetch = false; - } - _position += (long)outTotal; - return outTotal; - } - - public override long Seek(long offset, SeekOrigin origin) + public override void Write(byte[] buffer, int offset, int count) + { + if (!fetch) { throw new NotSupportedException(); } - - public override void SetLength(long value) + if (outCount > 0) { - throw new NotSupportedException(); + var toCopy = outCount < count ? outCount : count; + Buffer.BlockCopy(buffer, offset, outBuffer, outOffset, toCopy); + outOffset += toCopy; + outCount -= toCopy; + offset += toCopy; + count -= toCopy; + outTotal += toCopy; } - - public override void Write(byte[] buffer, int offset, int count) + if (count > 0) { - if (!fetch) + if (tmpBuffer.Length < tmpCount + count) { - throw new NotSupportedException(); - } - if (outCount > 0) - { - int toCopy = outCount < count ? outCount : count; - Buffer.BlockCopy(buffer, offset, outBuffer, outOffset, toCopy); - outOffset += toCopy; - outCount -= toCopy; - offset += toCopy; - count -= toCopy; - outTotal += toCopy; - } - if (count > 0) - { - if (tmpBuffer.Length < tmpCount + count) - { - byte[] newBuffer = new byte[ - tmpBuffer.Length * 2 > tmpCount + count - ? tmpBuffer.Length * 2 - : tmpCount + count - ]; - Buffer.BlockCopy(tmpBuffer, 0, newBuffer, 0, tmpCount); - tmpBuffer = newBuffer; - } - Buffer.BlockCopy(buffer, offset, tmpBuffer, tmpCount, count); - tmpCount += count; - tmpOffset = 0; - unpack.Suspended = true; - } - else - { - unpack.Suspended = false; + var newBuffer = new byte[ + tmpBuffer.Length * 2 > tmpCount + count + ? tmpBuffer.Length * 2 + : tmpCount + count + ]; + Buffer.BlockCopy(tmpBuffer, 0, newBuffer, 0, tmpCount); + tmpBuffer = newBuffer; } + Buffer.BlockCopy(buffer, offset, tmpBuffer, tmpCount, count); + tmpCount += count; + tmpOffset = 0; + unpack.Suspended = true; + } + else + { + unpack.Suspended = false; } } } diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/AudioVariables.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/AudioVariables.cs index 3e7319f3..d53d777f 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/AudioVariables.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/AudioVariables.cs @@ -1,26 +1,25 @@ -namespace SharpCompress.Compressors.Rar.UnpackV1.Decode +namespace SharpCompress.Compressors.Rar.UnpackV1.Decode; + +internal class AudioVariables { - internal class AudioVariables + internal AudioVariables() { - internal AudioVariables() - { - Dif = new int[11]; - } - - internal int[] Dif { get; } - internal int ByteCount { get; set; } - internal int D1 { get; set; } - - internal int D2 { get; set; } - internal int D3 { get; set; } - internal int D4 { get; set; } - - internal int K1 { get; set; } - internal int K2 { get; set; } - internal int K3 { get; set; } - internal int K4 { get; set; } - internal int K5 { get; set; } - internal int LastChar { get; set; } - internal int LastDelta { get; set; } + Dif = new int[11]; } + + internal int[] Dif { get; } + internal int ByteCount { get; set; } + internal int D1 { get; set; } + + internal int D2 { get; set; } + internal int D3 { get; set; } + internal int D4 { get; set; } + + internal int K1 { get; set; } + internal int K2 { get; set; } + internal int K3 { get; set; } + internal int K4 { get; set; } + internal int K5 { get; set; } + internal int LastChar { get; set; } + internal int LastDelta { get; set; } } diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/BitDecode.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/BitDecode.cs index aa8ff4dd..d61ce17a 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/BitDecode.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/BitDecode.cs @@ -1,7 +1,6 @@ -namespace SharpCompress.Compressors.Rar.UnpackV1.Decode +namespace SharpCompress.Compressors.Rar.UnpackV1.Decode; + +internal class BitDecode : Decode { - internal class BitDecode : Decode - { - internal BitDecode() : base(new int[PackDef.BC]) { } - } + internal BitDecode() : base(new int[PackDef.BC]) { } } diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/CodeType.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/CodeType.cs index a0f31371..0ec7943d 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/CodeType.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/CodeType.cs @@ -1,15 +1,14 @@ -namespace SharpCompress.Compressors.Rar.UnpackV1.Decode +namespace SharpCompress.Compressors.Rar.UnpackV1.Decode; + +internal enum CodeType { - internal enum CodeType - { - CODE_HUFFMAN, - CODE_LZ, - CODE_LZ2, - CODE_REPEATLZ, - CODE_CACHELZ, - CODE_STARTFILE, - CODE_ENDFILE, - CODE_VM, - CODE_VMDATA - } + CODE_HUFFMAN, + CODE_LZ, + CODE_LZ2, + CODE_REPEATLZ, + CODE_CACHELZ, + CODE_STARTFILE, + CODE_ENDFILE, + CODE_VM, + CODE_VMDATA } diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/Decode.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/Decode.cs index 7634dc7e..44ce0333 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/Decode.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/Decode.cs @@ -1,31 +1,30 @@ -namespace SharpCompress.Compressors.Rar.UnpackV1.Decode +namespace SharpCompress.Compressors.Rar.UnpackV1.Decode; + +internal class Decode { - internal class Decode + internal Decode() : this(new int[2]) { } + + protected Decode(int[] customDecodeNum) { - internal Decode() : this(new int[2]) { } - - protected Decode(int[] customDecodeNum) - { - DecodeLen = new int[16]; - DecodePos = new int[16]; - DecodeNum = customDecodeNum; - } - - /// returns the decode Length array - /// decodeLength - /// - internal int[] DecodeLen { get; } - - /// returns the decode num array - /// decodeNum - /// - internal int[] DecodeNum { get; } - - /// returns the decodePos array - /// decodePos - /// - internal int[] DecodePos { get; } - - internal int MaxNum { get; set; } + DecodeLen = new int[16]; + DecodePos = new int[16]; + DecodeNum = customDecodeNum; } + + /// returns the decode Length array + /// decodeLength + /// + internal int[] DecodeLen { get; } + + /// returns the decode num array + /// decodeNum + /// + internal int[] DecodeNum { get; } + + /// returns the decodePos array + /// decodePos + /// + internal int[] DecodePos { get; } + + internal int MaxNum { get; set; } } diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/DistDecode.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/DistDecode.cs index 9b49acc3..7b3c29b5 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/DistDecode.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/DistDecode.cs @@ -1,7 +1,6 @@ -namespace SharpCompress.Compressors.Rar.UnpackV1.Decode +namespace SharpCompress.Compressors.Rar.UnpackV1.Decode; + +internal class DistDecode : Decode { - internal class DistDecode : Decode - { - internal DistDecode() : base(new int[PackDef.DC]) { } - } + internal DistDecode() : base(new int[PackDef.DC]) { } } diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/FilterType.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/FilterType.cs index 1a6360dc..67e38c45 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/FilterType.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/FilterType.cs @@ -1,17 +1,16 @@ -namespace SharpCompress.Compressors.Rar.UnpackV1.Decode +namespace SharpCompress.Compressors.Rar.UnpackV1.Decode; + +internal enum FilterType : byte { - internal enum FilterType : byte - { - // These values must not be changed, because we use them directly - // in RAR5 compression and decompression code. - FILTER_DELTA = 0, - FILTER_E8, - FILTER_E8E9, - FILTER_ARM, - FILTER_AUDIO, - FILTER_RGB, - FILTER_ITANIUM, - FILTER_PPM, - FILTER_NONE - } + // These values must not be changed, because we use them directly + // in RAR5 compression and decompression code. + FILTER_DELTA = 0, + FILTER_E8, + FILTER_E8E9, + FILTER_ARM, + FILTER_AUDIO, + FILTER_RGB, + FILTER_ITANIUM, + FILTER_PPM, + FILTER_NONE } diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/LitDecode.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/LitDecode.cs index 035e7ce4..b45eaf8d 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/LitDecode.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/LitDecode.cs @@ -1,7 +1,6 @@ -namespace SharpCompress.Compressors.Rar.UnpackV1.Decode +namespace SharpCompress.Compressors.Rar.UnpackV1.Decode; + +internal class LitDecode : Decode { - internal class LitDecode : Decode - { - internal LitDecode() : base(new int[PackDef.NC]) { } - } + internal LitDecode() : base(new int[PackDef.NC]) { } } diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/LowDistDecode.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/LowDistDecode.cs index d3f358e8..c438a3af 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/LowDistDecode.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/LowDistDecode.cs @@ -1,7 +1,6 @@ -namespace SharpCompress.Compressors.Rar.UnpackV1.Decode +namespace SharpCompress.Compressors.Rar.UnpackV1.Decode; + +internal class LowDistDecode : Decode { - internal class LowDistDecode : Decode - { - internal LowDistDecode() : base(new int[PackDef.LDC]) { } - } + internal LowDistDecode() : base(new int[PackDef.LDC]) { } } diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/MultDecode.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/MultDecode.cs index 6342ac1f..6ef48ceb 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/MultDecode.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/MultDecode.cs @@ -1,7 +1,6 @@ -namespace SharpCompress.Compressors.Rar.UnpackV1.Decode +namespace SharpCompress.Compressors.Rar.UnpackV1.Decode; + +internal class MultDecode : Decode { - internal class MultDecode : Decode - { - internal MultDecode() : base(new int[PackDef.MC20]) { } - } + internal MultDecode() : base(new int[PackDef.MC20]) { } } diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/PackDef.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/PackDef.cs index 00ee5bb6..bed8d3d0 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/PackDef.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/PackDef.cs @@ -1,49 +1,48 @@ -namespace SharpCompress.Compressors.Rar.UnpackV1.Decode +namespace SharpCompress.Compressors.Rar.UnpackV1.Decode; + +internal static class PackDef { - internal static class PackDef - { - // 20171217 NOTE: these contants are gone from unrar src code - // seems to be more dynamic - public const int MAXWINSIZE = 0x400000; - public const int MAXWINMASK = MAXWINSIZE - 1; + // 20171217 NOTE: these contants are gone from unrar src code + // seems to be more dynamic + public const int MAXWINSIZE = 0x400000; + public const int MAXWINMASK = MAXWINSIZE - 1; - public const uint MAX_LZ_MATCH = 0x1001; - public const uint MAX3_LZ_MATCH = 0x101; // Maximum match length for RAR v3. - public const int LOW_DIST_REP_COUNT = 16; + public const uint MAX_LZ_MATCH = 0x1001; + public const uint MAX3_LZ_MATCH = 0x101; // Maximum match length for RAR v3. + public const int LOW_DIST_REP_COUNT = 16; - public const int NC = 299; /* alphabet = {0, 1, 2, ..., NC - 1} */ - public const int DC = 60; - public const int LDC = 17; - public const int RC = 28; + public const int NC = 299; /* alphabet = {0, 1, 2, ..., NC - 1} */ + public const int DC = 60; + public const int LDC = 17; + public const int RC = 28; - // 20171217: NOTE: these constants seem to have been updated in the unrar src code - // at some unknown point. updating causes decompression failure, not sure why. - // public const int NC = 306; /* alphabet = {0, 1, 2, ..., NC - 1} */ - // public const int DC = 64; - // public const int LDC = 16; - // public const int RC = 44; - public const int HUFF_TABLE_SIZE = NC + DC + RC + LDC; - public const int BC = 20; + // 20171217: NOTE: these constants seem to have been updated in the unrar src code + // at some unknown point. updating causes decompression failure, not sure why. + // public const int NC = 306; /* alphabet = {0, 1, 2, ..., NC - 1} */ + // public const int DC = 64; + // public const int LDC = 16; + // public const int RC = 44; + public const int HUFF_TABLE_SIZE = NC + DC + RC + LDC; + public const int BC = 20; - public const uint NC30 = 299; /* alphabet = {0, 1, 2, ..., NC - 1} */ - public const uint DC30 = 60; - public const uint LDC30 = 17; - public const uint RC30 = 28; - public const uint BC30 = 20; - public const uint HUFF_TABLE_SIZE30 = NC30 + DC30 + RC30 + LDC30; + public const uint NC30 = 299; /* alphabet = {0, 1, 2, ..., NC - 1} */ + public const uint DC30 = 60; + public const uint LDC30 = 17; + public const uint RC30 = 28; + public const uint BC30 = 20; + public const uint HUFF_TABLE_SIZE30 = NC30 + DC30 + RC30 + LDC30; - public const int NC20 = 298; /* alphabet = {0, 1, 2, ..., NC - 1} */ - public const int DC20 = 48; - public const int RC20 = 28; - public const int BC20 = 19; - public const int MC20 = 257; + public const int NC20 = 298; /* alphabet = {0, 1, 2, ..., NC - 1} */ + public const int DC20 = 48; + public const int RC20 = 28; + public const int BC20 = 19; + public const int MC20 = 257; - // Largest alphabet size among all values listed above. - public const uint LARGEST_TABLE_SIZE = 306; + // Largest alphabet size among all values listed above. + public const uint LARGEST_TABLE_SIZE = 306; - //public enum { - // CODE_HUFFMAN, CODE_LZ, CODE_REPEATLZ, CODE_CACHELZ, CODE_STARTFILE, - // CODE_ENDFILE, CODE_FILTER, CODE_FILTERDATA - //} - } + //public enum { + // CODE_HUFFMAN, CODE_LZ, CODE_REPEATLZ, CODE_CACHELZ, CODE_STARTFILE, + // CODE_ENDFILE, CODE_FILTER, CODE_FILTERDATA + //} } diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/RepDecode.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/RepDecode.cs index 648630e1..d13914b3 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/RepDecode.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/RepDecode.cs @@ -1,7 +1,6 @@ -namespace SharpCompress.Compressors.Rar.UnpackV1.Decode +namespace SharpCompress.Compressors.Rar.UnpackV1.Decode; + +internal class RepDecode : Decode { - internal class RepDecode : Decode - { - internal RepDecode() : base(new int[PackDef.RC]) { } - } + internal RepDecode() : base(new int[PackDef.RC]) { } } diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/PPM/BlockTypes.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/PPM/BlockTypes.cs index c25fae4e..3b4a9372 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/PPM/BlockTypes.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/PPM/BlockTypes.cs @@ -1,8 +1,7 @@ -namespace SharpCompress.Compressors.Rar.UnpackV1.PPM +namespace SharpCompress.Compressors.Rar.UnpackV1.PPM; + +internal enum BlockTypes { - internal enum BlockTypes - { - BLOCK_LZ = 0, - BLOCK_PPM = 1 - } + BLOCK_LZ = 0, + BLOCK_PPM = 1 } diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack.cs index 63dd4875..08ba47f2 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack.cs @@ -10,1328 +10,1324 @@ using SharpCompress.Compressors.Rar.UnpackV1.Decode; using SharpCompress.Compressors.Rar.UnpackV1.PPM; using SharpCompress.Compressors.Rar.VM; -namespace SharpCompress.Compressors.Rar.UnpackV1 +namespace SharpCompress.Compressors.Rar.UnpackV1; + +internal sealed partial class Unpack : BitInput, IRarUnpack { - internal sealed partial class Unpack : BitInput, IRarUnpack + private readonly BitInput Inp; + + public Unpack() { - private readonly BitInput Inp; + // to ease in porting Unpack50.cs + Inp = this; + } - public Unpack() + public bool FileExtracted { get; private set; } + + public long DestSize + { + get => destUnpSize; + set { - // to ease in porting Unpack50.cs - Inp = this; + destUnpSize = value; + FileExtracted = false; } + } - public bool FileExtracted { get; private set; } + public bool Suspended + { + get => suspended; + set => suspended = value; + } - public long DestSize + public int Char + { + get { - get => destUnpSize; - set + if (inAddr > MAX_SIZE - 30) { - destUnpSize = value; - FileExtracted = false; + unpReadBuf(); } + return (InBuf[inAddr++] & 0xff); } + } - public bool Suspended + public int PpmEscChar { get; set; } + + private readonly ModelPpm ppm = new ModelPpm(); + + private readonly RarVM rarVM = new RarVM(); + + // Filters code, one entry per filter + private readonly List filters = new List(); + + // Filters stack, several entrances of same filter are possible + private readonly List prgStack = new List(); + + // lengths of preceding blocks, one length per filter. Used to reduce size + // required to write block length if lengths are repeating + private readonly List oldFilterLengths = new List(); + + private int lastFilter; + + private bool tablesRead; + + private readonly byte[] unpOldTable = new byte[PackDef.HUFF_TABLE_SIZE]; + + private BlockTypes unpBlockType; + + //private bool externalWindow; + + private long writtenFileSize; + + private bool ppmError; + + private int prevLowDist; + + private int lowDistRepCount; + + private static readonly int[] DBitLengthCounts = + { + 4, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 14, + 0, + 12 + }; + + private FileHeader fileHeader; + + private void Init(byte[] window) + { + if (window is null) { - get => suspended; - set => suspended = value; + this.window = new byte[PackDef.MAXWINSIZE]; } - - public int Char + else { - get + this.window = window; + + //externalWindow = true; + } + inAddr = 0; + UnpInitData(false); + } + + public void DoUnpack(FileHeader fileHeader, Stream readStream, Stream writeStream) + { + destUnpSize = fileHeader.UncompressedSize; + this.fileHeader = fileHeader; + this.readStream = readStream; + this.writeStream = writeStream; + if (!fileHeader.IsSolid) + { + Init(null); + } + suspended = false; + DoUnpack(); + } + + public void DoUnpack() + { + if (fileHeader.CompressionMethod == 0) + { + UnstoreFile(); + return; + } + switch (fileHeader.CompressionAlgorithm) + { + case 15: // rar 1.5 compression + unpack15(fileHeader.IsSolid); + break; + + case 20: // rar 2.x compression + case 26: // files larger than 2GB + unpack20(fileHeader.IsSolid); + break; + + case 29: // rar 3.x compression + case 36: // alternative hash + Unpack29(fileHeader.IsSolid); + break; + + case 50: // rar 5.x compression + Unpack5(fileHeader.IsSolid); + break; + + default: + throw new InvalidFormatException( + "unknown rar compression version " + fileHeader.CompressionAlgorithm + ); + } + } + + private void UnstoreFile() + { + var buffer = new byte[0x10000]; + while (true) + { + var code = readStream.Read(buffer, 0, (int)Math.Min(buffer.Length, destUnpSize)); + if (code == 0 || code == -1) { - if (inAddr > MAX_SIZE - 30) - { - unpReadBuf(); - } - return (InBuf[inAddr++] & 0xff); + break; } - } - - public int PpmEscChar { get; set; } - - private readonly ModelPpm ppm = new ModelPpm(); - - private readonly RarVM rarVM = new RarVM(); - - // Filters code, one entry per filter - private readonly List filters = new List(); - - // Filters stack, several entrances of same filter are possible - private readonly List prgStack = new List(); - - // lengths of preceding blocks, one length per filter. Used to reduce size - // required to write block length if lengths are repeating - private readonly List oldFilterLengths = new List(); - - private int lastFilter; - - private bool tablesRead; - - private readonly byte[] unpOldTable = new byte[PackDef.HUFF_TABLE_SIZE]; - - private BlockTypes unpBlockType; - - //private bool externalWindow; - - private long writtenFileSize; - - private bool ppmError; - - private int prevLowDist; - - private int lowDistRepCount; - - private static readonly int[] DBitLengthCounts = - { - 4, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 14, - 0, - 12 - }; - - private FileHeader fileHeader; - - private void Init(byte[] window) - { - if (window is null) + code = code < destUnpSize ? code : (int)destUnpSize; + writeStream.Write(buffer, 0, code); + if (destUnpSize >= 0) { - this.window = new byte[PackDef.MAXWINSIZE]; + destUnpSize -= code; } - else + if (suspended) { - this.window = window; - - //externalWindow = true; - } - inAddr = 0; - UnpInitData(false); - } - - public void DoUnpack(FileHeader fileHeader, Stream readStream, Stream writeStream) - { - destUnpSize = fileHeader.UncompressedSize; - this.fileHeader = fileHeader; - this.readStream = readStream; - this.writeStream = writeStream; - if (!fileHeader.IsSolid) - { - Init(null); - } - suspended = false; - DoUnpack(); - } - - public void DoUnpack() - { - if (fileHeader.CompressionMethod == 0) - { - UnstoreFile(); return; } - switch (fileHeader.CompressionAlgorithm) + } + } + + private void Unpack29(bool solid) + { + var DDecode = new int[PackDef.DC]; + var DBits = new byte[PackDef.DC]; + + int Bits; + + if (DDecode[1] == 0) + { + int Dist = 0, + BitLength = 0, + Slot = 0; + for (var I = 0; I < DBitLengthCounts.Length; I++, BitLength++) { - case 15: // rar 1.5 compression - unpack15(fileHeader.IsSolid); - break; - - case 20: // rar 2.x compression - case 26: // files larger than 2GB - unpack20(fileHeader.IsSolid); - break; - - case 29: // rar 3.x compression - case 36: // alternative hash - Unpack29(fileHeader.IsSolid); - break; - - case 50: // rar 5.x compression - Unpack5(fileHeader.IsSolid); - break; - - default: - throw new InvalidFormatException( - "unknown rar compression version " + fileHeader.CompressionAlgorithm - ); + var count = DBitLengthCounts[I]; + for (var J = 0; J < count; J++, Slot++, Dist += (1 << BitLength)) + { + DDecode[Slot] = Dist; + DBits[Slot] = (byte)BitLength; + } } } - private void UnstoreFile() + FileExtracted = true; + + if (!suspended) { - byte[] buffer = new byte[0x10000]; - while (true) + UnpInitData(solid); + if (!unpReadBuf()) { - int code = readStream.Read(buffer, 0, (int)Math.Min(buffer.Length, destUnpSize)); - if (code == 0 || code == -1) + return; + } + if ((!solid || !tablesRead) && !ReadTables()) + { + return; + } + } + + if (ppmError) + { + return; + } + + while (true) + { + unpPtr &= PackDef.MAXWINMASK; + + if (inAddr > readBorder) + { + if (!unpReadBuf()) { break; } - code = code < destUnpSize ? code : (int)destUnpSize; - writeStream.Write(buffer, 0, code); - if (destUnpSize >= 0) + } + + // System.out.println(((wrPtr - unpPtr) & + // Compress.MAXWINMASK)+":"+wrPtr+":"+unpPtr); + if (((wrPtr - unpPtr) & PackDef.MAXWINMASK) < 260 && wrPtr != unpPtr) + { + UnpWriteBuf(); + if (destUnpSize <= 0) { - destUnpSize -= code; + return; } if (suspended) { + FileExtracted = false; return; } } - } - - private void Unpack29(bool solid) - { - int[] DDecode = new int[PackDef.DC]; - byte[] DBits = new byte[PackDef.DC]; - - int Bits; - - if (DDecode[1] == 0) + if (unpBlockType == BlockTypes.BLOCK_PPM) { - int Dist = 0, - BitLength = 0, - Slot = 0; - for (int I = 0; I < DBitLengthCounts.Length; I++, BitLength++) + var Ch = ppm.DecodeChar(); + if (Ch == -1) { - int count = DBitLengthCounts[I]; - for (int J = 0; J < count; J++, Slot++, Dist += (1 << BitLength)) - { - DDecode[Slot] = Dist; - DBits[Slot] = (byte)BitLength; - } + ppmError = true; + break; } - } - - FileExtracted = true; - - if (!suspended) - { - UnpInitData(solid); - if (!unpReadBuf()) + if (Ch == PpmEscChar) { - return; - } - if ((!solid || !tablesRead) && !ReadTables()) - { - return; - } - } - - if (ppmError) - { - return; - } - - while (true) - { - unpPtr &= PackDef.MAXWINMASK; - - if (inAddr > readBorder) - { - if (!unpReadBuf()) + var NextCh = ppm.DecodeChar(); + if (NextCh == 0) { - break; - } - } - - // System.out.println(((wrPtr - unpPtr) & - // Compress.MAXWINMASK)+":"+wrPtr+":"+unpPtr); - if (((wrPtr - unpPtr) & PackDef.MAXWINMASK) < 260 && wrPtr != unpPtr) - { - UnpWriteBuf(); - if (destUnpSize <= 0) - { - return; - } - if (suspended) - { - FileExtracted = false; - return; - } - } - if (unpBlockType == BlockTypes.BLOCK_PPM) - { - int Ch = ppm.DecodeChar(); - if (Ch == -1) - { - ppmError = true; - break; - } - if (Ch == PpmEscChar) - { - int NextCh = ppm.DecodeChar(); - if (NextCh == 0) - { - if (!ReadTables()) - { - break; - } - continue; - } - if (NextCh == 2 || NextCh == -1) + if (!ReadTables()) { break; } - if (NextCh == 3) + continue; + } + if (NextCh == 2 || NextCh == -1) + { + break; + } + if (NextCh == 3) + { + if (!ReadVMCodePPM()) { - if (!ReadVMCodePPM()) - { - break; - } - continue; + break; } - if (NextCh == 4) + continue; + } + if (NextCh == 4) + { + int Distance = 0, + Length = 0; + var failed = false; + for (var I = 0; I < 4 && !failed; I++) { - int Distance = 0, - Length = 0; - bool failed = false; - for (int I = 0; I < 4 && !failed; I++) + var ch = ppm.DecodeChar(); + if (ch == -1) { - int ch = ppm.DecodeChar(); - if (ch == -1) + failed = true; + } + else + { + if (I == 3) { - failed = true; + // Bug fixed + Length = ch & 0xff; } else { - if (I == 3) - { - // Bug fixed - Length = ch & 0xff; - } - else - { - // Bug fixed - Distance = (Distance << 8) + (ch & 0xff); - } + // Bug fixed + Distance = (Distance << 8) + (ch & 0xff); } } - if (failed) - { - break; - } - CopyString(Length + 32, Distance + 2); - continue; } - if (NextCh == 5) + if (failed) { - int Length = ppm.DecodeChar(); - if (Length == -1) - { - break; - } - CopyString(Length + 4, 1); - continue; + break; } + CopyString(Length + 32, Distance + 2); + continue; } - window[unpPtr++] = (byte)Ch; - continue; + if (NextCh == 5) + { + var Length = ppm.DecodeChar(); + if (Length == -1) + { + break; + } + CopyString(Length + 4, 1); + continue; + } + } + window[unpPtr++] = (byte)Ch; + continue; + } + + var Number = this.decodeNumber(LD); + if (Number < 256) + { + window[unpPtr++] = (byte)Number; + continue; + } + if (Number >= 271) + { + var Length = LDecode[Number -= 271] + 3; + if ((Bits = LBits[Number]) > 0) + { + Length += Utility.URShift(GetBits(), (16 - Bits)); + AddBits(Bits); } - int Number = this.decodeNumber(LD); - if (Number < 256) + var DistNumber = this.decodeNumber(DD); + var Distance = DDecode[DistNumber] + 1; + if ((Bits = DBits[DistNumber]) > 0) { - window[unpPtr++] = (byte)Number; - continue; - } - if (Number >= 271) - { - int Length = LDecode[Number -= 271] + 3; - if ((Bits = LBits[Number]) > 0) + if (DistNumber > 9) { - Length += Utility.URShift(GetBits(), (16 - Bits)); - AddBits(Bits); - } - - int DistNumber = this.decodeNumber(DD); - int Distance = DDecode[DistNumber] + 1; - if ((Bits = DBits[DistNumber]) > 0) - { - if (DistNumber > 9) + if (Bits > 4) { - if (Bits > 4) + Distance += ((Utility.URShift(GetBits(), (20 - Bits))) << 4); + AddBits(Bits - 4); + } + if (lowDistRepCount > 0) + { + lowDistRepCount--; + Distance += prevLowDist; + } + else + { + var LowDist = this.decodeNumber(LDD); + if (LowDist == 16) { - Distance += ((Utility.URShift(GetBits(), (20 - Bits))) << 4); - AddBits(Bits - 4); - } - if (lowDistRepCount > 0) - { - lowDistRepCount--; + lowDistRepCount = PackDef.LOW_DIST_REP_COUNT - 1; Distance += prevLowDist; } else { - int LowDist = this.decodeNumber(LDD); - if (LowDist == 16) - { - lowDistRepCount = PackDef.LOW_DIST_REP_COUNT - 1; - Distance += prevLowDist; - } - else - { - Distance += LowDist; - prevLowDist = LowDist; - } + Distance += LowDist; + prevLowDist = LowDist; } } - else - { - Distance += Utility.URShift(GetBits(), (16 - Bits)); - AddBits(Bits); - } } - - if (Distance >= 0x2000) - { - Length++; - if (Distance >= 0x40000L) - { - Length++; - } - } - - InsertOldDist(Distance); - InsertLastMatch(Length, Distance); - - CopyString(Length, Distance); - continue; - } - if (Number == 256) - { - if (!ReadEndOfBlock()) - { - break; - } - continue; - } - if (Number == 257) - { - if (!ReadVMCode()) - { - break; - } - continue; - } - if (Number == 258) - { - if (lastLength != 0) - { - CopyString(lastLength, lastDist); - } - continue; - } - if (Number < 263) - { - int DistNum = Number - 259; - int Distance = oldDist[DistNum]; - for (int I = DistNum; I > 0; I--) - { - oldDist[I] = oldDist[I - 1]; - } - oldDist[0] = Distance; - - int LengthNumber = this.decodeNumber(RD); - int Length = LDecode[LengthNumber] + 2; - if ((Bits = LBits[LengthNumber]) > 0) - { - Length += Utility.URShift(GetBits(), (16 - Bits)); - AddBits(Bits); - } - InsertLastMatch(Length, Distance); - CopyString(Length, Distance); - continue; - } - if (Number < 272) - { - int Distance = SDDecode[Number -= 263] + 1; - if ((Bits = SDBits[Number]) > 0) + else { Distance += Utility.URShift(GetBits(), (16 - Bits)); AddBits(Bits); } - InsertOldDist(Distance); - InsertLastMatch(2, Distance); - CopyString(2, Distance); } - } - UnpWriteBuf(); - } - private void UnpWriteBuf() - { - int WrittenBorder = wrPtr; - int WriteSize = (unpPtr - WrittenBorder) & PackDef.MAXWINMASK; - for (int I = 0; I < prgStack.Count; I++) - { - UnpackFilter flt = prgStack[I]; - if (flt is null) + if (Distance >= 0x2000) { - continue; - } - if (flt.NextWindow) - { - flt.NextWindow = false; // ->NextWindow=false; - continue; - } - int BlockStart = flt.BlockStart; // ->BlockStart; - int BlockLength = flt.BlockLength; // ->BlockLength; - if (((BlockStart - WrittenBorder) & PackDef.MAXWINMASK) < WriteSize) - { - if (WrittenBorder != BlockStart) + Length++; + if (Distance >= 0x40000L) { - UnpWriteArea(WrittenBorder, BlockStart); - WrittenBorder = BlockStart; - WriteSize = (unpPtr - WrittenBorder) & PackDef.MAXWINMASK; + Length++; } - if (BlockLength <= WriteSize) + } + + InsertOldDist(Distance); + InsertLastMatch(Length, Distance); + + CopyString(Length, Distance); + continue; + } + if (Number == 256) + { + if (!ReadEndOfBlock()) + { + break; + } + continue; + } + if (Number == 257) + { + if (!ReadVMCode()) + { + break; + } + continue; + } + if (Number == 258) + { + if (lastLength != 0) + { + CopyString(lastLength, lastDist); + } + continue; + } + if (Number < 263) + { + var DistNum = Number - 259; + var Distance = oldDist[DistNum]; + for (var I = DistNum; I > 0; I--) + { + oldDist[I] = oldDist[I - 1]; + } + oldDist[0] = Distance; + + var LengthNumber = this.decodeNumber(RD); + var Length = LDecode[LengthNumber] + 2; + if ((Bits = LBits[LengthNumber]) > 0) + { + Length += Utility.URShift(GetBits(), (16 - Bits)); + AddBits(Bits); + } + InsertLastMatch(Length, Distance); + CopyString(Length, Distance); + continue; + } + if (Number < 272) + { + var Distance = SDDecode[Number -= 263] + 1; + if ((Bits = SDBits[Number]) > 0) + { + Distance += Utility.URShift(GetBits(), (16 - Bits)); + AddBits(Bits); + } + InsertOldDist(Distance); + InsertLastMatch(2, Distance); + CopyString(2, Distance); + } + } + UnpWriteBuf(); + } + + private void UnpWriteBuf() + { + var WrittenBorder = wrPtr; + var WriteSize = (unpPtr - WrittenBorder) & PackDef.MAXWINMASK; + for (var I = 0; I < prgStack.Count; I++) + { + var flt = prgStack[I]; + if (flt is null) + { + continue; + } + if (flt.NextWindow) + { + flt.NextWindow = false; // ->NextWindow=false; + continue; + } + var BlockStart = flt.BlockStart; // ->BlockStart; + var BlockLength = flt.BlockLength; // ->BlockLength; + if (((BlockStart - WrittenBorder) & PackDef.MAXWINMASK) < WriteSize) + { + if (WrittenBorder != BlockStart) + { + UnpWriteArea(WrittenBorder, BlockStart); + WrittenBorder = BlockStart; + WriteSize = (unpPtr - WrittenBorder) & PackDef.MAXWINMASK; + } + if (BlockLength <= WriteSize) + { + var BlockEnd = (BlockStart + BlockLength) & PackDef.MAXWINMASK; + if (BlockStart < BlockEnd || BlockEnd == 0) { - int BlockEnd = (BlockStart + BlockLength) & PackDef.MAXWINMASK; - if (BlockStart < BlockEnd || BlockEnd == 0) - { - // VM.SetMemory(0,Window+BlockStart,BlockLength); - rarVM.setMemory(0, window, BlockStart, BlockLength); - } - else - { - int FirstPartLength = PackDef.MAXWINSIZE - BlockStart; - - // VM.SetMemory(0,Window+BlockStart,FirstPartLength); - rarVM.setMemory(0, window, BlockStart, FirstPartLength); - - // VM.SetMemory(FirstPartLength,Window,BlockEnd); - rarVM.setMemory(FirstPartLength, window, 0, BlockEnd); - } - - VMPreparedProgram ParentPrg = filters[flt.ParentFilter].Program; - VMPreparedProgram Prg = flt.Program; - - if (ParentPrg.GlobalData.Count > RarVM.VM_FIXEDGLOBALSIZE) - { - // copy global data from previous script execution if - // any - // Prg->GlobalData.Alloc(ParentPrg->GlobalData.Size()); - // memcpy(&Prg->GlobalData[VM_FIXEDGLOBALSIZE],&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],ParentPrg->GlobalData.Size()-VM_FIXEDGLOBALSIZE); - Prg.GlobalData.Clear(); - for ( - int i = 0; - i < ParentPrg.GlobalData.Count - RarVM.VM_FIXEDGLOBALSIZE; - i++ - ) - { - Prg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i] = ParentPrg.GlobalData[ - RarVM.VM_FIXEDGLOBALSIZE + i - ]; - } - } - - ExecuteCode(Prg); - - if (Prg.GlobalData.Count > RarVM.VM_FIXEDGLOBALSIZE) - { - // save global data for next script execution - if (ParentPrg.GlobalData.Count < Prg.GlobalData.Count) - { - //ParentPrg.GlobalData.Clear(); // ->GlobalData.Alloc(Prg->GlobalData.Size()); - ParentPrg.GlobalData.SetSize(Prg.GlobalData.Count); - } - - // memcpy(&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],&Prg->GlobalData[VM_FIXEDGLOBALSIZE],Prg->GlobalData.Size()-VM_FIXEDGLOBALSIZE); - for ( - int i = 0; - i < Prg.GlobalData.Count - RarVM.VM_FIXEDGLOBALSIZE; - i++ - ) - { - ParentPrg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i] = Prg.GlobalData[ - RarVM.VM_FIXEDGLOBALSIZE + i - ]; - } - } - else - { - ParentPrg.GlobalData.Clear(); - } - - int FilteredDataOffset = Prg.FilteredDataOffset; - int FilteredDataSize = Prg.FilteredDataSize; - byte[] FilteredData = new byte[FilteredDataSize]; - - for (int i = 0; i < FilteredDataSize; i++) - { - FilteredData[i] = rarVM.Mem[FilteredDataOffset + i]; - - // Prg.GlobalData.get(FilteredDataOffset - // + - // i); - } - - prgStack[I] = null; - while (I + 1 < prgStack.Count) - { - UnpackFilter NextFilter = prgStack[I + 1]; - if ( - NextFilter is null - || NextFilter.BlockStart != BlockStart - || NextFilter.BlockLength != FilteredDataSize - || NextFilter.NextWindow - ) - { - break; - } - - // apply several filters to same data block - - rarVM.setMemory(0, FilteredData, 0, FilteredDataSize); - - // .SetMemory(0,FilteredData,FilteredDataSize); - - VMPreparedProgram pPrg = filters[NextFilter.ParentFilter].Program; - VMPreparedProgram NextPrg = NextFilter.Program; - - if (pPrg.GlobalData.Count > RarVM.VM_FIXEDGLOBALSIZE) - { - // copy global data from previous script execution - // if any - // NextPrg->GlobalData.Alloc(ParentPrg->GlobalData.Size()); - NextPrg.GlobalData.SetSize(pPrg.GlobalData.Count); - - // memcpy(&NextPrg->GlobalData[VM_FIXEDGLOBALSIZE],&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],ParentPrg->GlobalData.Size()-VM_FIXEDGLOBALSIZE); - for ( - int i = 0; - i < pPrg.GlobalData.Count - RarVM.VM_FIXEDGLOBALSIZE; - i++ - ) - { - NextPrg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i] = - pPrg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i]; - } - } - - ExecuteCode(NextPrg); - - if (NextPrg.GlobalData.Count > RarVM.VM_FIXEDGLOBALSIZE) - { - // save global data for next script execution - if (pPrg.GlobalData.Count < NextPrg.GlobalData.Count) - { - pPrg.GlobalData.SetSize(NextPrg.GlobalData.Count); - } - - // memcpy(&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],&NextPrg->GlobalData[VM_FIXEDGLOBALSIZE],NextPrg->GlobalData.Size()-VM_FIXEDGLOBALSIZE); - for ( - int i = 0; - i < NextPrg.GlobalData.Count - RarVM.VM_FIXEDGLOBALSIZE; - i++ - ) - { - pPrg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i] = - NextPrg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i]; - } - } - else - { - pPrg.GlobalData.Clear(); - } - FilteredDataOffset = NextPrg.FilteredDataOffset; - FilteredDataSize = NextPrg.FilteredDataSize; - - FilteredData = new byte[FilteredDataSize]; - for (int i = 0; i < FilteredDataSize; i++) - { - FilteredData[i] = NextPrg.GlobalData[FilteredDataOffset + i]; - } - - I++; - prgStack[I] = null; - } - writeStream.Write(FilteredData, 0, FilteredDataSize); - unpSomeRead = true; - writtenFileSize += FilteredDataSize; - destUnpSize -= FilteredDataSize; - WrittenBorder = BlockEnd; - WriteSize = (unpPtr - WrittenBorder) & PackDef.MAXWINMASK; + // VM.SetMemory(0,Window+BlockStart,BlockLength); + rarVM.setMemory(0, window, BlockStart, BlockLength); } else { - for (int J = I; J < prgStack.Count; J++) + var FirstPartLength = PackDef.MAXWINSIZE - BlockStart; + + // VM.SetMemory(0,Window+BlockStart,FirstPartLength); + rarVM.setMemory(0, window, BlockStart, FirstPartLength); + + // VM.SetMemory(FirstPartLength,Window,BlockEnd); + rarVM.setMemory(FirstPartLength, window, 0, BlockEnd); + } + + var ParentPrg = filters[flt.ParentFilter].Program; + var Prg = flt.Program; + + if (ParentPrg.GlobalData.Count > RarVM.VM_FIXEDGLOBALSIZE) + { + // copy global data from previous script execution if + // any + // Prg->GlobalData.Alloc(ParentPrg->GlobalData.Size()); + // memcpy(&Prg->GlobalData[VM_FIXEDGLOBALSIZE],&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],ParentPrg->GlobalData.Size()-VM_FIXEDGLOBALSIZE); + Prg.GlobalData.Clear(); + for ( + var i = 0; + i < ParentPrg.GlobalData.Count - RarVM.VM_FIXEDGLOBALSIZE; + i++ + ) { - UnpackFilter filt = prgStack[J]; - if (filt != null && filt.NextWindow) + Prg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i] = ParentPrg.GlobalData[ + RarVM.VM_FIXEDGLOBALSIZE + i + ]; + } + } + + ExecuteCode(Prg); + + if (Prg.GlobalData.Count > RarVM.VM_FIXEDGLOBALSIZE) + { + // save global data for next script execution + if (ParentPrg.GlobalData.Count < Prg.GlobalData.Count) + { + //ParentPrg.GlobalData.Clear(); // ->GlobalData.Alloc(Prg->GlobalData.Size()); + ParentPrg.GlobalData.SetSize(Prg.GlobalData.Count); + } + + // memcpy(&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],&Prg->GlobalData[VM_FIXEDGLOBALSIZE],Prg->GlobalData.Size()-VM_FIXEDGLOBALSIZE); + for ( + var i = 0; + i < Prg.GlobalData.Count - RarVM.VM_FIXEDGLOBALSIZE; + i++ + ) + { + ParentPrg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i] = Prg.GlobalData[ + RarVM.VM_FIXEDGLOBALSIZE + i + ]; + } + } + else + { + ParentPrg.GlobalData.Clear(); + } + + var FilteredDataOffset = Prg.FilteredDataOffset; + var FilteredDataSize = Prg.FilteredDataSize; + var FilteredData = new byte[FilteredDataSize]; + + for (var i = 0; i < FilteredDataSize; i++) + { + FilteredData[i] = rarVM.Mem[FilteredDataOffset + i]; + + // Prg.GlobalData.get(FilteredDataOffset + // + + // i); + } + + prgStack[I] = null; + while (I + 1 < prgStack.Count) + { + var NextFilter = prgStack[I + 1]; + if ( + NextFilter is null + || NextFilter.BlockStart != BlockStart + || NextFilter.BlockLength != FilteredDataSize + || NextFilter.NextWindow + ) + { + break; + } + + // apply several filters to same data block + + rarVM.setMemory(0, FilteredData, 0, FilteredDataSize); + + // .SetMemory(0,FilteredData,FilteredDataSize); + + var pPrg = filters[NextFilter.ParentFilter].Program; + var NextPrg = NextFilter.Program; + + if (pPrg.GlobalData.Count > RarVM.VM_FIXEDGLOBALSIZE) + { + // copy global data from previous script execution + // if any + // NextPrg->GlobalData.Alloc(ParentPrg->GlobalData.Size()); + NextPrg.GlobalData.SetSize(pPrg.GlobalData.Count); + + // memcpy(&NextPrg->GlobalData[VM_FIXEDGLOBALSIZE],&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],ParentPrg->GlobalData.Size()-VM_FIXEDGLOBALSIZE); + for ( + var i = 0; + i < pPrg.GlobalData.Count - RarVM.VM_FIXEDGLOBALSIZE; + i++ + ) { - filt.NextWindow = false; + NextPrg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i] = + pPrg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i]; } } - wrPtr = WrittenBorder; - return; + + ExecuteCode(NextPrg); + + if (NextPrg.GlobalData.Count > RarVM.VM_FIXEDGLOBALSIZE) + { + // save global data for next script execution + if (pPrg.GlobalData.Count < NextPrg.GlobalData.Count) + { + pPrg.GlobalData.SetSize(NextPrg.GlobalData.Count); + } + + // memcpy(&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],&NextPrg->GlobalData[VM_FIXEDGLOBALSIZE],NextPrg->GlobalData.Size()-VM_FIXEDGLOBALSIZE); + for ( + var i = 0; + i < NextPrg.GlobalData.Count - RarVM.VM_FIXEDGLOBALSIZE; + i++ + ) + { + pPrg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i] = + NextPrg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i]; + } + } + else + { + pPrg.GlobalData.Clear(); + } + FilteredDataOffset = NextPrg.FilteredDataOffset; + FilteredDataSize = NextPrg.FilteredDataSize; + + FilteredData = new byte[FilteredDataSize]; + for (var i = 0; i < FilteredDataSize; i++) + { + FilteredData[i] = NextPrg.GlobalData[FilteredDataOffset + i]; + } + + I++; + prgStack[I] = null; } + writeStream.Write(FilteredData, 0, FilteredDataSize); + unpSomeRead = true; + writtenFileSize += FilteredDataSize; + destUnpSize -= FilteredDataSize; + WrittenBorder = BlockEnd; + WriteSize = (unpPtr - WrittenBorder) & PackDef.MAXWINMASK; + } + else + { + for (var J = I; J < prgStack.Count; J++) + { + var filt = prgStack[J]; + if (filt != null && filt.NextWindow) + { + filt.NextWindow = false; + } + } + wrPtr = WrittenBorder; + return; } } - - UnpWriteArea(WrittenBorder, unpPtr); - wrPtr = unpPtr; } - private void UnpWriteArea(int startPtr, int endPtr) + UnpWriteArea(WrittenBorder, unpPtr); + wrPtr = unpPtr; + } + + private void UnpWriteArea(int startPtr, int endPtr) + { + if (endPtr != startPtr) { - if (endPtr != startPtr) - { - unpSomeRead = true; - } - if (endPtr < startPtr) - { - UnpWriteData(window, startPtr, -startPtr & PackDef.MAXWINMASK); - UnpWriteData(window, 0, endPtr); - unpAllBuf = true; - } - else - { - UnpWriteData(window, startPtr, endPtr - startPtr); - } + unpSomeRead = true; } - - private void UnpWriteData(byte[] data, int offset, int size) + if (endPtr < startPtr) { - if (destUnpSize <= 0) - { - return; - } - int writeSize = size; - if (writeSize > destUnpSize) - { - writeSize = (int)destUnpSize; - } - writeStream.Write(data, offset, writeSize); - - writtenFileSize += size; - destUnpSize -= size; + UnpWriteData(window, startPtr, -startPtr & PackDef.MAXWINMASK); + UnpWriteData(window, 0, endPtr); + unpAllBuf = true; } - - private void InsertOldDist(uint distance) + else { - // TODO uint - InsertOldDist((int)distance); + UnpWriteData(window, startPtr, endPtr - startPtr); } + } - private void InsertOldDist(int distance) + private void UnpWriteData(byte[] data, int offset, int size) + { + if (destUnpSize <= 0) { - oldDist[3] = oldDist[2]; - oldDist[2] = oldDist[1]; - oldDist[1] = oldDist[0]; - oldDist[0] = distance; + return; } - - private void InsertLastMatch(int length, int distance) + var writeSize = size; + if (writeSize > destUnpSize) { - lastDist = distance; - lastLength = length; + writeSize = (int)destUnpSize; } + writeStream.Write(data, offset, writeSize); - private void CopyString(uint length, uint distance) + writtenFileSize += size; + destUnpSize -= size; + } + + private void InsertOldDist(uint distance) + { + // TODO uint + InsertOldDist((int)distance); + } + + private void InsertOldDist(int distance) + { + oldDist[3] = oldDist[2]; + oldDist[2] = oldDist[1]; + oldDist[1] = oldDist[0]; + oldDist[0] = distance; + } + + private void InsertLastMatch(int length, int distance) + { + lastDist = distance; + lastLength = length; + } + + private void CopyString(uint length, uint distance) + { + // TODO uint + CopyString((int)length, (int)distance); + } + + private void CopyString(int length, int distance) + { + // System.out.println("copyString(" + length + ", " + distance + ")"); + + var destPtr = unpPtr - distance; + + // System.out.println(unpPtr+":"+distance); + if ( + destPtr >= 0 + && destPtr < PackDef.MAXWINSIZE - 260 + && unpPtr < PackDef.MAXWINSIZE - 260 + ) { - // TODO uint - CopyString((int)length, (int)distance); - } + window[unpPtr++] = window[destPtr++]; - private void CopyString(int length, int distance) - { - // System.out.println("copyString(" + length + ", " + distance + ")"); - - int destPtr = unpPtr - distance; - - // System.out.println(unpPtr+":"+distance); - if ( - destPtr >= 0 - && destPtr < PackDef.MAXWINSIZE - 260 - && unpPtr < PackDef.MAXWINSIZE - 260 - ) + while (--length > 0) { window[unpPtr++] = window[destPtr++]; + } + } + else + { + while (length-- != 0) + { + window[unpPtr] = window[destPtr++ & PackDef.MAXWINMASK]; + unpPtr = (unpPtr + 1) & PackDef.MAXWINMASK; + } + } + } - while (--length > 0) + private void UnpInitData(bool solid) + { + if (!solid) + { + tablesRead = false; + new Span(oldDist).Clear(); // memset(oldDist,0,sizeof(OldDist)); + + oldDistPtr = 0; + lastDist = 0; + lastLength = 0; + + new Span(unpOldTable).Clear(); // memset(UnpOldTable,0,sizeof(UnpOldTable)); + + unpPtr = 0; + wrPtr = 0; + PpmEscChar = 2; + WriteBorder = Math.Min(MaxWinSize, UNPACK_MAX_WRITE) & MaxWinMask; + + InitFilters(); + } + InitBitInput(); + ppmError = false; + writtenFileSize = 0; + readTop = 0; + readBorder = 0; + unpInitData20(solid); + } + + //void Unpack::UnpInitData(bool Solid) + //{ + // if (!Solid) + // { + // memset(OldDist,0,sizeof(OldDist)); + // OldDistPtr=0; + // LastDist=LastLength=0; + //// memset(Window,0,MaxWinSize); + // memset(&BlockTables,0,sizeof(BlockTables)); + // UnpPtr=WrPtr=0; + // WriteBorder=Min(MaxWinSize,UNPACK_MAX_WRITE)&MaxWinMask; + // } + // // Filters never share several solid files, so we can safely reset them + // // even in solid archive. + // InitFilters(); + // + // Inp.InitBitInput(); + // WrittenFileSize=0; + // ReadTop=0; + // ReadBorder=0; + // + // memset(&BlockHeader,0,sizeof(BlockHeader)); + // BlockHeader.BlockSize=-1; // '-1' means not defined yet. + //#ifndef SFX_MODULE + // UnpInitData20(Solid); + //#endif + // UnpInitData30(Solid); + // UnpInitData50(Solid); + //} + + private void InitFilters() + { + oldFilterLengths.Clear(); + lastFilter = 0; + + filters.Clear(); + + prgStack.Clear(); + } + + private bool ReadEndOfBlock() + { + var BitField = GetBits(); + bool NewTable, + NewFile = false; + if ((BitField & 0x8000) != 0) + { + NewTable = true; + AddBits(1); + } + else + { + NewFile = true; + NewTable = (BitField & 0x4000) != 0; + AddBits(2); + } + tablesRead = !NewTable; + return !(NewFile || NewTable && !ReadTables()); + } + + private bool ReadTables() + { + var bitLength = new byte[PackDef.BC]; + + var table = new byte[PackDef.HUFF_TABLE_SIZE]; + if (inAddr > readTop - 25) + { + if (!unpReadBuf()) + { + return (false); + } + } + AddBits((8 - inBit) & 7); + long bitField = GetBits() & unchecked((int)0xffFFffFF); + if ((bitField & 0x8000) != 0) + { + unpBlockType = BlockTypes.BLOCK_PPM; + return (ppm.DecodeInit(this, PpmEscChar)); + } + unpBlockType = BlockTypes.BLOCK_LZ; + + prevLowDist = 0; + lowDistRepCount = 0; + + if ((bitField & 0x4000) == 0) + { + new Span(unpOldTable).Clear(); // memset(UnpOldTable,0,sizeof(UnpOldTable)); + } + AddBits(2); + + for (var i = 0; i < PackDef.BC; i++) + { + var length = (Utility.URShift(GetBits(), 12)) & 0xFF; + AddBits(4); + if (length == 15) + { + var zeroCount = (Utility.URShift(GetBits(), 12)) & 0xFF; + AddBits(4); + if (zeroCount == 0) { - window[unpPtr++] = window[destPtr++]; + bitLength[i] = 15; + } + else + { + zeroCount += 2; + while (zeroCount-- > 0 && i < bitLength.Length) + { + bitLength[i++] = 0; + } + i--; } } else { - while (length-- != 0) - { - window[unpPtr] = window[destPtr++ & PackDef.MAXWINMASK]; - unpPtr = (unpPtr + 1) & PackDef.MAXWINMASK; - } + bitLength[i] = (byte)length; } } - private void UnpInitData(bool solid) + UnpackUtility.makeDecodeTables(bitLength, 0, BD, PackDef.BC); + + var TableSize = PackDef.HUFF_TABLE_SIZE; + + for (var i = 0; i < TableSize;) { - if (!solid) - { - tablesRead = false; - new Span(oldDist).Clear(); // memset(oldDist,0,sizeof(OldDist)); - - oldDistPtr = 0; - lastDist = 0; - lastLength = 0; - - new Span(unpOldTable).Clear(); // memset(UnpOldTable,0,sizeof(UnpOldTable)); - - unpPtr = 0; - wrPtr = 0; - PpmEscChar = 2; - WriteBorder = Math.Min(MaxWinSize, UNPACK_MAX_WRITE) & MaxWinMask; - - InitFilters(); - } - InitBitInput(); - ppmError = false; - writtenFileSize = 0; - readTop = 0; - readBorder = 0; - unpInitData20(solid); - } - - //void Unpack::UnpInitData(bool Solid) - //{ - // if (!Solid) - // { - // memset(OldDist,0,sizeof(OldDist)); - // OldDistPtr=0; - // LastDist=LastLength=0; - //// memset(Window,0,MaxWinSize); - // memset(&BlockTables,0,sizeof(BlockTables)); - // UnpPtr=WrPtr=0; - // WriteBorder=Min(MaxWinSize,UNPACK_MAX_WRITE)&MaxWinMask; - // } - // // Filters never share several solid files, so we can safely reset them - // // even in solid archive. - // InitFilters(); - // - // Inp.InitBitInput(); - // WrittenFileSize=0; - // ReadTop=0; - // ReadBorder=0; - // - // memset(&BlockHeader,0,sizeof(BlockHeader)); - // BlockHeader.BlockSize=-1; // '-1' means not defined yet. - //#ifndef SFX_MODULE - // UnpInitData20(Solid); - //#endif - // UnpInitData30(Solid); - // UnpInitData50(Solid); - //} - - private void InitFilters() - { - oldFilterLengths.Clear(); - lastFilter = 0; - - filters.Clear(); - - prgStack.Clear(); - } - - private bool ReadEndOfBlock() - { - int BitField = GetBits(); - bool NewTable, - NewFile = false; - if ((BitField & 0x8000) != 0) - { - NewTable = true; - AddBits(1); - } - else - { - NewFile = true; - NewTable = (BitField & 0x4000) != 0; - AddBits(2); - } - tablesRead = !NewTable; - return !(NewFile || NewTable && !ReadTables()); - } - - private bool ReadTables() - { - byte[] bitLength = new byte[PackDef.BC]; - - byte[] table = new byte[PackDef.HUFF_TABLE_SIZE]; - if (inAddr > readTop - 25) + if (inAddr > readTop - 5) { if (!unpReadBuf()) { return (false); } } - AddBits((8 - inBit) & 7); - long bitField = GetBits() & unchecked((int)0xffFFffFF); - if ((bitField & 0x8000) != 0) + var Number = this.decodeNumber(BD); + if (Number < 16) { - unpBlockType = BlockTypes.BLOCK_PPM; - return (ppm.DecodeInit(this, PpmEscChar)); + table[i] = (byte)((Number + unpOldTable[i]) & 0xf); + i++; } - unpBlockType = BlockTypes.BLOCK_LZ; - - prevLowDist = 0; - lowDistRepCount = 0; - - if ((bitField & 0x4000) == 0) + else if (Number < 18) { - new Span(unpOldTable).Clear(); // memset(UnpOldTable,0,sizeof(UnpOldTable)); - } - AddBits(2); - - for (int i = 0; i < PackDef.BC; i++) - { - int length = (Utility.URShift(GetBits(), 12)) & 0xFF; - AddBits(4); - if (length == 15) + int N; + if (Number == 16) { - int zeroCount = (Utility.URShift(GetBits(), 12)) & 0xFF; - AddBits(4); - if (zeroCount == 0) - { - bitLength[i] = 15; - } - else - { - zeroCount += 2; - while (zeroCount-- > 0 && i < bitLength.Length) - { - bitLength[i++] = 0; - } - i--; - } + N = (Utility.URShift(GetBits(), 13)) + 3; + AddBits(3); } else { - bitLength[i] = (byte)length; + N = (Utility.URShift(GetBits(), 9)) + 11; + AddBits(7); } - } - - UnpackUtility.makeDecodeTables(bitLength, 0, BD, PackDef.BC); - - int TableSize = PackDef.HUFF_TABLE_SIZE; - - for (int i = 0; i < TableSize; ) - { - if (inAddr > readTop - 5) + while (N-- > 0 && i < TableSize) { - if (!unpReadBuf()) - { - return (false); - } - } - int Number = this.decodeNumber(BD); - if (Number < 16) - { - table[i] = (byte)((Number + unpOldTable[i]) & 0xf); + table[i] = table[i - 1]; i++; } - else if (Number < 18) + } + else + { + int N; + if (Number == 18) { - int N; - if (Number == 16) - { - N = (Utility.URShift(GetBits(), 13)) + 3; - AddBits(3); - } - else - { - N = (Utility.URShift(GetBits(), 9)) + 11; - AddBits(7); - } - while (N-- > 0 && i < TableSize) - { - table[i] = table[i - 1]; - i++; - } + N = (Utility.URShift(GetBits(), 13)) + 3; + AddBits(3); } else { - int N; - if (Number == 18) - { - N = (Utility.URShift(GetBits(), 13)) + 3; - AddBits(3); - } - else - { - N = (Utility.URShift(GetBits(), 9)) + 11; - AddBits(7); - } - while (N-- > 0 && i < TableSize) - { - table[i++] = 0; - } + N = (Utility.URShift(GetBits(), 9)) + 11; + AddBits(7); + } + while (N-- > 0 && i < TableSize) + { + table[i++] = 0; } } - tablesRead = true; - if (inAddr > readTop) - { - return (false); - } - UnpackUtility.makeDecodeTables(table, 0, LD, PackDef.NC); - UnpackUtility.makeDecodeTables(table, PackDef.NC, DD, PackDef.DC); - UnpackUtility.makeDecodeTables(table, PackDef.NC + PackDef.DC, LDD, PackDef.LDC); - UnpackUtility.makeDecodeTables( - table, - PackDef.NC + PackDef.DC + PackDef.LDC, - RD, - PackDef.RC - ); - - // memcpy(unpOldTable,table,sizeof(unpOldTable)); - - Buffer.BlockCopy(table, 0, unpOldTable, 0, unpOldTable.Length); - return (true); } - - private bool ReadVMCode() + tablesRead = true; + if (inAddr > readTop) { - int FirstByte = GetBits() >> 8; + return (false); + } + UnpackUtility.makeDecodeTables(table, 0, LD, PackDef.NC); + UnpackUtility.makeDecodeTables(table, PackDef.NC, DD, PackDef.DC); + UnpackUtility.makeDecodeTables(table, PackDef.NC + PackDef.DC, LDD, PackDef.LDC); + UnpackUtility.makeDecodeTables( + table, + PackDef.NC + PackDef.DC + PackDef.LDC, + RD, + PackDef.RC + ); + + // memcpy(unpOldTable,table,sizeof(unpOldTable)); + + Buffer.BlockCopy(table, 0, unpOldTable, 0, unpOldTable.Length); + return (true); + } + + private bool ReadVMCode() + { + var FirstByte = GetBits() >> 8; + AddBits(8); + var Length = (FirstByte & 7) + 1; + if (Length == 7) + { + Length = (GetBits() >> 8) + 7; AddBits(8); - int Length = (FirstByte & 7) + 1; - if (Length == 7) - { - Length = (GetBits() >> 8) + 7; - AddBits(8); - } - else if (Length == 8) - { - Length = GetBits(); - AddBits(16); - } - - List vmCode = new List(); - for (int I = 0; I < Length; I++) - { - if (inAddr >= readTop - 1 && !unpReadBuf() && I < Length - 1) - { - return (false); - } - vmCode.Add((byte)(GetBits() >> 8)); - AddBits(8); - } - return (AddVMCode(FirstByte, vmCode, Length)); + } + else if (Length == 8) + { + Length = GetBits(); + AddBits(16); } - private bool ReadVMCodePPM() + var vmCode = new List(); + for (var I = 0; I < Length; I++) { - int FirstByte = ppm.DecodeChar(); - if (FirstByte == -1) + if (inAddr >= readTop - 1 && !unpReadBuf() && I < Length - 1) { return (false); } - int Length = (FirstByte & 7) + 1; - if (Length == 7) - { - int B1 = ppm.DecodeChar(); - if (B1 == -1) - { - return (false); - } - Length = B1 + 7; - } - else if (Length == 8) - { - int B1 = ppm.DecodeChar(); - if (B1 == -1) - { - return (false); - } - int B2 = ppm.DecodeChar(); - if (B2 == -1) - { - return (false); - } - Length = B1 * 256 + B2; - } - - List vmCode = new List(); - for (int I = 0; I < Length; I++) - { - int Ch = ppm.DecodeChar(); - if (Ch == -1) - { - return (false); - } - vmCode.Add((byte)Ch); // VMCode[I]=Ch; - } - return (AddVMCode(FirstByte, vmCode, Length)); + vmCode.Add((byte)(GetBits() >> 8)); + AddBits(8); } + return (AddVMCode(FirstByte, vmCode, Length)); + } - private bool AddVMCode(int firstByte, List vmCode, int length) + private bool ReadVMCodePPM() + { + var FirstByte = ppm.DecodeChar(); + if (FirstByte == -1) { - BitInput Inp = new BitInput(); - Inp.InitBitInput(); - - // memcpy(Inp.InBuf,Code,Min(BitInput::MAX_SIZE,CodeSize)); - for (int i = 0; i < Math.Min(MAX_SIZE, vmCode.Count); i++) - { - Inp.InBuf[i] = vmCode[i]; - } - rarVM.init(); - - int FiltPos; - if ((firstByte & 0x80) != 0) - { - FiltPos = RarVM.ReadData(Inp); - if (FiltPos == 0) - { - InitFilters(); - } - else - { - FiltPos--; - } - } - else - { - FiltPos = lastFilter; // use the same filter as last time - } - - if (FiltPos > filters.Count || FiltPos > oldFilterLengths.Count) + return (false); + } + var Length = (FirstByte & 7) + 1; + if (Length == 7) + { + var B1 = ppm.DecodeChar(); + if (B1 == -1) { return (false); } - lastFilter = FiltPos; - bool NewFilter = (FiltPos == filters.Count); - - UnpackFilter StackFilter = new UnpackFilter(); // new filter for - - // PrgStack - - UnpackFilter Filter; - if (NewFilter) - // new filter code, never used before since VM reset + Length = B1 + 7; + } + else if (Length == 8) + { + var B1 = ppm.DecodeChar(); + if (B1 == -1) { - // too many different filters, corrupt archive - if (FiltPos > 1024) - { - return (false); - } - - // Filters[Filters.Size()-1]=Filter=new UnpackFilter; - Filter = new UnpackFilter(); - filters.Add(Filter); - StackFilter.ParentFilter = filters.Count - 1; - oldFilterLengths.Add(0); - Filter.ExecCount = 0; + return (false); } - // filter was used in the past - else + var B2 = ppm.DecodeChar(); + if (B2 == -1) { - Filter = filters[FiltPos]; - StackFilter.ParentFilter = FiltPos; - Filter.ExecCount = Filter.ExecCount + 1; // ->ExecCount++; + return (false); } + Length = (B1 * 256) + B2; + } - prgStack.Add(StackFilter); - StackFilter.ExecCount = Filter.ExecCount; // ->ExecCount; - - int BlockStart = RarVM.ReadData(Inp); - if ((firstByte & 0x40) != 0) + var vmCode = new List(); + for (var I = 0; I < Length; I++) + { + var Ch = ppm.DecodeChar(); + if (Ch == -1) { - BlockStart += 258; + return (false); } - StackFilter.BlockStart = ((BlockStart + unpPtr) & PackDef.MAXWINMASK); - if ((firstByte & 0x20) != 0) + vmCode.Add((byte)Ch); // VMCode[I]=Ch; + } + return (AddVMCode(FirstByte, vmCode, Length)); + } + + private bool AddVMCode(int firstByte, List vmCode, int length) + { + var Inp = new BitInput(); + Inp.InitBitInput(); + + // memcpy(Inp.InBuf,Code,Min(BitInput::MAX_SIZE,CodeSize)); + for (var i = 0; i < Math.Min(MAX_SIZE, vmCode.Count); i++) + { + Inp.InBuf[i] = vmCode[i]; + } + rarVM.init(); + + int FiltPos; + if ((firstByte & 0x80) != 0) + { + FiltPos = RarVM.ReadData(Inp); + if (FiltPos == 0) { - StackFilter.BlockLength = RarVM.ReadData(Inp); + InitFilters(); } else { - StackFilter.BlockLength = - FiltPos < oldFilterLengths.Count ? oldFilterLengths[FiltPos] : 0; + FiltPos--; } - StackFilter.NextWindow = - (wrPtr != unpPtr) && ((wrPtr - unpPtr) & PackDef.MAXWINMASK) <= BlockStart; + } + else + { + FiltPos = lastFilter; // use the same filter as last time + } - // DebugLog("\nNextWindow: UnpPtr=%08x WrPtr=%08x - // BlockStart=%08x",UnpPtr,WrPtr,BlockStart); + if (FiltPos > filters.Count || FiltPos > oldFilterLengths.Count) + { + return (false); + } + lastFilter = FiltPos; + var NewFilter = (FiltPos == filters.Count); - oldFilterLengths[FiltPos] = StackFilter.BlockLength; + var StackFilter = new UnpackFilter(); // new filter for - // memset(StackFilter->Prg.InitR,0,sizeof(StackFilter->Prg.InitR)); - new Span(StackFilter.Program.InitR).Clear(); - StackFilter.Program.InitR[3] = RarVM.VM_GLOBALMEMADDR; // StackFilter->Prg.InitR[3]=VM_GLOBALMEMADDR; - StackFilter.Program.InitR[4] = StackFilter.BlockLength; + // PrgStack - // StackFilter->Prg.InitR[4]=StackFilter->BlockLength; - StackFilter.Program.InitR[5] = StackFilter.ExecCount; // StackFilter->Prg.InitR[5]=StackFilter->ExecCount; - - if ((firstByte & 0x10) != 0) - // set registers to optional parameters - // if any + UnpackFilter Filter; + if (NewFilter) + // new filter code, never used before since VM reset + { + // too many different filters, corrupt archive + if (FiltPos > 1024) { - int InitMask = Utility.URShift(Inp.GetBits(), 9); - Inp.AddBits(7); - for (int I = 0; I < 7; I++) + return (false); + } + + // Filters[Filters.Size()-1]=Filter=new UnpackFilter; + Filter = new UnpackFilter(); + filters.Add(Filter); + StackFilter.ParentFilter = filters.Count - 1; + oldFilterLengths.Add(0); + Filter.ExecCount = 0; + } + // filter was used in the past + else + { + Filter = filters[FiltPos]; + StackFilter.ParentFilter = FiltPos; + Filter.ExecCount++; // ->ExecCount++; + } + + prgStack.Add(StackFilter); + StackFilter.ExecCount = Filter.ExecCount; // ->ExecCount; + + var BlockStart = RarVM.ReadData(Inp); + if ((firstByte & 0x40) != 0) + { + BlockStart += 258; + } + StackFilter.BlockStart = ((BlockStart + unpPtr) & PackDef.MAXWINMASK); + if ((firstByte & 0x20) != 0) + { + StackFilter.BlockLength = RarVM.ReadData(Inp); + } + else + { + StackFilter.BlockLength = + FiltPos < oldFilterLengths.Count ? oldFilterLengths[FiltPos] : 0; + } + StackFilter.NextWindow = + (wrPtr != unpPtr) && ((wrPtr - unpPtr) & PackDef.MAXWINMASK) <= BlockStart; + + // DebugLog("\nNextWindow: UnpPtr=%08x WrPtr=%08x + // BlockStart=%08x",UnpPtr,WrPtr,BlockStart); + + oldFilterLengths[FiltPos] = StackFilter.BlockLength; + + // memset(StackFilter->Prg.InitR,0,sizeof(StackFilter->Prg.InitR)); + new Span(StackFilter.Program.InitR).Clear(); + StackFilter.Program.InitR[3] = RarVM.VM_GLOBALMEMADDR; // StackFilter->Prg.InitR[3]=VM_GLOBALMEMADDR; + StackFilter.Program.InitR[4] = StackFilter.BlockLength; + + // StackFilter->Prg.InitR[4]=StackFilter->BlockLength; + StackFilter.Program.InitR[5] = StackFilter.ExecCount; // StackFilter->Prg.InitR[5]=StackFilter->ExecCount; + + if ((firstByte & 0x10) != 0) + // set registers to optional parameters + // if any + { + var InitMask = Utility.URShift(Inp.GetBits(), 9); + Inp.AddBits(7); + for (var I = 0; I < 7; I++) + { + if ((InitMask & (1 << I)) != 0) { - if ((InitMask & (1 << I)) != 0) - { - // StackFilter->Prg.InitR[I]=RarVM::ReadData(Inp); - StackFilter.Program.InitR[I] = RarVM.ReadData(Inp); - } + // StackFilter->Prg.InitR[I]=RarVM::ReadData(Inp); + StackFilter.Program.InitR[I] = RarVM.ReadData(Inp); } } + } - if (NewFilter) + if (NewFilter) + { + var VMCodeSize = RarVM.ReadData(Inp); + if (VMCodeSize >= 0x10000 || VMCodeSize == 0) { - int VMCodeSize = RarVM.ReadData(Inp); - if (VMCodeSize >= 0x10000 || VMCodeSize == 0) - { - return (false); - } - byte[] VMCode = new byte[VMCodeSize]; - for (int I = 0; I < VMCodeSize; I++) - { - if (Inp.Overflow(3)) - { - return (false); - } - VMCode[I] = (byte)(Inp.GetBits() >> 8); - Inp.AddBits(8); - } - - // VM.Prepare(&VMCode[0],VMCodeSize,&Filter->Prg); - rarVM.prepare(VMCode, VMCodeSize, Filter.Program); + return (false); } - StackFilter.Program.AltCommands = Filter.Program.Commands; // StackFilter->Prg.AltCmd=&Filter->Prg.Cmd[0]; - StackFilter.Program.CommandCount = Filter.Program.CommandCount; - - // StackFilter->Prg.CmdCount=Filter->Prg.CmdCount; - - int StaticDataSize = Filter.Program.StaticData.Count; - if (StaticDataSize > 0 && StaticDataSize < RarVM.VM_GLOBALMEMSIZE) - { - // read statically defined data contained in DB commands - // StackFilter->Prg.StaticData.Add(StaticDataSize); - StackFilter.Program.StaticData = Filter.Program.StaticData; - - // memcpy(&StackFilter->Prg.StaticData[0],&Filter->Prg.StaticData[0],StaticDataSize); - } - - if (StackFilter.Program.GlobalData.Count < RarVM.VM_FIXEDGLOBALSIZE) - { - // StackFilter->Prg.GlobalData.Reset(); - // StackFilter->Prg.GlobalData.Add(VM_FIXEDGLOBALSIZE); - StackFilter.Program.GlobalData.Clear(); - StackFilter.Program.GlobalData.SetSize(RarVM.VM_FIXEDGLOBALSIZE); - } - - // byte *GlobalData=&StackFilter->Prg.GlobalData[0]; - - List globalData = StackFilter.Program.GlobalData; - for (int I = 0; I < 7; I++) - { - rarVM.SetLowEndianValue(globalData, I * 4, StackFilter.Program.InitR[I]); - } - - // VM.SetLowEndianValue((uint - // *)&GlobalData[0x1c],StackFilter->BlockLength); - rarVM.SetLowEndianValue(globalData, 0x1c, StackFilter.BlockLength); - - // VM.SetLowEndianValue((uint *)&GlobalData[0x20],0); - rarVM.SetLowEndianValue(globalData, 0x20, 0); - rarVM.SetLowEndianValue(globalData, 0x24, 0); - rarVM.SetLowEndianValue(globalData, 0x28, 0); - - // VM.SetLowEndianValue((uint - // *)&GlobalData[0x2c],StackFilter->ExecCount); - rarVM.SetLowEndianValue(globalData, 0x2c, StackFilter.ExecCount); - - // memset(&GlobalData[0x30],0,16); - for (int i = 0; i < 16; i++) - { - globalData[0x30 + i] = 0x0; - } - if ((firstByte & 8) != 0) - // put data block passed as parameter if any + var VMCode = new byte[VMCodeSize]; + for (var I = 0; I < VMCodeSize; I++) { if (Inp.Overflow(3)) { return (false); } - int DataSize = RarVM.ReadData(Inp); - if (DataSize > RarVM.VM_GLOBALMEMSIZE - RarVM.VM_FIXEDGLOBALSIZE) + VMCode[I] = (byte)(Inp.GetBits() >> 8); + Inp.AddBits(8); + } + + // VM.Prepare(&VMCode[0],VMCodeSize,&Filter->Prg); + rarVM.prepare(VMCode, VMCodeSize, Filter.Program); + } + StackFilter.Program.AltCommands = Filter.Program.Commands; // StackFilter->Prg.AltCmd=&Filter->Prg.Cmd[0]; + StackFilter.Program.CommandCount = Filter.Program.CommandCount; + + // StackFilter->Prg.CmdCount=Filter->Prg.CmdCount; + + var StaticDataSize = Filter.Program.StaticData.Count; + if (StaticDataSize > 0 && StaticDataSize < RarVM.VM_GLOBALMEMSIZE) + { + // read statically defined data contained in DB commands + // StackFilter->Prg.StaticData.Add(StaticDataSize); + StackFilter.Program.StaticData = Filter.Program.StaticData; + + // memcpy(&StackFilter->Prg.StaticData[0],&Filter->Prg.StaticData[0],StaticDataSize); + } + + if (StackFilter.Program.GlobalData.Count < RarVM.VM_FIXEDGLOBALSIZE) + { + // StackFilter->Prg.GlobalData.Reset(); + // StackFilter->Prg.GlobalData.Add(VM_FIXEDGLOBALSIZE); + StackFilter.Program.GlobalData.Clear(); + StackFilter.Program.GlobalData.SetSize(RarVM.VM_FIXEDGLOBALSIZE); + } + + // byte *GlobalData=&StackFilter->Prg.GlobalData[0]; + + var globalData = StackFilter.Program.GlobalData; + for (var I = 0; I < 7; I++) + { + rarVM.SetLowEndianValue(globalData, I * 4, StackFilter.Program.InitR[I]); + } + + // VM.SetLowEndianValue((uint + // *)&GlobalData[0x1c],StackFilter->BlockLength); + rarVM.SetLowEndianValue(globalData, 0x1c, StackFilter.BlockLength); + + // VM.SetLowEndianValue((uint *)&GlobalData[0x20],0); + rarVM.SetLowEndianValue(globalData, 0x20, 0); + rarVM.SetLowEndianValue(globalData, 0x24, 0); + rarVM.SetLowEndianValue(globalData, 0x28, 0); + + // VM.SetLowEndianValue((uint + // *)&GlobalData[0x2c],StackFilter->ExecCount); + rarVM.SetLowEndianValue(globalData, 0x2c, StackFilter.ExecCount); + + // memset(&GlobalData[0x30],0,16); + for (var i = 0; i < 16; i++) + { + globalData[0x30 + i] = 0x0; + } + if ((firstByte & 8) != 0) + // put data block passed as parameter if any + { + if (Inp.Overflow(3)) + { + return (false); + } + var DataSize = RarVM.ReadData(Inp); + if (DataSize > RarVM.VM_GLOBALMEMSIZE - RarVM.VM_FIXEDGLOBALSIZE) + { + return (false); + } + var CurSize = StackFilter.Program.GlobalData.Count; + if (CurSize < DataSize + RarVM.VM_FIXEDGLOBALSIZE) + { + // StackFilter->Prg.GlobalData.Add(DataSize+VM_FIXEDGLOBALSIZE-CurSize); + StackFilter.Program.GlobalData.SetSize( + DataSize + RarVM.VM_FIXEDGLOBALSIZE - CurSize + ); + } + var offset = RarVM.VM_FIXEDGLOBALSIZE; + globalData = StackFilter.Program.GlobalData; + for (var I = 0; I < DataSize; I++) + { + if (Inp.Overflow(3)) { return (false); } - int CurSize = StackFilter.Program.GlobalData.Count; - if (CurSize < DataSize + RarVM.VM_FIXEDGLOBALSIZE) - { - // StackFilter->Prg.GlobalData.Add(DataSize+VM_FIXEDGLOBALSIZE-CurSize); - StackFilter.Program.GlobalData.SetSize( - DataSize + RarVM.VM_FIXEDGLOBALSIZE - CurSize - ); - } - int offset = RarVM.VM_FIXEDGLOBALSIZE; - globalData = StackFilter.Program.GlobalData; - for (int I = 0; I < DataSize; I++) - { - if (Inp.Overflow(3)) - { - return (false); - } - globalData[offset + I] = (byte)(Utility.URShift(Inp.GetBits(), 8)); - Inp.AddBits(8); - } - } - return (true); - } - - private void ExecuteCode(VMPreparedProgram Prg) - { - if (Prg.GlobalData.Count > 0) - { - // Prg->InitR[6]=int64to32(WrittenFileSize); - Prg.InitR[6] = (int)(writtenFileSize); - - // rarVM.SetLowEndianValue((uint - // *)&Prg->GlobalData[0x24],int64to32(WrittenFileSize)); - rarVM.SetLowEndianValue(Prg.GlobalData, 0x24, (int)writtenFileSize); - - // rarVM.SetLowEndianValue((uint - // *)&Prg->GlobalData[0x28],int64to32(WrittenFileSize>>32)); - rarVM.SetLowEndianValue( - Prg.GlobalData, - 0x28, - (int)(Utility.URShift(writtenFileSize, 32)) - ); - rarVM.execute(Prg); + globalData[offset + I] = (byte)(Utility.URShift(Inp.GetBits(), 8)); + Inp.AddBits(8); } } + return (true); + } - private void CleanUp() + private void ExecuteCode(VMPreparedProgram Prg) + { + if (Prg.GlobalData.Count > 0) { - if (ppm != null) - { - SubAllocator allocator = ppm.SubAlloc; - if (allocator != null) - { - allocator.StopSubAllocator(); - } - } + // Prg->InitR[6]=int64to32(WrittenFileSize); + Prg.InitR[6] = (int)(writtenFileSize); + + // rarVM.SetLowEndianValue((uint + // *)&Prg->GlobalData[0x24],int64to32(WrittenFileSize)); + rarVM.SetLowEndianValue(Prg.GlobalData, 0x24, (int)writtenFileSize); + + // rarVM.SetLowEndianValue((uint + // *)&Prg->GlobalData[0x28],int64to32(WrittenFileSize>>32)); + rarVM.SetLowEndianValue( + Prg.GlobalData, + 0x28, + (int)(Utility.URShift(writtenFileSize, 32)) + ); + rarVM.execute(Prg); + } + } + + private void CleanUp() + { + if (ppm != null) + { + var allocator = ppm.SubAlloc; + allocator?.StopSubAllocator(); } } } diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack15.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack15.cs index d463a020..c0257809 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack15.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack15.cs @@ -11,487 +11,461 @@ using System; using System.IO; using SharpCompress.Compressors.Rar.UnpackV1.Decode; -namespace SharpCompress.Compressors.Rar.UnpackV1 +namespace SharpCompress.Compressors.Rar.UnpackV1; + +internal partial class Unpack { - internal partial class Unpack + private int readBorder; + + private bool suspended; + + internal bool unpAllBuf; + + //private ComprDataIO unpIO; + private Stream readStream; + private Stream writeStream; + + internal bool unpSomeRead; + + private int readTop; + + private long destUnpSize; + + private byte[] window; + + private readonly int[] oldDist = new int[4]; + + private int unpPtr, + wrPtr; + + private int oldDistPtr; + + private readonly int[] ChSet = new int[256], + ChSetA = new int[256], + ChSetB = new int[256], + ChSetC = new int[256]; + + private readonly int[] Place = new int[256], + PlaceA = new int[256], + PlaceB = new int[256], + PlaceC = new int[256]; + + private readonly int[] NToPl = new int[256], + NToPlB = new int[256], + NToPlC = new int[256]; + + private int FlagBuf, + AvrPlc, + AvrPlcB, + AvrLn1, + AvrLn2, + AvrLn3; + + private int Buf60, + NumHuf, + StMode, + LCount, + FlagsCnt; + + private int Nhfb, + Nlzb, + MaxDist3; + + private int lastDist, + lastLength; + + private const int STARTL1 = 2; + + private static readonly int[] DecL1 = { - private int readBorder; + 0x8000, + 0xa000, + 0xc000, + 0xd000, + 0xe000, + 0xea00, + 0xee00, + 0xf000, + 0xf200, + 0xf200, + 0xffff + }; - private bool suspended; + private static readonly int[] PosL1 = { 0, 0, 0, 2, 3, 5, 7, 11, 16, 20, 24, 32, 32 }; - internal bool unpAllBuf; + private const int STARTL2 = 3; - //private ComprDataIO unpIO; - private Stream readStream; - private Stream writeStream; + private static readonly int[] DecL2 = + { + 0xa000, + 0xc000, + 0xd000, + 0xe000, + 0xea00, + 0xee00, + 0xf000, + 0xf200, + 0xf240, + 0xffff + }; - internal bool unpSomeRead; + private static readonly int[] PosL2 = { 0, 0, 0, 0, 5, 7, 9, 13, 18, 22, 26, 34, 36 }; - private int readTop; + private const int STARTHF0 = 4; - private long destUnpSize; + private static readonly int[] DecHf0 = + { + 0x8000, + 0xc000, + 0xe000, + 0xf200, + 0xf200, + 0xf200, + 0xf200, + 0xf200, + 0xffff + }; - private byte[] window; + private static readonly int[] PosHf0 = { 0, 0, 0, 0, 0, 8, 16, 24, 33, 33, 33, 33, 33 }; - private readonly int[] oldDist = new int[4]; + private const int STARTHF1 = 5; - private int unpPtr, - wrPtr; + private static readonly int[] DecHf1 = + { + 0x2000, + 0xc000, + 0xe000, + 0xf000, + 0xf200, + 0xf200, + 0xf7e0, + 0xffff + }; - private int oldDistPtr; + private static readonly int[] PosHf1 = { 0, 0, 0, 0, 0, 0, 4, 44, 60, 76, 80, 80, 127 }; - private readonly int[] ChSet = new int[256], - ChSetA = new int[256], - ChSetB = new int[256], - ChSetC = new int[256]; + private const int STARTHF2 = 5; - private readonly int[] Place = new int[256], - PlaceA = new int[256], - PlaceB = new int[256], - PlaceC = new int[256]; + private static readonly int[] DecHf2 = + { + 0x1000, + 0x2400, + 0x8000, + 0xc000, + 0xfa00, + 0xffff, + 0xffff, + 0xffff + }; - private readonly int[] NToPl = new int[256], - NToPlB = new int[256], - NToPlC = new int[256]; + private static readonly int[] PosHf2 = { 0, 0, 0, 0, 0, 0, 2, 7, 53, 117, 233, 0, 0 }; - private int FlagBuf, - AvrPlc, - AvrPlcB, - AvrLn1, - AvrLn2, - AvrLn3; + private const int STARTHF3 = 6; - private int Buf60, - NumHuf, - StMode, - LCount, - FlagsCnt; + private static readonly int[] DecHf3 = + { + 0x800, + 0x2400, + 0xee00, + 0xfe80, + 0xffff, + 0xffff, + 0xffff + }; - private int Nhfb, - Nlzb, - MaxDist3; + private static readonly int[] PosHf3 = { 0, 0, 0, 0, 0, 0, 0, 2, 16, 218, 251, 0, 0 }; - private int lastDist, - lastLength; + private const int STARTHF4 = 8; - private const int STARTL1 = 2; + private static readonly int[] DecHf4 = { 0xff00, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff }; - private static readonly int[] DecL1 = + private static readonly int[] PosHf4 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0 }; + + private static readonly int[] ShortLen1 = + { + 1, + 3, + 4, + 4, + 5, + 6, + 7, + 8, + 8, + 4, + 4, + 5, + 6, + 6, + 4, + 0 + }; + + private static readonly int[] ShortXor1 = + { + 0, + 0xa0, + 0xd0, + 0xe0, + 0xf0, + 0xf8, + 0xfc, + 0xfe, + 0xff, + 0xc0, + 0x80, + 0x90, + 0x98, + 0x9c, + 0xb0 + }; + + private static readonly int[] ShortLen2 = + { + 2, + 3, + 3, + 3, + 4, + 4, + 5, + 6, + 6, + 4, + 4, + 5, + 6, + 6, + 4, + 0 + }; + + private static readonly int[] ShortXor2 = + { + 0, + 0x40, + 0x60, + 0xa0, + 0xd0, + 0xe0, + 0xf0, + 0xf8, + 0xfc, + 0xc0, + 0x80, + 0x90, + 0x98, + 0x9c, + 0xb0 + }; + + private void unpack15(bool solid) + { + if (suspended) { - 0x8000, - 0xa000, - 0xc000, - 0xd000, - 0xe000, - 0xea00, - 0xee00, - 0xf000, - 0xf200, - 0xf200, - 0xffff - }; - - private static readonly int[] PosL1 = { 0, 0, 0, 2, 3, 5, 7, 11, 16, 20, 24, 32, 32 }; - - private const int STARTL2 = 3; - - private static readonly int[] DecL2 = + unpPtr = wrPtr; + } + else { - 0xa000, - 0xc000, - 0xd000, - 0xe000, - 0xea00, - 0xee00, - 0xf000, - 0xf200, - 0xf240, - 0xffff - }; - - private static readonly int[] PosL2 = { 0, 0, 0, 0, 5, 7, 9, 13, 18, 22, 26, 34, 36 }; - - private const int STARTHF0 = 4; - - private static readonly int[] DecHf0 = - { - 0x8000, - 0xc000, - 0xe000, - 0xf200, - 0xf200, - 0xf200, - 0xf200, - 0xf200, - 0xffff - }; - - private static readonly int[] PosHf0 = { 0, 0, 0, 0, 0, 8, 16, 24, 33, 33, 33, 33, 33 }; - - private const int STARTHF1 = 5; - - private static readonly int[] DecHf1 = - { - 0x2000, - 0xc000, - 0xe000, - 0xf000, - 0xf200, - 0xf200, - 0xf7e0, - 0xffff - }; - - private static readonly int[] PosHf1 = { 0, 0, 0, 0, 0, 0, 4, 44, 60, 76, 80, 80, 127 }; - - private const int STARTHF2 = 5; - - private static readonly int[] DecHf2 = - { - 0x1000, - 0x2400, - 0x8000, - 0xc000, - 0xfa00, - 0xffff, - 0xffff, - 0xffff - }; - - private static readonly int[] PosHf2 = { 0, 0, 0, 0, 0, 0, 2, 7, 53, 117, 233, 0, 0 }; - - private const int STARTHF3 = 6; - - private static readonly int[] DecHf3 = - { - 0x800, - 0x2400, - 0xee00, - 0xfe80, - 0xffff, - 0xffff, - 0xffff - }; - - private static readonly int[] PosHf3 = { 0, 0, 0, 0, 0, 0, 0, 2, 16, 218, 251, 0, 0 }; - - private const int STARTHF4 = 8; - - private static readonly int[] DecHf4 = { 0xff00, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff }; - - private static readonly int[] PosHf4 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0 }; - - private static readonly int[] ShortLen1 = - { - 1, - 3, - 4, - 4, - 5, - 6, - 7, - 8, - 8, - 4, - 4, - 5, - 6, - 6, - 4, - 0 - }; - - private static readonly int[] ShortXor1 = - { - 0, - 0xa0, - 0xd0, - 0xe0, - 0xf0, - 0xf8, - 0xfc, - 0xfe, - 0xff, - 0xc0, - 0x80, - 0x90, - 0x98, - 0x9c, - 0xb0 - }; - - private static readonly int[] ShortLen2 = - { - 2, - 3, - 3, - 3, - 4, - 4, - 5, - 6, - 6, - 4, - 4, - 5, - 6, - 6, - 4, - 0 - }; - - private static readonly int[] ShortXor2 = - { - 0, - 0x40, - 0x60, - 0xa0, - 0xd0, - 0xe0, - 0xf0, - 0xf8, - 0xfc, - 0xc0, - 0x80, - 0x90, - 0x98, - 0x9c, - 0xb0 - }; - - private void unpack15(bool solid) - { - if (suspended) + UnpInitData(solid); + oldUnpInitData(solid); + unpReadBuf(); + if (!solid) { - unpPtr = wrPtr; + initHuff(); + unpPtr = 0; } else { - UnpInitData(solid); - oldUnpInitData(solid); - unpReadBuf(); - if (!solid) + unpPtr = wrPtr; + } + --destUnpSize; + } + if (destUnpSize >= 0) + { + getFlagsBuf(); + FlagsCnt = 8; + } + + while (destUnpSize >= 0) + { + unpPtr &= PackDef.MAXWINMASK; + + if (inAddr > readTop - 30 && !unpReadBuf()) + { + break; + } + if (((wrPtr - unpPtr) & PackDef.MAXWINMASK) < 270 && wrPtr != unpPtr) + { + oldUnpWriteBuf(); + if (suspended) { - initHuff(); - unpPtr = 0; + return; + } + } + if (StMode != 0) + { + huffDecode(); + continue; + } + + if (--FlagsCnt < 0) + { + getFlagsBuf(); + FlagsCnt = 7; + } + + if ((FlagBuf & 0x80) != 0) + { + FlagBuf <<= 1; + if (Nlzb > Nhfb) + { + longLZ(); } else - { - unpPtr = wrPtr; - } - --destUnpSize; - } - if (destUnpSize >= 0) - { - getFlagsBuf(); - FlagsCnt = 8; - } - - while (destUnpSize >= 0) - { - unpPtr &= PackDef.MAXWINMASK; - - if (inAddr > readTop - 30 && !unpReadBuf()) - { - break; - } - if (((wrPtr - unpPtr) & PackDef.MAXWINMASK) < 270 && wrPtr != unpPtr) - { - oldUnpWriteBuf(); - if (suspended) - { - return; - } - } - if (StMode != 0) { huffDecode(); - continue; } - + } + else + { + FlagBuf <<= 1; if (--FlagsCnt < 0) { getFlagsBuf(); FlagsCnt = 7; } - if ((FlagBuf & 0x80) != 0) { FlagBuf <<= 1; if (Nlzb > Nhfb) { - longLZ(); + huffDecode(); } else { - huffDecode(); + longLZ(); } } else { FlagBuf <<= 1; - if (--FlagsCnt < 0) - { - getFlagsBuf(); - FlagsCnt = 7; - } - if ((FlagBuf & 0x80) != 0) - { - FlagBuf <<= 1; - if (Nlzb > Nhfb) - { - huffDecode(); - } - else - { - longLZ(); - } - } - else - { - FlagBuf <<= 1; - shortLZ(); - } + shortLZ(); } } - oldUnpWriteBuf(); + } + oldUnpWriteBuf(); + } + + private bool unpReadBuf() + { + var dataSize = readTop - inAddr; + if (dataSize < 0) + { + return (false); + } + if (inAddr > MAX_SIZE / 2) + { + if (dataSize > 0) + { + //memmove(InBuf,InBuf+InAddr,DataSize); + // for (int i = 0; i < dataSize; i++) { + // inBuf[i] = inBuf[inAddr + i]; + // } + Array.Copy(InBuf, inAddr, InBuf, 0, dataSize); + } + inAddr = 0; + readTop = dataSize; + } + else + { + dataSize = readTop; } - private bool unpReadBuf() + //int readCode=UnpIO->UnpRead(InBuf+DataSize,(BitInput::MAX_SIZE-DataSize)&~0xf); + var readCode = readStream.Read(InBuf, dataSize, (MAX_SIZE - dataSize) & ~0xf); + if (readCode > 0) { - int dataSize = readTop - inAddr; - if (dataSize < 0) + readTop += readCode; + } + readBorder = readTop - 30; + return (readCode != -1); + } + + private int getShortLen1(int pos) + { + return pos == 1 ? Buf60 + 3 : ShortLen1[pos]; + } + + private int getShortLen2(int pos) + { + return pos == 3 ? Buf60 + 3 : ShortLen2[pos]; + } + + private void shortLZ() + { + int Length, + SaveLength; + int LastDistance; + int Distance; + int DistancePlace; + NumHuf = 0; + + var BitField = GetBits(); + if (LCount == 2) + { + AddBits(1); + if (BitField >= 0x8000) { - return (false); + oldCopyString(lastDist, lastLength); + return; } - if (inAddr > MAX_SIZE / 2) + BitField <<= 1; + LCount = 0; + } + BitField = Utility.URShift(BitField, 8); + if (AvrLn1 < 37) + { + for (Length = 0; ; Length++) { - if (dataSize > 0) + if ( + ( + (BitField ^ ShortXor1[Length]) + & (~(Utility.URShift(0xff, getShortLen1(Length)))) + ) == 0 + ) { - //memmove(InBuf,InBuf+InAddr,DataSize); - // for (int i = 0; i < dataSize; i++) { - // inBuf[i] = inBuf[inAddr + i]; - // } - Array.Copy(InBuf, inAddr, InBuf, 0, dataSize); + break; } - inAddr = 0; - readTop = dataSize; } - else - { - dataSize = readTop; - } - - //int readCode=UnpIO->UnpRead(InBuf+DataSize,(BitInput::MAX_SIZE-DataSize)&~0xf); - int readCode = readStream.Read(InBuf, dataSize, (MAX_SIZE - dataSize) & ~0xf); - if (readCode > 0) - { - readTop += readCode; - } - readBorder = readTop - 30; - return (readCode != -1); + AddBits(getShortLen1(Length)); } - - private int getShortLen1(int pos) + else { - return pos == 1 ? Buf60 + 3 : ShortLen1[pos]; - } - - private int getShortLen2(int pos) - { - return pos == 3 ? Buf60 + 3 : ShortLen2[pos]; - } - - private void shortLZ() - { - int Length, - SaveLength; - int LastDistance; - int Distance; - int DistancePlace; - NumHuf = 0; - - int BitField = GetBits(); - if (LCount == 2) + for (Length = 0; ; Length++) { - AddBits(1); - if (BitField >= 0x8000) + if (((BitField ^ ShortXor2[Length]) & (~(0xff >> getShortLen2(Length)))) == 0) { - oldCopyString(lastDist, lastLength); - return; + break; } - BitField <<= 1; + } + AddBits(getShortLen2(Length)); + } + + if (Length >= 9) + { + if (Length == 9) + { + LCount++; + oldCopyString(lastDist, lastLength); + return; + } + if (Length == 14) + { LCount = 0; - } - BitField = Utility.URShift(BitField, 8); - if (AvrLn1 < 37) - { - for (Length = 0; ; Length++) - { - if ( - ( - (BitField ^ ShortXor1[Length]) - & (~(Utility.URShift(0xff, getShortLen1(Length)))) - ) == 0 - ) - { - break; - } - } - AddBits(getShortLen1(Length)); - } - else - { - for (Length = 0; ; Length++) - { - if (((BitField ^ ShortXor2[Length]) & (~(0xff >> getShortLen2(Length)))) == 0) - { - break; - } - } - AddBits(getShortLen2(Length)); - } - - if (Length >= 9) - { - if (Length == 9) - { - LCount++; - oldCopyString(lastDist, lastLength); - return; - } - if (Length == 14) - { - LCount = 0; - Length = decodeNum(GetBits(), STARTL2, DecL2, PosL2) + 5; - Distance = (GetBits() >> 1) | 0x8000; - AddBits(15); - lastLength = Length; - lastDist = Distance; - oldCopyString(Distance, Length); - return; - } - - LCount = 0; - SaveLength = Length; - Distance = oldDist[(oldDistPtr - (Length - 9)) & 3]; - Length = decodeNum(GetBits(), STARTL1, DecL1, PosL1) + 2; - if (Length == 0x101 && SaveLength == 10) - { - Buf60 ^= 1; - return; - } - if (Distance > 256) - { - Length++; - } - if (Distance >= MaxDist3) - { - Length++; - } - - oldDist[oldDistPtr++] = Distance; - oldDistPtr = oldDistPtr & 3; + Length = decodeNum(GetBits(), STARTL2, DecL2, PosL2) + 5; + Distance = (GetBits() >> 1) | 0x8000; + AddBits(15); lastLength = Length; lastDist = Distance; oldCopyString(Distance, Length); @@ -499,372 +473,397 @@ namespace SharpCompress.Compressors.Rar.UnpackV1 } LCount = 0; - AvrLn1 += Length; - AvrLn1 -= (AvrLn1 >> 4); - - DistancePlace = decodeNum(GetBits(), STARTHF2, DecHf2, PosHf2) & 0xff; - Distance = ChSetA[DistancePlace]; - if (--DistancePlace != -1) + SaveLength = Length; + Distance = oldDist[(oldDistPtr - (Length - 9)) & 3]; + Length = decodeNum(GetBits(), STARTL1, DecL1, PosL1) + 2; + if (Length == 0x101 && SaveLength == 10) { - PlaceA[Distance]--; - LastDistance = ChSetA[DistancePlace]; - PlaceA[LastDistance]++; - ChSetA[DistancePlace + 1] = LastDistance; - ChSetA[DistancePlace] = Distance; + Buf60 ^= 1; + return; } - Length += 2; - oldDist[oldDistPtr++] = ++Distance; - oldDistPtr = oldDistPtr & 3; - lastLength = Length; - lastDist = Distance; - oldCopyString(Distance, Length); - } - - private void longLZ() - { - int Length; - int Distance; - int DistancePlace, - NewDistancePlace; - int OldAvr2, - OldAvr3; - - NumHuf = 0; - Nlzb += 16; - if (Nlzb > 0xff) + if (Distance > 256) { - Nlzb = 0x90; - Nhfb = Utility.URShift(Nhfb, 1); + Length++; } - OldAvr2 = AvrLn2; - - int BitField = GetBits(); - if (AvrLn2 >= 122) - { - Length = decodeNum(BitField, STARTL2, DecL2, PosL2); - } - else - { - if (AvrLn2 >= 64) - { - Length = decodeNum(BitField, STARTL1, DecL1, PosL1); - } - else - { - if (BitField < 0x100) - { - Length = BitField; - AddBits(16); - } - else - { - for (Length = 0; ((BitField << Length) & 0x8000) == 0; Length++) - { - ; - } - AddBits(Length + 1); - } - } - } - AvrLn2 += Length; - AvrLn2 -= Utility.URShift(AvrLn2, 5); - - BitField = GetBits(); - if (AvrPlcB > 0x28ff) - { - DistancePlace = decodeNum(BitField, STARTHF2, DecHf2, PosHf2); - } - else - { - if (AvrPlcB > 0x6ff) - { - DistancePlace = decodeNum(BitField, STARTHF1, DecHf1, PosHf1); - } - else - { - DistancePlace = decodeNum(BitField, STARTHF0, DecHf0, PosHf0); - } - } - AvrPlcB += DistancePlace; - AvrPlcB -= (AvrPlcB >> 8); - while (true) - { - Distance = ChSetB[DistancePlace & 0xff]; - NewDistancePlace = NToPlB[Distance++ & 0xff]++; - if ((Distance & 0xff) == 0) - { - corrHuff(ChSetB, NToPlB); - } - else - { - break; - } - } - - ChSetB[DistancePlace] = ChSetB[NewDistancePlace]; - ChSetB[NewDistancePlace] = Distance; - - Distance = Utility.URShift(((Distance & 0xff00) | (Utility.URShift(GetBits(), 8))), 1); - AddBits(7); - - OldAvr3 = AvrLn3; - if (Length != 1 && Length != 4) - { - if (Length == 0 && Distance <= MaxDist3) - { - AvrLn3++; - AvrLn3 -= (AvrLn3 >> 8); - } - else - { - if (AvrLn3 > 0) - { - AvrLn3--; - } - } - } - Length += 3; if (Distance >= MaxDist3) { Length++; } - if (Distance <= 256) - { - Length += 8; - } - if (OldAvr3 > 0xb0 || AvrPlc >= 0x2a00 && OldAvr2 < 0x40) - { - MaxDist3 = 0x7f00; - } - else - { - MaxDist3 = 0x2001; - } + oldDist[oldDistPtr++] = Distance; - oldDistPtr = oldDistPtr & 3; + oldDistPtr &= 3; lastLength = Length; lastDist = Distance; oldCopyString(Distance, Length); + return; } - private void huffDecode() + LCount = 0; + AvrLn1 += Length; + AvrLn1 -= (AvrLn1 >> 4); + + DistancePlace = decodeNum(GetBits(), STARTHF2, DecHf2, PosHf2) & 0xff; + Distance = ChSetA[DistancePlace]; + if (--DistancePlace != -1) { - int CurByte, - NewBytePlace; - int Length; - int Distance; - int BytePlace; + PlaceA[Distance]--; + LastDistance = ChSetA[DistancePlace]; + PlaceA[LastDistance]++; + ChSetA[DistancePlace + 1] = LastDistance; + ChSetA[DistancePlace] = Distance; + } + Length += 2; + oldDist[oldDistPtr++] = ++Distance; + oldDistPtr &= 3; + lastLength = Length; + lastDist = Distance; + oldCopyString(Distance, Length); + } - int BitField = GetBits(); + private void longLZ() + { + int Length; + int Distance; + int DistancePlace, + NewDistancePlace; + int OldAvr2, + OldAvr3; - if (AvrPlc > 0x75ff) + NumHuf = 0; + Nlzb += 16; + if (Nlzb > 0xff) + { + Nlzb = 0x90; + Nhfb = Utility.URShift(Nhfb, 1); + } + OldAvr2 = AvrLn2; + + var BitField = GetBits(); + if (AvrLn2 >= 122) + { + Length = decodeNum(BitField, STARTL2, DecL2, PosL2); + } + else + { + if (AvrLn2 >= 64) { - BytePlace = decodeNum(BitField, STARTHF4, DecHf4, PosHf4); + Length = decodeNum(BitField, STARTL1, DecL1, PosL1); } else { - if (AvrPlc > 0x5dff) + if (BitField < 0x100) { - BytePlace = decodeNum(BitField, STARTHF3, DecHf3, PosHf3); + Length = BitField; + AddBits(16); } else { - if (AvrPlc > 0x35ff) + for (Length = 0; ((BitField << Length) & 0x8000) == 0; Length++) { - BytePlace = decodeNum(BitField, STARTHF2, DecHf2, PosHf2); + ; + } + AddBits(Length + 1); + } + } + } + AvrLn2 += Length; + AvrLn2 -= Utility.URShift(AvrLn2, 5); + + BitField = GetBits(); + if (AvrPlcB > 0x28ff) + { + DistancePlace = decodeNum(BitField, STARTHF2, DecHf2, PosHf2); + } + else + { + if (AvrPlcB > 0x6ff) + { + DistancePlace = decodeNum(BitField, STARTHF1, DecHf1, PosHf1); + } + else + { + DistancePlace = decodeNum(BitField, STARTHF0, DecHf0, PosHf0); + } + } + AvrPlcB += DistancePlace; + AvrPlcB -= (AvrPlcB >> 8); + while (true) + { + Distance = ChSetB[DistancePlace & 0xff]; + NewDistancePlace = NToPlB[Distance++ & 0xff]++; + if ((Distance & 0xff) == 0) + { + corrHuff(ChSetB, NToPlB); + } + else + { + break; + } + } + + ChSetB[DistancePlace] = ChSetB[NewDistancePlace]; + ChSetB[NewDistancePlace] = Distance; + + Distance = Utility.URShift(((Distance & 0xff00) | (Utility.URShift(GetBits(), 8))), 1); + AddBits(7); + + OldAvr3 = AvrLn3; + if (Length != 1 && Length != 4) + { + if (Length == 0 && Distance <= MaxDist3) + { + AvrLn3++; + AvrLn3 -= (AvrLn3 >> 8); + } + else + { + if (AvrLn3 > 0) + { + AvrLn3--; + } + } + } + Length += 3; + if (Distance >= MaxDist3) + { + Length++; + } + if (Distance <= 256) + { + Length += 8; + } + if (OldAvr3 > 0xb0 || AvrPlc >= 0x2a00 && OldAvr2 < 0x40) + { + MaxDist3 = 0x7f00; + } + else + { + MaxDist3 = 0x2001; + } + oldDist[oldDistPtr++] = Distance; + oldDistPtr &= 3; + lastLength = Length; + lastDist = Distance; + oldCopyString(Distance, Length); + } + + private void huffDecode() + { + int CurByte, + NewBytePlace; + int Length; + int Distance; + int BytePlace; + + var BitField = GetBits(); + + if (AvrPlc > 0x75ff) + { + BytePlace = decodeNum(BitField, STARTHF4, DecHf4, PosHf4); + } + else + { + if (AvrPlc > 0x5dff) + { + BytePlace = decodeNum(BitField, STARTHF3, DecHf3, PosHf3); + } + else + { + if (AvrPlc > 0x35ff) + { + BytePlace = decodeNum(BitField, STARTHF2, DecHf2, PosHf2); + } + else + { + if (AvrPlc > 0x0dff) + { + BytePlace = decodeNum(BitField, STARTHF1, DecHf1, PosHf1); } else { - if (AvrPlc > 0x0dff) - { - BytePlace = decodeNum(BitField, STARTHF1, DecHf1, PosHf1); - } - else - { - BytePlace = decodeNum(BitField, STARTHF0, DecHf0, PosHf0); - } + BytePlace = decodeNum(BitField, STARTHF0, DecHf0, PosHf0); } } } - BytePlace &= 0xff; - if (StMode != 0) + } + BytePlace &= 0xff; + if (StMode != 0) + { + if (BytePlace == 0 && BitField > 0xfff) { - if (BytePlace == 0 && BitField > 0xfff) + BytePlace = 0x100; + } + if (--BytePlace == -1) + { + BitField = GetBits(); + AddBits(1); + if ((BitField & 0x8000) != 0) { - BytePlace = 0x100; - } - if (--BytePlace == -1) - { - BitField = GetBits(); - AddBits(1); - if ((BitField & 0x8000) != 0) - { - NumHuf = StMode = 0; - return; - } - Length = (BitField & 0x4000) != 0 ? 4 : 3; - AddBits(1); - Distance = decodeNum(GetBits(), STARTHF2, DecHf2, PosHf2); - Distance = (Distance << 5) | (Utility.URShift(GetBits(), 11)); - AddBits(5); - oldCopyString(Distance, Length); + NumHuf = StMode = 0; return; } + Length = (BitField & 0x4000) != 0 ? 4 : 3; + AddBits(1); + Distance = decodeNum(GetBits(), STARTHF2, DecHf2, PosHf2); + Distance = (Distance << 5) | (Utility.URShift(GetBits(), 11)); + AddBits(5); + oldCopyString(Distance, Length); + return; + } + } + else + { + if (NumHuf++ >= 16 && FlagsCnt == 0) + { + StMode = 1; + } + } + AvrPlc += BytePlace; + AvrPlc -= Utility.URShift(AvrPlc, 8); + Nhfb += 16; + if (Nhfb > 0xff) + { + Nhfb = 0x90; + Nlzb = Utility.URShift(Nlzb, 1); + } + + window[unpPtr++] = (byte)(Utility.URShift(ChSet[BytePlace], 8)); + --destUnpSize; + + while (true) + { + CurByte = ChSet[BytePlace]; + NewBytePlace = NToPl[CurByte++ & 0xff]++; + if ((CurByte & 0xff) > 0xa1) + { + corrHuff(ChSet, NToPl); } else { - if (NumHuf++ >= 16 && FlagsCnt == 0) - { - StMode = 1; - } - } - AvrPlc += BytePlace; - AvrPlc -= Utility.URShift(AvrPlc, 8); - Nhfb += 16; - if (Nhfb > 0xff) - { - Nhfb = 0x90; - Nlzb = Utility.URShift(Nlzb, 1); - } - - window[unpPtr++] = (byte)(Utility.URShift(ChSet[BytePlace], 8)); - --destUnpSize; - - while (true) - { - CurByte = ChSet[BytePlace]; - NewBytePlace = NToPl[CurByte++ & 0xff]++; - if ((CurByte & 0xff) > 0xa1) - { - corrHuff(ChSet, NToPl); - } - else - { - break; - } - } - - ChSet[BytePlace] = ChSet[NewBytePlace]; - ChSet[NewBytePlace] = CurByte; - } - - private void getFlagsBuf() - { - int Flags, - NewFlagsPlace; - int FlagsPlace = decodeNum(GetBits(), STARTHF2, DecHf2, PosHf2); - - while (true) - { - Flags = ChSetC[FlagsPlace]; - FlagBuf = Utility.URShift(Flags, 8); - NewFlagsPlace = NToPlC[Flags++ & 0xff]++; - if ((Flags & 0xff) != 0) - { - break; - } - corrHuff(ChSetC, NToPlC); - } - - ChSetC[FlagsPlace] = ChSetC[NewFlagsPlace]; - ChSetC[NewFlagsPlace] = Flags; - } - - private void oldUnpInitData(bool Solid) - { - if (!Solid) - { - AvrPlcB = AvrLn1 = AvrLn2 = AvrLn3 = NumHuf = Buf60 = 0; - AvrPlc = 0x3500; - MaxDist3 = 0x2001; - Nhfb = Nlzb = 0x80; - } - FlagsCnt = 0; - FlagBuf = 0; - StMode = 0; - LCount = 0; - readTop = 0; - } - - private void initHuff() - { - for (int I = 0; I < 256; I++) - { - Place[I] = PlaceA[I] = PlaceB[I] = I; - PlaceC[I] = (~I + 1) & 0xff; - ChSet[I] = ChSetB[I] = I << 8; - ChSetA[I] = I; - ChSetC[I] = ((~I + 1) & 0xff) << 8; - } - - new Span(NToPl).Clear(); // memset(NToPl,0,sizeof(NToPl)); - new Span(NToPlB).Clear(); // memset(NToPlB,0,sizeof(NToPlB)); - new Span(NToPlC).Clear(); // memset(NToPlC,0,sizeof(NToPlC)); - corrHuff(ChSetB, NToPlB); - } - - private void corrHuff(int[] CharSet, int[] NumToPlace) - { - int I, - J, - pos = 0; - for (I = 7; I >= 0; I--) - { - for (J = 0; J < 32; J++, pos++) - { - CharSet[pos] = ((CharSet[pos] & ~0xff) | I); // *CharSet=(*CharSet - - // & ~0xff) | I; - } - } - new Span(NumToPlace).Clear(); // memset(NumToPlace,0,sizeof(NToPl)); - for (I = 6; I >= 0; I--) - { - NumToPlace[I] = (7 - I) * 32; + break; } } - private void oldCopyString(int Distance, int Length) + ChSet[BytePlace] = ChSet[NewBytePlace]; + ChSet[NewBytePlace] = CurByte; + } + + private void getFlagsBuf() + { + int Flags, + NewFlagsPlace; + var FlagsPlace = decodeNum(GetBits(), STARTHF2, DecHf2, PosHf2); + + while (true) { - destUnpSize -= Length; - while ((Length--) != 0) + Flags = ChSetC[FlagsPlace]; + FlagBuf = Utility.URShift(Flags, 8); + NewFlagsPlace = NToPlC[Flags++ & 0xff]++; + if ((Flags & 0xff) != 0) { - window[unpPtr] = window[(unpPtr - Distance) & PackDef.MAXWINMASK]; - unpPtr = (unpPtr + 1) & PackDef.MAXWINMASK; + break; } + corrHuff(ChSetC, NToPlC); } - private int decodeNum(int Num, int StartPos, int[] DecTab, int[] PosTab) + ChSetC[FlagsPlace] = ChSetC[NewFlagsPlace]; + ChSetC[NewFlagsPlace] = Flags; + } + + private void oldUnpInitData(bool Solid) + { + if (!Solid) { - int I; - for (Num &= 0xfff0, I = 0; DecTab[I] <= Num; I++) - { - StartPos++; - } - AddBits(StartPos); - return ( - (Utility.URShift((Num - (I != 0 ? DecTab[I - 1] : 0)), (16 - StartPos))) - + PosTab[StartPos] - ); + AvrPlcB = AvrLn1 = AvrLn2 = AvrLn3 = NumHuf = Buf60 = 0; + AvrPlc = 0x3500; + MaxDist3 = 0x2001; + Nhfb = Nlzb = 0x80; + } + FlagsCnt = 0; + FlagBuf = 0; + StMode = 0; + LCount = 0; + readTop = 0; + } + + private void initHuff() + { + for (var I = 0; I < 256; I++) + { + Place[I] = PlaceA[I] = PlaceB[I] = I; + PlaceC[I] = (~I + 1) & 0xff; + ChSet[I] = ChSetB[I] = I << 8; + ChSetA[I] = I; + ChSetC[I] = ((~I + 1) & 0xff) << 8; } - private void oldUnpWriteBuf() + new Span(NToPl).Clear(); // memset(NToPl,0,sizeof(NToPl)); + new Span(NToPlB).Clear(); // memset(NToPlB,0,sizeof(NToPlB)); + new Span(NToPlC).Clear(); // memset(NToPlC,0,sizeof(NToPlC)); + corrHuff(ChSetB, NToPlB); + } + + private void corrHuff(int[] CharSet, int[] NumToPlace) + { + int I, + J, + pos = 0; + for (I = 7; I >= 0; I--) { - if (unpPtr != wrPtr) + for (J = 0; J < 32; J++, pos++) { - unpSomeRead = true; + CharSet[pos] = ((CharSet[pos] & ~0xff) | I); // *CharSet=(*CharSet + + // & ~0xff) | I; } - if (unpPtr < wrPtr) - { - writeStream.Write(window, wrPtr, -wrPtr & PackDef.MAXWINMASK); - writeStream.Write(window, 0, unpPtr); - unpAllBuf = true; - } - else - { - writeStream.Write(window, wrPtr, unpPtr - wrPtr); - } - wrPtr = unpPtr; + } + new Span(NumToPlace).Clear(); // memset(NumToPlace,0,sizeof(NToPl)); + for (I = 6; I >= 0; I--) + { + NumToPlace[I] = (7 - I) * 32; } } + + private void oldCopyString(int Distance, int Length) + { + destUnpSize -= Length; + while ((Length--) != 0) + { + window[unpPtr] = window[(unpPtr - Distance) & PackDef.MAXWINMASK]; + unpPtr = (unpPtr + 1) & PackDef.MAXWINMASK; + } + } + + private int decodeNum(int Num, int StartPos, int[] DecTab, int[] PosTab) + { + int I; + for (Num &= 0xfff0, I = 0; DecTab[I] <= Num; I++) + { + StartPos++; + } + AddBits(StartPos); + return ( + (Utility.URShift((Num - (I != 0 ? DecTab[I - 1] : 0)), (16 - StartPos))) + + PosTab[StartPos] + ); + } + + private void oldUnpWriteBuf() + { + if (unpPtr != wrPtr) + { + unpSomeRead = true; + } + if (unpPtr < wrPtr) + { + writeStream.Write(window, wrPtr, -wrPtr & PackDef.MAXWINMASK); + writeStream.Write(window, 0, unpPtr); + unpAllBuf = true; + } + else + { + writeStream.Write(window, wrPtr, unpPtr - wrPtr); + } + wrPtr = unpPtr; + } } diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack20.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack20.cs index fa28fc0d..1b882545 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack20.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack20.cs @@ -10,667 +10,666 @@ using System; using SharpCompress.Compressors.Rar.UnpackV1.Decode; -namespace SharpCompress.Compressors.Rar.UnpackV1 +namespace SharpCompress.Compressors.Rar.UnpackV1; + +internal partial class Unpack { - internal partial class Unpack + private readonly MultDecode[] MD = new MultDecode[4]; + + private readonly byte[] UnpOldTable20 = new byte[PackDef.MC20 * 4]; + + private int UnpAudioBlock, + UnpChannels, + UnpCurChannel, + UnpChannelDelta; + + private readonly AudioVariables[] AudV = new AudioVariables[4]; + + private readonly LitDecode LD = new LitDecode(); + + private readonly DistDecode DD = new DistDecode(); + + private readonly LowDistDecode LDD = new LowDistDecode(); + + private readonly RepDecode RD = new RepDecode(); + + private readonly BitDecode BD = new BitDecode(); + + private static readonly int[] LDecode = { - private readonly MultDecode[] MD = new MultDecode[4]; + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 10, + 12, + 14, + 16, + 20, + 24, + 28, + 32, + 40, + 48, + 56, + 64, + 80, + 96, + 112, + 128, + 160, + 192, + 224 + }; - private readonly byte[] UnpOldTable20 = new byte[PackDef.MC20 * 4]; - - private int UnpAudioBlock, - UnpChannels, - UnpCurChannel, - UnpChannelDelta; - - private readonly AudioVariables[] AudV = new AudioVariables[4]; - - private readonly LitDecode LD = new LitDecode(); - - private readonly DistDecode DD = new DistDecode(); - - private readonly LowDistDecode LDD = new LowDistDecode(); - - private readonly RepDecode RD = new RepDecode(); - - private readonly BitDecode BD = new BitDecode(); - - private static readonly int[] LDecode = + private static ReadOnlySpan LBits => + new byte[] { 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, 1, 2, + 2, + 2, + 2, + 3, + 3, + 3, 3, 4, + 4, + 4, + 4, 5, - 6, - 7, - 8, - 10, - 12, - 14, - 16, - 20, - 24, - 28, - 32, - 40, - 48, - 56, - 64, - 80, - 96, - 112, - 128, - 160, - 192, - 224 + 5, + 5, + 5 }; - private static ReadOnlySpan LBits => - new byte[] + private static readonly int[] DDecode = + { + 0, + 1, + 2, + 3, + 4, + 6, + 8, + 12, + 16, + 24, + 32, + 48, + 64, + 96, + 128, + 192, + 256, + 384, + 512, + 768, + 1024, + 1536, + 2048, + 3072, + 4096, + 6144, + 8192, + 12288, + 16384, + 24576, + 32768, + 49152, + 65536, + 98304, + 131072, + 196608, + 262144, + 327680, + 393216, + 458752, + 524288, + 589824, + 655360, + 720896, + 786432, + 851968, + 917504, + 983040 + }; + + private static readonly int[] DBits = + { + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 2, + 3, + 3, + 4, + 4, + 5, + 5, + 6, + 6, + 7, + 7, + 8, + 8, + 9, + 9, + 10, + 10, + 11, + 11, + 12, + 12, + 13, + 13, + 14, + 14, + 15, + 15, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16 + }; + + private static readonly int[] SDDecode = { 0, 4, 8, 16, 32, 64, 128, 192 }; + + private static readonly int[] SDBits = { 2, 2, 3, 4, 5, 6, 6, 6 }; + + private void unpack20(bool solid) + { + int Bits; + + if (suspended) + { + unpPtr = wrPtr; + } + else + { + UnpInitData(solid); + if (!unpReadBuf()) { - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1, - 1, - 1, - 1, - 2, - 2, - 2, - 2, - 3, - 3, - 3, - 3, - 4, - 4, - 4, - 4, - 5, - 5, - 5, - 5 - }; - - private static readonly int[] DDecode = - { - 0, - 1, - 2, - 3, - 4, - 6, - 8, - 12, - 16, - 24, - 32, - 48, - 64, - 96, - 128, - 192, - 256, - 384, - 512, - 768, - 1024, - 1536, - 2048, - 3072, - 4096, - 6144, - 8192, - 12288, - 16384, - 24576, - 32768, - 49152, - 65536, - 98304, - 131072, - 196608, - 262144, - 327680, - 393216, - 458752, - 524288, - 589824, - 655360, - 720896, - 786432, - 851968, - 917504, - 983040 - }; - - private static readonly int[] DBits = - { - 0, - 0, - 0, - 0, - 1, - 1, - 2, - 2, - 3, - 3, - 4, - 4, - 5, - 5, - 6, - 6, - 7, - 7, - 8, - 8, - 9, - 9, - 10, - 10, - 11, - 11, - 12, - 12, - 13, - 13, - 14, - 14, - 15, - 15, - 16, - 16, - 16, - 16, - 16, - 16, - 16, - 16, - 16, - 16, - 16, - 16, - 16, - 16 - }; - - private static readonly int[] SDDecode = { 0, 4, 8, 16, 32, 64, 128, 192 }; - - private static readonly int[] SDBits = { 2, 2, 3, 4, 5, 6, 6, 6 }; - - private void unpack20(bool solid) - { - int Bits; - - if (suspended) - { - unpPtr = wrPtr; + return; } - else + if (!solid) { - UnpInitData(solid); - if (!unpReadBuf()) + if (!ReadTables20()) { return; } - if (!solid) + } + --destUnpSize; + } + + while (destUnpSize >= 0) + { + unpPtr &= PackDef.MAXWINMASK; + + if (inAddr > readTop - 30) + { + if (!unpReadBuf()) + { + break; + } + } + if (((wrPtr - unpPtr) & PackDef.MAXWINMASK) < 270 && wrPtr != unpPtr) + { + oldUnpWriteBuf(); + if (suspended) + { + return; + } + } + if (UnpAudioBlock != 0) + { + var AudioNumber = this.decodeNumber(MD[UnpCurChannel]); + + if (AudioNumber == 256) { if (!ReadTables20()) - { - return; - } - } - --destUnpSize; - } - - while (destUnpSize >= 0) - { - unpPtr &= PackDef.MAXWINMASK; - - if (inAddr > readTop - 30) - { - if (!unpReadBuf()) { break; } - } - if (((wrPtr - unpPtr) & PackDef.MAXWINMASK) < 270 && wrPtr != unpPtr) - { - oldUnpWriteBuf(); - if (suspended) - { - return; - } - } - if (UnpAudioBlock != 0) - { - int AudioNumber = this.decodeNumber(MD[UnpCurChannel]); - - if (AudioNumber == 256) - { - if (!ReadTables20()) - { - break; - } - continue; - } - window[unpPtr++] = DecodeAudio(AudioNumber); - if (++UnpCurChannel == UnpChannels) - { - UnpCurChannel = 0; - } - --destUnpSize; continue; } - - int Number = this.decodeNumber(LD); - if (Number < 256) + window[unpPtr++] = DecodeAudio(AudioNumber); + if (++UnpCurChannel == UnpChannels) { - window[unpPtr++] = (byte)Number; - --destUnpSize; - continue; + UnpCurChannel = 0; } - if (Number > 269) + --destUnpSize; + continue; + } + + var Number = this.decodeNumber(LD); + if (Number < 256) + { + window[unpPtr++] = (byte)Number; + --destUnpSize; + continue; + } + if (Number > 269) + { + var Length = LDecode[Number -= 270] + 3; + if ((Bits = LBits[Number]) > 0) { - int Length = LDecode[Number -= 270] + 3; - if ((Bits = LBits[Number]) > 0) - { - Length += Utility.URShift(GetBits(), (16 - Bits)); - AddBits(Bits); - } + Length += Utility.URShift(GetBits(), (16 - Bits)); + AddBits(Bits); + } - int DistNumber = this.decodeNumber(DD); - int Distance = DDecode[DistNumber] + 1; - if ((Bits = DBits[DistNumber]) > 0) - { - Distance += Utility.URShift(GetBits(), (16 - Bits)); - AddBits(Bits); - } + var DistNumber = this.decodeNumber(DD); + var Distance = DDecode[DistNumber] + 1; + if ((Bits = DBits[DistNumber]) > 0) + { + Distance += Utility.URShift(GetBits(), (16 - Bits)); + AddBits(Bits); + } + if (Distance >= 0x2000) + { + Length++; + if (Distance >= 0x40000L) + { + Length++; + } + } + + CopyString20(Length, Distance); + continue; + } + if (Number == 269) + { + if (!ReadTables20()) + { + break; + } + continue; + } + if (Number == 256) + { + CopyString20(lastLength, lastDist); + continue; + } + if (Number < 261) + { + var Distance = oldDist[(oldDistPtr - (Number - 256)) & 3]; + var LengthNumber = this.decodeNumber(RD); + var Length = LDecode[LengthNumber] + 2; + if ((Bits = LBits[LengthNumber]) > 0) + { + Length += Utility.URShift(GetBits(), (16 - Bits)); + AddBits(Bits); + } + if (Distance >= 0x101) + { + Length++; if (Distance >= 0x2000) { Length++; - if (Distance >= 0x40000L) + if (Distance >= 0x40000) { Length++; } } - - CopyString20(Length, Distance); - continue; - } - if (Number == 269) - { - if (!ReadTables20()) - { - break; - } - continue; - } - if (Number == 256) - { - CopyString20(lastLength, lastDist); - continue; - } - if (Number < 261) - { - int Distance = oldDist[(oldDistPtr - (Number - 256)) & 3]; - int LengthNumber = this.decodeNumber(RD); - int Length = LDecode[LengthNumber] + 2; - if ((Bits = LBits[LengthNumber]) > 0) - { - Length += Utility.URShift(GetBits(), (16 - Bits)); - AddBits(Bits); - } - if (Distance >= 0x101) - { - Length++; - if (Distance >= 0x2000) - { - Length++; - if (Distance >= 0x40000) - { - Length++; - } - } - } - CopyString20(Length, Distance); - continue; - } - if (Number < 270) - { - int Distance = SDDecode[Number -= 261] + 1; - if ((Bits = SDBits[Number]) > 0) - { - Distance += Utility.URShift(GetBits(), (16 - Bits)); - AddBits(Bits); - } - CopyString20(2, Distance); } + CopyString20(Length, Distance); + continue; } - ReadLastTables(); - oldUnpWriteBuf(); - } - - private void CopyString20(int Length, int Distance) - { - lastDist = oldDist[oldDistPtr++ & 3] = Distance; - lastLength = Length; - destUnpSize -= Length; - - int DestPtr = unpPtr - Distance; - if (DestPtr < PackDef.MAXWINSIZE - 300 && unpPtr < PackDef.MAXWINSIZE - 300) + if (Number < 270) { - window[unpPtr++] = window[DestPtr++]; - window[unpPtr++] = window[DestPtr++]; - while (Length > 2) + var Distance = SDDecode[Number -= 261] + 1; + if ((Bits = SDBits[Number]) > 0) { - Length--; - window[unpPtr++] = window[DestPtr++]; - } - } - else - { - while ((Length--) != 0) - { - window[unpPtr] = window[DestPtr++ & PackDef.MAXWINMASK]; - unpPtr = (unpPtr + 1) & PackDef.MAXWINMASK; + Distance += Utility.URShift(GetBits(), (16 - Bits)); + AddBits(Bits); } + CopyString20(2, Distance); } } + ReadLastTables(); + oldUnpWriteBuf(); + } - private bool ReadTables20() + private void CopyString20(int Length, int Distance) + { + lastDist = oldDist[oldDistPtr++ & 3] = Distance; + lastLength = Length; + destUnpSize -= Length; + + var DestPtr = unpPtr - Distance; + if (DestPtr < PackDef.MAXWINSIZE - 300 && unpPtr < PackDef.MAXWINSIZE - 300) { - byte[] BitLength = new byte[PackDef.BC20]; - byte[] Table = new byte[PackDef.MC20 * 4]; - int TableSize, - N, - I; - if (inAddr > readTop - 25) + window[unpPtr++] = window[DestPtr++]; + window[unpPtr++] = window[DestPtr++]; + while (Length > 2) + { + Length--; + window[unpPtr++] = window[DestPtr++]; + } + } + else + { + while ((Length--) != 0) + { + window[unpPtr] = window[DestPtr++ & PackDef.MAXWINMASK]; + unpPtr = (unpPtr + 1) & PackDef.MAXWINMASK; + } + } + } + + private bool ReadTables20() + { + var BitLength = new byte[PackDef.BC20]; + var Table = new byte[PackDef.MC20 * 4]; + int TableSize, + N, + I; + if (inAddr > readTop - 25) + { + if (!unpReadBuf()) + { + return (false); + } + } + var BitField = GetBits(); + UnpAudioBlock = (BitField & 0x8000); + + if (0 == (BitField & 0x4000)) + { + // memset(UnpOldTable20,0,sizeof(UnpOldTable20)); + new Span(UnpOldTable20).Clear(); + } + AddBits(2); + + if (UnpAudioBlock != 0) + { + UnpChannels = ((Utility.URShift(BitField, 12)) & 3) + 1; + if (UnpCurChannel >= UnpChannels) + { + UnpCurChannel = 0; + } + AddBits(2); + TableSize = PackDef.MC20 * UnpChannels; + } + else + { + TableSize = PackDef.NC20 + PackDef.DC20 + PackDef.RC20; + } + for (I = 0; I < PackDef.BC20; I++) + { + BitLength[I] = (byte)(Utility.URShift(GetBits(), 12)); + AddBits(4); + } + UnpackUtility.makeDecodeTables(BitLength, 0, BD, PackDef.BC20); + I = 0; + while (I < TableSize) + { + if (inAddr > readTop - 5) { if (!unpReadBuf()) { return (false); } } - int BitField = GetBits(); - UnpAudioBlock = (BitField & 0x8000); - - if (0 == (BitField & 0x4000)) + var Number = this.decodeNumber(BD); + if (Number < 16) { - // memset(UnpOldTable20,0,sizeof(UnpOldTable20)); - new Span(UnpOldTable20).Clear(); + Table[I] = (byte)((Number + UnpOldTable20[I]) & 0xf); + I++; } - AddBits(2); - - if (UnpAudioBlock != 0) + else if (Number == 16) { - UnpChannels = ((Utility.URShift(BitField, 12)) & 3) + 1; - if (UnpCurChannel >= UnpChannels) - { - UnpCurChannel = 0; - } + N = (Utility.URShift(GetBits(), 14)) + 3; AddBits(2); - TableSize = PackDef.MC20 * UnpChannels; - } - else - { - TableSize = PackDef.NC20 + PackDef.DC20 + PackDef.RC20; - } - for (I = 0; I < PackDef.BC20; I++) - { - BitLength[I] = (byte)(Utility.URShift(GetBits(), 12)); - AddBits(4); - } - UnpackUtility.makeDecodeTables(BitLength, 0, BD, PackDef.BC20); - I = 0; - while (I < TableSize) - { - if (inAddr > readTop - 5) + while (N-- > 0 && I < TableSize) { - if (!unpReadBuf()) - { - return (false); - } - } - int Number = this.decodeNumber(BD); - if (Number < 16) - { - Table[I] = (byte)((Number + UnpOldTable20[I]) & 0xf); + Table[I] = Table[I - 1]; I++; } - else if (Number == 16) + } + else + { + if (Number == 17) { - N = (Utility.URShift(GetBits(), 14)) + 3; - AddBits(2); - while (N-- > 0 && I < TableSize) - { - Table[I] = Table[I - 1]; - I++; - } + N = (Utility.URShift(GetBits(), 13)) + 3; + AddBits(3); } else { - if (Number == 17) - { - N = (Utility.URShift(GetBits(), 13)) + 3; - AddBits(3); - } - else - { - N = (Utility.URShift(GetBits(), 9)) + 11; - AddBits(7); - } - while (N-- > 0 && I < TableSize) - { - Table[I++] = 0; - } + N = (Utility.URShift(GetBits(), 9)) + 11; + AddBits(7); + } + while (N-- > 0 && I < TableSize) + { + Table[I++] = 0; } } - if (inAddr > readTop) + } + if (inAddr > readTop) + { + return (true); + } + if (UnpAudioBlock != 0) + { + for (I = 0; I < UnpChannels; I++) { - return (true); + UnpackUtility.makeDecodeTables(Table, I * PackDef.MC20, MD[I], PackDef.MC20); } + } + else + { + UnpackUtility.makeDecodeTables(Table, 0, LD, PackDef.NC20); + UnpackUtility.makeDecodeTables(Table, PackDef.NC20, DD, PackDef.DC20); + UnpackUtility.makeDecodeTables( + Table, + PackDef.NC20 + PackDef.DC20, + RD, + PackDef.RC20 + ); + } + + // memcpy(UnpOldTable20,Table,sizeof(UnpOldTable20)); + for (var i = 0; i < UnpOldTable20.Length; i++) + { + UnpOldTable20[i] = Table[i]; + } + return (true); + } + + private void unpInitData20(bool Solid) + { + if (!Solid) + { + UnpChannelDelta = UnpCurChannel = 0; + UnpChannels = 1; + + // memset(AudV,0,sizeof(AudV)); + AudV[0] = new AudioVariables(); + AudV[1] = new AudioVariables(); + AudV[2] = new AudioVariables(); + AudV[3] = new AudioVariables(); + + // memset(UnpOldTable20,0,sizeof(UnpOldTable20)); + new Span(UnpOldTable20).Clear(); + } + } + + private void ReadLastTables() + { + if (readTop >= inAddr + 5) + { if (UnpAudioBlock != 0) { - for (I = 0; I < UnpChannels; I++) + if (this.decodeNumber(MD[UnpCurChannel]) == 256) { - UnpackUtility.makeDecodeTables(Table, I * PackDef.MC20, MD[I], PackDef.MC20); + ReadTables20(); } } else { - UnpackUtility.makeDecodeTables(Table, 0, LD, PackDef.NC20); - UnpackUtility.makeDecodeTables(Table, PackDef.NC20, DD, PackDef.DC20); - UnpackUtility.makeDecodeTables( - Table, - PackDef.NC20 + PackDef.DC20, - RD, - PackDef.RC20 - ); - } - - // memcpy(UnpOldTable20,Table,sizeof(UnpOldTable20)); - for (int i = 0; i < UnpOldTable20.Length; i++) - { - UnpOldTable20[i] = Table[i]; - } - return (true); - } - - private void unpInitData20(bool Solid) - { - if (!Solid) - { - UnpChannelDelta = UnpCurChannel = 0; - UnpChannels = 1; - - // memset(AudV,0,sizeof(AudV)); - AudV[0] = new AudioVariables(); - AudV[1] = new AudioVariables(); - AudV[2] = new AudioVariables(); - AudV[3] = new AudioVariables(); - - // memset(UnpOldTable20,0,sizeof(UnpOldTable20)); - new Span(UnpOldTable20).Clear(); - } - } - - private void ReadLastTables() - { - if (readTop >= inAddr + 5) - { - if (UnpAudioBlock != 0) + if (this.decodeNumber(LD) == 269) { - if (this.decodeNumber(MD[UnpCurChannel]) == 256) - { - ReadTables20(); - } - } - else - { - if (this.decodeNumber(LD) == 269) - { - ReadTables20(); - } + ReadTables20(); } } } - - private byte DecodeAudio(int Delta) - { - AudioVariables v = AudV[UnpCurChannel]; - v.ByteCount = v.ByteCount + 1; - v.D4 = v.D3; - v.D3 = v.D2; // ->D3=V->D2; - v.D2 = v.LastDelta - v.D1; // ->D2=V->LastDelta-V->D1; - v.D1 = v.LastDelta; // V->D1=V->LastDelta; - - // int PCh=8*V->LastChar+V->K1*V->D1 +V->K2*V->D2 +V->K3*V->D3 - // +V->K4*V->D4+ V->K5*UnpChannelDelta; - int PCh = 8 * v.LastChar + v.K1 * v.D1; - PCh += v.K2 * v.D2 + v.K3 * v.D3; - PCh += v.K4 * v.D4 + v.K5 * UnpChannelDelta; - PCh = (Utility.URShift(PCh, 3)) & 0xFF; - - int Ch = PCh - Delta; - - int D = ((byte)Delta) << 3; - - v.Dif[0] += Math.Abs(D); // V->Dif[0]+=abs(D); - v.Dif[1] += Math.Abs(D - v.D1); // V->Dif[1]+=abs(D-V->D1); - v.Dif[2] += Math.Abs(D + v.D1); // V->Dif[2]+=abs(D+V->D1); - v.Dif[3] += Math.Abs(D - v.D2); // V->Dif[3]+=abs(D-V->D2); - v.Dif[4] += Math.Abs(D + v.D2); // V->Dif[4]+=abs(D+V->D2); - v.Dif[5] += Math.Abs(D - v.D3); // V->Dif[5]+=abs(D-V->D3); - v.Dif[6] += Math.Abs(D + v.D3); // V->Dif[6]+=abs(D+V->D3); - v.Dif[7] += Math.Abs(D - v.D4); // V->Dif[7]+=abs(D-V->D4); - v.Dif[8] += Math.Abs(D + v.D4); // V->Dif[8]+=abs(D+V->D4); - v.Dif[9] += Math.Abs(D - UnpChannelDelta); // V->Dif[9]+=abs(D-UnpChannelDelta); - v.Dif[10] += Math.Abs(D + UnpChannelDelta); // V->Dif[10]+=abs(D+UnpChannelDelta); - - v.LastDelta = (byte)(Ch - v.LastChar); - UnpChannelDelta = v.LastDelta; - v.LastChar = Ch; // V->LastChar=Ch; - - if ((v.ByteCount & 0x1F) == 0) - { - int MinDif = v.Dif[0], - NumMinDif = 0; - v.Dif[0] = 0; // ->Dif[0]=0; - for (int I = 1; I < v.Dif.Length; I++) - { - if (v.Dif[I] < MinDif) - { - MinDif = v.Dif[I]; - NumMinDif = I; - } - v.Dif[I] = 0; - } - switch (NumMinDif) - { - case 1: - if (v.K1 >= -16) - { - v.K1 = v.K1 - 1; // V->K1--; - } - break; - - case 2: - if (v.K1 < 16) - { - v.K1 = v.K1 + 1; // V->K1++; - } - break; - - case 3: - if (v.K2 >= -16) - { - v.K2 = v.K2 - 1; // V->K2--; - } - break; - - case 4: - if (v.K2 < 16) - { - v.K2 = v.K2 + 1; // V->K2++; - } - break; - - case 5: - if (v.K3 >= -16) - { - v.K3 = v.K3 - 1; - } - break; - - case 6: - if (v.K3 < 16) - { - v.K3 = v.K3 + 1; - } - break; - - case 7: - if (v.K4 >= -16) - { - v.K4 = v.K4 - 1; - } - break; - - case 8: - if (v.K4 < 16) - { - v.K4 = v.K4 + 1; - } - break; - - case 9: - if (v.K5 >= -16) - { - v.K5 = v.K5 - 1; - } - break; - - case 10: - if (v.K5 < 16) - { - v.K5 = v.K5 + 1; - } - break; - } - } - return ((byte)Ch); - } + } + + private byte DecodeAudio(int Delta) + { + var v = AudV[UnpCurChannel]; + v.ByteCount++; + v.D4 = v.D3; + v.D3 = v.D2; // ->D3=V->D2; + v.D2 = v.LastDelta - v.D1; // ->D2=V->LastDelta-V->D1; + v.D1 = v.LastDelta; // V->D1=V->LastDelta; + + // int PCh=8*V->LastChar+V->K1*V->D1 +V->K2*V->D2 +V->K3*V->D3 + // +V->K4*V->D4+ V->K5*UnpChannelDelta; + var PCh = (8 * v.LastChar) + (v.K1 * v.D1); + PCh += (v.K2 * v.D2) + (v.K3 * v.D3); + PCh += (v.K4 * v.D4) + (v.K5 * UnpChannelDelta); + PCh = (Utility.URShift(PCh, 3)) & 0xFF; + + var Ch = PCh - Delta; + + var D = ((byte)Delta) << 3; + + v.Dif[0] += Math.Abs(D); // V->Dif[0]+=abs(D); + v.Dif[1] += Math.Abs(D - v.D1); // V->Dif[1]+=abs(D-V->D1); + v.Dif[2] += Math.Abs(D + v.D1); // V->Dif[2]+=abs(D+V->D1); + v.Dif[3] += Math.Abs(D - v.D2); // V->Dif[3]+=abs(D-V->D2); + v.Dif[4] += Math.Abs(D + v.D2); // V->Dif[4]+=abs(D+V->D2); + v.Dif[5] += Math.Abs(D - v.D3); // V->Dif[5]+=abs(D-V->D3); + v.Dif[6] += Math.Abs(D + v.D3); // V->Dif[6]+=abs(D+V->D3); + v.Dif[7] += Math.Abs(D - v.D4); // V->Dif[7]+=abs(D-V->D4); + v.Dif[8] += Math.Abs(D + v.D4); // V->Dif[8]+=abs(D+V->D4); + v.Dif[9] += Math.Abs(D - UnpChannelDelta); // V->Dif[9]+=abs(D-UnpChannelDelta); + v.Dif[10] += Math.Abs(D + UnpChannelDelta); // V->Dif[10]+=abs(D+UnpChannelDelta); + + v.LastDelta = (byte)(Ch - v.LastChar); + UnpChannelDelta = v.LastDelta; + v.LastChar = Ch; // V->LastChar=Ch; + + if ((v.ByteCount & 0x1F) == 0) + { + int MinDif = v.Dif[0], + NumMinDif = 0; + v.Dif[0] = 0; // ->Dif[0]=0; + for (var I = 1; I < v.Dif.Length; I++) + { + if (v.Dif[I] < MinDif) + { + MinDif = v.Dif[I]; + NumMinDif = I; + } + v.Dif[I] = 0; + } + switch (NumMinDif) + { + case 1: + if (v.K1 >= -16) + { + v.K1--; // V->K1--; + } + break; + + case 2: + if (v.K1 < 16) + { + v.K1++; // V->K1++; + } + break; + + case 3: + if (v.K2 >= -16) + { + v.K2--; // V->K2--; + } + break; + + case 4: + if (v.K2 < 16) + { + v.K2++; // V->K2++; + } + break; + + case 5: + if (v.K3 >= -16) + { + v.K3--; + } + break; + + case 6: + if (v.K3 < 16) + { + v.K3++; + } + break; + + case 7: + if (v.K4 >= -16) + { + v.K4--; + } + break; + + case 8: + if (v.K4 < 16) + { + v.K4++; + } + break; + + case 9: + if (v.K5 >= -16) + { + v.K5--; + } + break; + + case 10: + if (v.K5 < 16) + { + v.K5++; + } + break; + } + } + return ((byte)Ch); } } diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack50.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack50.cs index a7cc9408..553e1896 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack50.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack50.cs @@ -1,954 +1,951 @@ -#if true +#if true using System; using System.Collections.Generic; using SharpCompress.Compressors.Rar.UnpackV1.Decode; -using size_t = System.UInt32; -using UnpackBlockHeader = SharpCompress.Compressors.Rar.UnpackV1; -namespace SharpCompress.Compressors.Rar.UnpackV1 +namespace SharpCompress.Compressors.Rar.UnpackV1; + +internal partial class Unpack { - internal partial class Unpack + // Maximum allowed number of compressed bits processed in quick mode. + private const int MAX_QUICK_DECODE_BITS = 10; + + // Maximum number of filters per entire data block. Must be at least + // twice more than MAX_PACK_FILTERS to store filters from two data blocks. + private const int MAX_UNPACK_FILTERS = 8192; + + // Maximum number of filters per entire data block for RAR3 unpack. + // Must be at least twice more than v3_MAX_PACK_FILTERS to store filters + // from two data blocks. + private const int MAX3_UNPACK_FILTERS = 8192; + + // Limit maximum number of channels in RAR3 delta filter to some reasonable + // value to prevent too slow processing of corrupt archives with invalid + // channels number. Must be equal or larger than v3_MAX_FILTER_CHANNELS. + // No need to provide it for RAR5, which uses only 5 bits to store channels. + private const int MAX3_UNPACK_CHANNELS = 1024; + + // Maximum size of single filter block. We restrict it to limit memory + // allocation. Must be equal or larger than MAX_ANALYZE_SIZE. + private const int MAX_FILTER_BLOCK_SIZE = 0x400000; + + // Write data in 4 MB or smaller blocks. Must not exceed PACK_MAX_WRITE, + // so we keep number of buffered filter in unpacker reasonable. + private const int UNPACK_MAX_WRITE = 0x400000; + + // Decode compressed bit fields to alphabet numbers. + // struct DecodeTable + // { + // // Real size of DecodeNum table. + // public uint MaxNum; + // + // // Left aligned start and upper limit codes defining code space + // // ranges for bit lengths. DecodeLen[BitLength-1] defines the start of + // // range for bit length and DecodeLen[BitLength] defines next code + // // after the end of range or in other words the upper limit code + // // for specified bit length. + // //uint DecodeLen[16]; + // public uint [] DecodeLen = new uint[16]; + // + // // Every item of this array contains the sum of all preceding items. + // // So it contains the start position in code list for every bit length. + // public uint DecodePos[16]; + // + // // Number of compressed bits processed in quick mode. + // // Must not exceed MAX_QUICK_DECODE_BITS. + // public uint QuickBits; + // + // // Translates compressed bits (up to QuickBits length) + // // to bit length in quick mode. + // public byte QuickLen[1< Filters + { + get { return filters; } + } - // Maximum size of single filter block. We restrict it to limit memory - // allocation. Must be equal or larger than MAX_ANALYZE_SIZE. - private const int MAX_FILTER_BLOCK_SIZE = 0x400000; + // TODO: make sure these aren't already somewhere else + public int BlockSize; + public int BlockBitSize; + public int BlockStart; + public int HeaderSize; + public bool LastBlockInFile; + public bool TablePresent; - // Write data in 4 MB or smaller blocks. Must not exceed PACK_MAX_WRITE, - // so we keep number of buffered filter in unpacker reasonable. - private const int UNPACK_MAX_WRITE = 0x400000; + public void Unpack5(bool Solid) + { + FileExtracted = true; - // Decode compressed bit fields to alphabet numbers. - // struct DecodeTable - // { - // // Real size of DecodeNum table. - // public uint MaxNum; - // - // // Left aligned start and upper limit codes defining code space - // // ranges for bit lengths. DecodeLen[BitLength-1] defines the start of - // // range for bit length and DecodeLen[BitLength] defines next code - // // after the end of range or in other words the upper limit code - // // for specified bit length. - // //uint DecodeLen[16]; - // public uint [] DecodeLen = new uint[16]; - // - // // Every item of this array contains the sum of all preceding items. - // // So it contains the start position in code list for every bit length. - // public uint DecodePos[16]; - // - // // Number of compressed bits processed in quick mode. - // // Must not exceed MAX_QUICK_DECODE_BITS. - // public uint QuickBits; - // - // // Translates compressed bits (up to QuickBits length) - // // to bit length in quick mode. - // public byte QuickLen[1< Filters - { - get { return filters; } - } - - // TODO: make sure these aren't already somewhere else - public int BlockSize; - public int BlockBitSize; - public int BlockStart; - public int HeaderSize; - public bool LastBlockInFile; - public bool TablePresent; - - public void Unpack5(bool Solid) - { - FileExtracted = true; - - if (!Suspended) + UnpInitData(Solid); + if (!UnpReadBuf()) { - UnpInitData(Solid); - if (!UnpReadBuf()) + return; + } + + // Check TablesRead5 to be sure that we read tables at least once + // regardless of current block header TablePresent flag. + // So we can safefly use these tables below. + if (!ReadBlockHeader() || !ReadTables() || !TablesRead5) + { + return; + } + } + + while (true) + { + UnpPtr &= MaxWinMask; + + if (Inp.InAddr >= ReadBorder) + { + var FileDone = false; + + // We use 'while', because for empty block containing only Huffman table, + // we'll be on the block border once again just after reading the table. + while ( + Inp.InAddr > BlockHeader.BlockStart + BlockHeader.BlockSize - 1 + || Inp.InAddr == BlockHeader.BlockStart + BlockHeader.BlockSize - 1 + && Inp.InBit >= BlockHeader.BlockBitSize + ) + { + if (BlockHeader.LastBlockInFile) + { + FileDone = true; + break; + } + if (!ReadBlockHeader() || !ReadTables()) + { + return; + } + } + if (FileDone || !UnpReadBuf()) + { + break; + } + } + + if ( + ((WriteBorder - UnpPtr) & MaxWinMask) < PackDef.MAX_LZ_MATCH + 3 + && WriteBorder != UnpPtr + ) + { + UnpWriteBuf(); + if (WrittenFileSize > DestUnpSize) { return; } - // Check TablesRead5 to be sure that we read tables at least once - // regardless of current block header TablePresent flag. - // So we can safefly use these tables below. - if (!ReadBlockHeader() || !ReadTables() || !TablesRead5) + if (Suspended) { + FileExtracted = false; return; } } - while (true) + //uint MainSlot=DecodeNumber(Inp,LD); + var MainSlot = this.DecodeNumber(LD); + if (MainSlot < 256) { - UnpPtr &= MaxWinMask; + // if (Fragmented) + // FragWindow[UnpPtr++]=(byte)MainSlot; + // else + Window[UnpPtr++] = (byte)MainSlot; + continue; + } + if (MainSlot >= 262) + { + var Length = SlotToLength(MainSlot - 262); - if (Inp.InAddr >= ReadBorder) + //uint DBits,Distance=1,DistSlot=DecodeNumber(Inp,&BlockTables.DD); + int DBits; + uint Distance = 1, + DistSlot = this.DecodeNumber(DD); + if (DistSlot < 4) { - bool FileDone = false; + DBits = 0; + Distance += DistSlot; + } + else + { + //DBits=DistSlot/2 - 1; + DBits = (int)((DistSlot / 2) - 1); + Distance += (2 | (DistSlot & 1)) << DBits; + } - // We use 'while', because for empty block containing only Huffman table, - // we'll be on the block border once again just after reading the table. - while ( - Inp.InAddr > BlockHeader.BlockStart + BlockHeader.BlockSize - 1 - || Inp.InAddr == BlockHeader.BlockStart + BlockHeader.BlockSize - 1 - && Inp.InBit >= BlockHeader.BlockBitSize - ) + if (DBits > 0) + { + if (DBits >= 4) { - if (BlockHeader.LastBlockInFile) + if (DBits > 4) { - FileDone = true; - break; + Distance += ((Inp.getbits() >> (36 - DBits)) << 4); + Inp.AddBits(DBits - 4); } - if (!ReadBlockHeader() || !ReadTables()) - { - return; - } - } - if (FileDone || !UnpReadBuf()) - { - break; - } - } - - if ( - ((WriteBorder - UnpPtr) & MaxWinMask) < PackDef.MAX_LZ_MATCH + 3 - && WriteBorder != UnpPtr - ) - { - UnpWriteBuf(); - if (WrittenFileSize > DestUnpSize) - { - return; - } - - if (Suspended) - { - FileExtracted = false; - return; - } - } - - //uint MainSlot=DecodeNumber(Inp,LD); - uint MainSlot = this.DecodeNumber(LD); - if (MainSlot < 256) - { - // if (Fragmented) - // FragWindow[UnpPtr++]=(byte)MainSlot; - // else - Window[UnpPtr++] = (byte)MainSlot; - continue; - } - if (MainSlot >= 262) - { - uint Length = SlotToLength(MainSlot - 262); - - //uint DBits,Distance=1,DistSlot=DecodeNumber(Inp,&BlockTables.DD); - int DBits; - uint Distance = 1, - DistSlot = this.DecodeNumber(DD); - if (DistSlot < 4) - { - DBits = 0; - Distance += DistSlot; + //uint LowDist=DecodeNumber(Inp,&BlockTables.LDD); + var LowDist = this.DecodeNumber(LDD); + Distance += LowDist; } else { - //DBits=DistSlot/2 - 1; - DBits = (int)(DistSlot / 2 - 1); - Distance += (2 | (DistSlot & 1)) << DBits; + Distance += Inp.getbits() >> (32 - DBits); + Inp.AddBits(DBits); } + } - if (DBits > 0) - { - if (DBits >= 4) - { - if (DBits > 4) - { - Distance += ((Inp.getbits() >> (36 - DBits)) << 4); - Inp.AddBits(DBits - 4); - } - //uint LowDist=DecodeNumber(Inp,&BlockTables.LDD); - uint LowDist = this.DecodeNumber(LDD); - Distance += LowDist; - } - else - { - Distance += Inp.getbits() >> (32 - DBits); - Inp.AddBits(DBits); - } - } - - if (Distance > 0x100) + if (Distance > 0x100) + { + Length++; + if (Distance > 0x2000) { Length++; - if (Distance > 0x2000) + if (Distance > 0x40000) { Length++; - if (Distance > 0x40000) - { - Length++; - } } } - - InsertOldDist(Distance); - LastLength = Length; - // if (Fragmented) - // FragWindow.CopyString(Length,Distance,UnpPtr,MaxWinMask); - // else - CopyString(Length, Distance); - continue; } - if (MainSlot == 256) - { - UnpackFilter Filter = new UnpackFilter(); - if (!ReadFilter(Filter) || !AddFilter(Filter)) - { - break; - } - continue; - } - if (MainSlot == 257) - { - if (LastLength != 0) - // if (Fragmented) - // FragWindow.CopyString(LastLength,OldDist[0],UnpPtr,MaxWinMask); - // else - //CopyString(LastLength,OldDist[0]); - { - CopyString(LastLength, OldDistN(0)); - } - - continue; - } - if (MainSlot < 262) - { - //uint DistNum=MainSlot-258; - int DistNum = (int)(MainSlot - 258); - //uint Distance=OldDist[DistNum]; - uint Distance = OldDistN(DistNum); - //for (uint I=DistNum;I>0;I--) - for (int I = DistNum; I > 0; I--) - //OldDistN[I]=OldDistN(I-1); - { - SetOldDistN(I, OldDistN(I - 1)); - } - - //OldDistN[0]=Distance; - SetOldDistN(0, Distance); - - uint LengthSlot = this.DecodeNumber(RD); - uint Length = SlotToLength(LengthSlot); - LastLength = Length; - // if (Fragmented) - // FragWindow.CopyString(Length,Distance,UnpPtr,MaxWinMask); - // else - CopyString(Length, Distance); - continue; - } + InsertOldDist(Distance); + LastLength = Length; + // if (Fragmented) + // FragWindow.CopyString(Length,Distance,UnpPtr,MaxWinMask); + // else + CopyString(Length, Distance); + continue; + } + if (MainSlot == 256) + { + var Filter = new UnpackFilter(); + if (!ReadFilter(Filter) || !AddFilter(Filter)) + { + break; + } + + continue; + } + if (MainSlot == 257) + { + if (LastLength != 0) + // if (Fragmented) + // FragWindow.CopyString(LastLength,OldDist[0],UnpPtr,MaxWinMask); + // else + //CopyString(LastLength,OldDist[0]); + { + CopyString(LastLength, OldDistN(0)); + } + + continue; + } + if (MainSlot < 262) + { + //uint DistNum=MainSlot-258; + var DistNum = (int)(MainSlot - 258); + //uint Distance=OldDist[DistNum]; + var Distance = OldDistN(DistNum); + //for (uint I=DistNum;I>0;I--) + for (var I = DistNum; I > 0; I--) + //OldDistN[I]=OldDistN(I-1); + { + SetOldDistN(I, OldDistN(I - 1)); + } + + //OldDistN[0]=Distance; + SetOldDistN(0, Distance); + + var LengthSlot = this.DecodeNumber(RD); + var Length = SlotToLength(LengthSlot); + LastLength = Length; + // if (Fragmented) + // FragWindow.CopyString(Length,Distance,UnpPtr,MaxWinMask); + // else + CopyString(Length, Distance); + continue; + } + } + UnpWriteBuf(); + } + + private uint ReadFilterData() + { + var ByteCount = (Inp.fgetbits() >> 14) + 1; + Inp.AddBits(2); + + uint Data = 0; + //for (uint I=0;I> 8) << (I * 8); + Inp.AddBits(8); + } + return Data; + } + + private bool ReadFilter(UnpackFilter Filter) + { + if (!Inp.ExternalBuffer && Inp.InAddr > ReadTop - 16) + { + if (!UnpReadBuf()) + { + return false; } - UnpWriteBuf(); } - private uint ReadFilterData() + Filter.uBlockStart = ReadFilterData(); + Filter.uBlockLength = ReadFilterData(); + if (Filter.BlockLength > MAX_FILTER_BLOCK_SIZE) { - uint ByteCount = (Inp.fgetbits() >> 14) + 1; - Inp.AddBits(2); - - uint Data = 0; - //for (uint I=0;I> 8) << (I * 8); - Inp.AddBits(8); - } - return Data; + Filter.BlockLength = 0; } - private bool ReadFilter(UnpackFilter Filter) + //Filter.Type=Inp.fgetbits()>>13; + Filter.Type = (byte)(Inp.fgetbits() >> 13); + Inp.faddbits(3); + + if (Filter.Type == (byte)FilterType.FILTER_DELTA) { - if (!Inp.ExternalBuffer && Inp.InAddr > ReadTop - 16) - { - if (!UnpReadBuf()) - { - return false; - } - } - - Filter.uBlockStart = ReadFilterData(); - Filter.uBlockLength = ReadFilterData(); - if (Filter.BlockLength > MAX_FILTER_BLOCK_SIZE) - { - Filter.BlockLength = 0; - } - - //Filter.Type=Inp.fgetbits()>>13; - Filter.Type = (byte)(Inp.fgetbits() >> 13); - Inp.faddbits(3); - - if (Filter.Type == (byte)FilterType.FILTER_DELTA) - { - //Filter.Channels=(Inp.fgetbits()>>11)+1; - Filter.Channels = (byte)((Inp.fgetbits() >> 11) + 1); - Inp.faddbits(5); - } - - return true; + //Filter.Channels=(Inp.fgetbits()>>11)+1; + Filter.Channels = (byte)((Inp.fgetbits() >> 11) + 1); + Inp.faddbits(5); } - private bool AddFilter(UnpackFilter Filter) + return true; + } + + private bool AddFilter(UnpackFilter Filter) + { + if (Filters.Count >= MAX_UNPACK_FILTERS) { + UnpWriteBuf(); // Write data, apply and flush filters. if (Filters.Count >= MAX_UNPACK_FILTERS) { - UnpWriteBuf(); // Write data, apply and flush filters. - if (Filters.Count >= MAX_UNPACK_FILTERS) - { - InitFilters(); // Still too many filters, prevent excessive memory use. - } - } - - // If distance to filter start is that large that due to circular dictionary - // mode now it points to old not written yet data, then we set 'NextWindow' - // flag and process this filter only after processing that older data. - Filter.NextWindow = - WrPtr != UnpPtr && ((WrPtr - UnpPtr) & MaxWinMask) <= Filter.BlockStart; - - Filter.uBlockStart = (uint)((Filter.BlockStart + UnpPtr) & MaxWinMask); - Filters.Add(Filter); - return true; - } - - private bool UnpReadBuf() - { - int DataSize = ReadTop - Inp.InAddr; // Data left to process. - if (DataSize < 0) - { - return false; - } - - BlockHeader.BlockSize -= Inp.InAddr - BlockHeader.BlockStart; - if (Inp.InAddr > MAX_SIZE / 2) - { - // If we already processed more than half of buffer, let's move - // remaining data into beginning to free more space for new data - // and ensure that calling function does not cross the buffer border - // even if we did not read anything here. Also it ensures that read size - // is not less than CRYPT_BLOCK_SIZE, so we can align it without risk - // to make it zero. - if (DataSize > 0) - //memmove(Inp.InBuf,Inp.InBuf+Inp.InAddr,DataSize); - { - Array.Copy(InBuf, inAddr, InBuf, 0, DataSize); - } - - // TODO: perf - //Buffer.BlockCopy(InBuf, inAddr, InBuf, 0, DataSize); - - Inp.InAddr = 0; - ReadTop = DataSize; - } - else - { - DataSize = ReadTop; - } - - int ReadCode = 0; - if (MAX_SIZE != DataSize) - //ReadCode=UnpIO->UnpRead(Inp.InBuf+DataSize,BitInput.MAX_SIZE-DataSize); - { - ReadCode = readStream.Read(InBuf, DataSize, MAX_SIZE - DataSize); - } - - if (ReadCode > 0) // Can be also -1. - { - ReadTop += ReadCode; - } - - ReadBorder = ReadTop - 30; - BlockHeader.BlockStart = Inp.InAddr; - if (BlockHeader.BlockSize != -1) // '-1' means not defined yet. - { - // We may need to quit from main extraction loop and read new block header - // and trees earlier than data in input buffer ends. - ReadBorder = Math.Min( - ReadBorder, - BlockHeader.BlockStart + BlockHeader.BlockSize - 1 - ); - } - return ReadCode != -1; - } - - //? - // void UnpWriteBuf() - // { - // size_t WrittenBorder=WrPtr; - // size_t FullWriteSize=(UnpPtr-WrittenBorder)&MaxWinMask; - // size_t WriteSizeLeft=FullWriteSize; - // bool NotAllFiltersProcessed=false; - // for (size_t I=0;IType==FilterType.FILTER_NONE) - // continue; - // if (flt->NextWindow) - // { - // // Here we skip filters which have block start in current data range - // // due to address wrap around in circular dictionary, but actually - // // belong to next dictionary block. If such filter start position - // // is included to current write range, then we reset 'NextWindow' flag. - // // In fact we can reset it even without such check, because current - // // implementation seems to guarantee 'NextWindow' flag reset after - // // buffer writing for all existing filters. But let's keep this check - // // just in case. Compressor guarantees that distance between - // // filter block start and filter storing position cannot exceed - // // the dictionary size. So if we covered the filter block start with - // // our write here, we can safely assume that filter is applicable - // // to next block on no further wrap arounds is possible. - // if (((flt->BlockStart-WrPtr)&MaxWinMask)<=FullWriteSize) - // flt->NextWindow=false; - // continue; - // } - // uint BlockStart=flt->BlockStart; - // uint BlockLength=flt->BlockLength; - // if (((BlockStart-WrittenBorder)&MaxWinMask)0) // We set it to 0 also for invalid filters. - // { - // uint BlockEnd=(BlockStart+BlockLength)&MaxWinMask; - // - // FilterSrcMemory.Alloc(BlockLength); - // byte *Mem=&FilterSrcMemory[0]; - // if (BlockStartUnpWrite(OutMem,BlockLength); - // - // UnpSomeRead=true; - // WrittenFileSize+=BlockLength; - // WrittenBorder=BlockEnd; - // WriteSizeLeft=(UnpPtr-WrittenBorder)&MaxWinMask; - // } - // } - // else - // { - // // Current filter intersects the window write border, so we adjust - // // the window border to process this filter next time, not now. - // WrPtr=WrittenBorder; - // - // // Since Filter start position can only increase, we quit processing - // // all following filters for this data block and reset 'NextWindow' - // // flag for them. - // for (size_t J=I;JType!=FilterType.FILTER_NONE) - // flt->NextWindow=false; - // } - // - // // Do not write data left after current filter now. - // NotAllFiltersProcessed=true; - // break; - // } - // } - // } - // - // // Remove processed filters from queue. - // size_t EmptyCount=0; - // for (size_t I=0;I0) - // Filters[I-EmptyCount]=Filters[I]; - // if (Filters[I].Type==FilterType.FILTER_NONE) - // EmptyCount++; - // } - // if (EmptyCount>0) - // Filters.Alloc(Filters.Size()-EmptyCount); - // - // if (!NotAllFiltersProcessed) // Only if all filters are processed. - // { - // // Write data left after last filter. - // UnpWriteArea(WrittenBorder,UnpPtr); - // WrPtr=UnpPtr; - // } - // - // // We prefer to write data in blocks not exceeding UNPACK_MAX_WRITE - // // instead of potentially huge MaxWinSize blocks. It also allows us - // // to keep the size of Filters array reasonable. - // WriteBorder=(UnpPtr+Min(MaxWinSize,UNPACK_MAX_WRITE))&MaxWinMask; - // - // // Choose the nearest among WriteBorder and WrPtr actual written border. - // // If border is equal to UnpPtr, it means that we have MaxWinSize data ahead. - // if (WriteBorder==UnpPtr || - // WrPtr!=UnpPtr && ((WrPtr-UnpPtr)&MaxWinMask)<((WriteBorder-UnpPtr)&MaxWinMask)) - // WriteBorder=WrPtr; - // } - - - // unused - //x byte* ApplyFilter(byte *Data,uint DataSize,UnpackFilter *Flt) - // byte[] ApplyFilter(byte []Data, uint DataSize, UnpackFilter Flt) - // { - // //x byte *SrcData=Data; - // byte []SrcData=Data; - // switch(Flt.Type) - // { - // case (byte)FilterType.FILTER_E8: - // case (byte)FilterType.FILTER_E8E9: - // { - // uint FileOffset=(uint)WrittenFileSize; - // - // const uint FileSize=0x1000000; - // byte CmpByte2=Flt.Type==(byte)FilterType.FILTER_E8E9 ? (byte)0xe9 : (byte)0xe8; - // // DataSize is unsigned, so we use "CurPos+4" and not "DataSize-4" - // // to avoid overflow for DataSize<4. - // for (uint CurPos=0;CurPos+4=0 - // RawPut4(Addr+FileSize,Data); - // } - // else - // if (((Addr-FileSize) & 0x80000000)!=0) // Addr>8); - // D[2]=(byte)(Offset>>16); - // } - // } - // } - // return SrcData; - // case (byte)FilterType.FILTER_DELTA: - // { - // // Unlike RAR3, we do not need to reject excessive channel - // // values here, since RAR5 uses only 5 bits to store channel. - // uint Channels=Flt->Channels,SrcPos=0; - // - // FilterDstMemory.Alloc(DataSize); - // byte *DstData=&FilterDstMemory[0]; - // - // // Bytes from same channels are grouped to continual data blocks, - // // so we need to place them back to their interleaving positions. - // for (uint CurChannel=0;CurChannel0) - //// { - //// size_t BlockSize=FragWindow.GetBlockSize(StartPtr,SizeToWrite); - //// UnpWriteData(&FragWindow[StartPtr],BlockSize); - //// SizeToWrite-=BlockSize; - //// StartPtr=(StartPtr+BlockSize) & MaxWinMask; - //// } - //// } - //// else - // if (EndPtr=DestUnpSize) - // return; - // size_t WriteSize=Size; - // long LeftToWrite=DestUnpSize-WrittenFileSize; - // if ((long)WriteSize>LeftToWrite) - // WriteSize=(size_t)LeftToWrite; - // UnpIO->UnpWrite(Data,WriteSize); - // WrittenFileSize+=Size; - // } - - private void UnpInitData50(bool Solid) - { - if (!Solid) - { - TablesRead5 = false; + InitFilters(); // Still too many filters, prevent excessive memory use. } } - private bool ReadBlockHeader() - { - Header.HeaderSize = 0; + // If distance to filter start is that large that due to circular dictionary + // mode now it points to old not written yet data, then we set 'NextWindow' + // flag and process this filter only after processing that older data. + Filter.NextWindow = + WrPtr != UnpPtr && ((WrPtr - UnpPtr) & MaxWinMask) <= Filter.BlockStart; - if (!Inp.ExternalBuffer && Inp.InAddr > ReadTop - 7) - { - if (!UnpReadBuf()) - { - return false; - } - } - - //Inp.faddbits((8-Inp.InBit)&7); - Inp.faddbits((uint)((8 - Inp.InBit) & 7)); - - byte BlockFlags = (byte)(Inp.fgetbits() >> 8); - Inp.faddbits(8); - //uint ByteCount=((BlockFlags>>3)&3)+1; // Block size byte count. - uint ByteCount = (uint)(((BlockFlags >> 3) & 3) + 1); // Block size byte count. - - if (ByteCount == 4) - { - return false; - } - - //Header.HeaderSize=2+ByteCount; - Header.HeaderSize = (int)(2 + ByteCount); - - Header.BlockBitSize = (BlockFlags & 7) + 1; - - byte SavedCheckSum = (byte)(Inp.fgetbits() >> 8); - Inp.faddbits(8); - - int BlockSize = 0; - //for (uint I=0;I>8)<<(I*8); - BlockSize += (int)(Inp.fgetbits() >> 8) << (I * 8); - Inp.AddBits(8); - } - - Header.BlockSize = BlockSize; - byte CheckSum = (byte)( - 0x5a ^ BlockFlags ^ BlockSize ^ (BlockSize >> 8) ^ (BlockSize >> 16) - ); - if (CheckSum != SavedCheckSum) - { - return false; - } - - Header.BlockStart = Inp.InAddr; - ReadBorder = Math.Min(ReadBorder, Header.BlockStart + Header.BlockSize - 1); - - Header.LastBlockInFile = (BlockFlags & 0x40) != 0; - Header.TablePresent = (BlockFlags & 0x80) != 0; - return true; - } - - //? - // bool ReadTables(BitInput Inp, ref UnpackBlockHeader Header, ref UnpackBlockTables Tables) - // { - // if (!Header.TablePresent) - // return true; - // - // if (!Inp.ExternalBuffer && Inp.InAddr>ReadTop-25) - // if (!UnpReadBuf()) - // return false; - // - // byte BitLength[BC]; - // for (uint I=0;I> 12); - // Inp.faddbits(4); - // if (Length==15) - // { - // uint ZeroCount=(byte)(Inp.fgetbits() >> 12); - // Inp.faddbits(4); - // if (ZeroCount==0) - // BitLength[I]=15; - // else - // { - // ZeroCount+=2; - // while (ZeroCount-- > 0 && IReadTop-5) - // if (!UnpReadBuf()) - // return false; - // uint Number=DecodeNumber(Inp,&Tables.BD); - // if (Number<16) - // { - // Table[I]=Number; - // I++; - // } - // else - // if (Number<18) - // { - // uint N; - // if (Number==16) - // { - // N=(Inp.fgetbits() >> 13)+3; - // Inp.faddbits(3); - // } - // else - // { - // N=(Inp.fgetbits() >> 9)+11; - // Inp.faddbits(7); - // } - // if (I==0) - // { - // // We cannot have "repeat previous" code at the first position. - // // Multiple such codes would shift Inp position without changing I, - // // which can lead to reading beyond of Inp boundary in mutithreading - // // mode, where Inp.ExternalBuffer disables bounds check and we just - // // reserve a lot of buffer space to not need such check normally. - // return false; - // } - // else - // while (N-- > 0 && I> 13)+3; - // Inp.faddbits(3); - // } - // else - // { - // N=(Inp.fgetbits() >> 9)+11; - // Inp.faddbits(7); - // } - // while (N-- > 0 && IReadTop) - // return false; - // MakeDecodeTables(&Table[0],&Tables.LD,NC); - // MakeDecodeTables(&Table[NC],&Tables.DD,DC); - // MakeDecodeTables(&Table[NC+DC],&Tables.LDD,LDC); - // MakeDecodeTables(&Table[NC+DC+LDC],&Tables.RD,RC); - // return true; - // } - - //? - // void InitFilters() - // { - // Filters.SoftReset(); - // } + Filter.uBlockStart = (uint)((Filter.BlockStart + UnpPtr) & MaxWinMask); + Filters.Add(Filter); + return true; } + + private bool UnpReadBuf() + { + var DataSize = ReadTop - Inp.InAddr; // Data left to process. + if (DataSize < 0) + { + return false; + } + + BlockHeader.BlockSize -= Inp.InAddr - BlockHeader.BlockStart; + if (Inp.InAddr > MAX_SIZE / 2) + { + // If we already processed more than half of buffer, let's move + // remaining data into beginning to free more space for new data + // and ensure that calling function does not cross the buffer border + // even if we did not read anything here. Also it ensures that read size + // is not less than CRYPT_BLOCK_SIZE, so we can align it without risk + // to make it zero. + if (DataSize > 0) + //memmove(Inp.InBuf,Inp.InBuf+Inp.InAddr,DataSize); + { + Array.Copy(InBuf, inAddr, InBuf, 0, DataSize); + } + + // TODO: perf + //Buffer.BlockCopy(InBuf, inAddr, InBuf, 0, DataSize); + + Inp.InAddr = 0; + ReadTop = DataSize; + } + else + { + DataSize = ReadTop; + } + + var ReadCode = 0; + if (MAX_SIZE != DataSize) + //ReadCode=UnpIO->UnpRead(Inp.InBuf+DataSize,BitInput.MAX_SIZE-DataSize); + { + ReadCode = readStream.Read(InBuf, DataSize, MAX_SIZE - DataSize); + } + + if (ReadCode > 0) // Can be also -1. + { + ReadTop += ReadCode; + } + + ReadBorder = ReadTop - 30; + BlockHeader.BlockStart = Inp.InAddr; + if (BlockHeader.BlockSize != -1) // '-1' means not defined yet. + { + // We may need to quit from main extraction loop and read new block header + // and trees earlier than data in input buffer ends. + ReadBorder = Math.Min( + ReadBorder, + BlockHeader.BlockStart + BlockHeader.BlockSize - 1 + ); + } + return ReadCode != -1; + } + + //? + // void UnpWriteBuf() + // { + // size_t WrittenBorder=WrPtr; + // size_t FullWriteSize=(UnpPtr-WrittenBorder)&MaxWinMask; + // size_t WriteSizeLeft=FullWriteSize; + // bool NotAllFiltersProcessed=false; + // for (size_t I=0;IType==FilterType.FILTER_NONE) + // continue; + // if (flt->NextWindow) + // { + // // Here we skip filters which have block start in current data range + // // due to address wrap around in circular dictionary, but actually + // // belong to next dictionary block. If such filter start position + // // is included to current write range, then we reset 'NextWindow' flag. + // // In fact we can reset it even without such check, because current + // // implementation seems to guarantee 'NextWindow' flag reset after + // // buffer writing for all existing filters. But let's keep this check + // // just in case. Compressor guarantees that distance between + // // filter block start and filter storing position cannot exceed + // // the dictionary size. So if we covered the filter block start with + // // our write here, we can safely assume that filter is applicable + // // to next block on no further wrap arounds is possible. + // if (((flt->BlockStart-WrPtr)&MaxWinMask)<=FullWriteSize) + // flt->NextWindow=false; + // continue; + // } + // uint BlockStart=flt->BlockStart; + // uint BlockLength=flt->BlockLength; + // if (((BlockStart-WrittenBorder)&MaxWinMask)0) // We set it to 0 also for invalid filters. + // { + // uint BlockEnd=(BlockStart+BlockLength)&MaxWinMask; + // + // FilterSrcMemory.Alloc(BlockLength); + // byte *Mem=&FilterSrcMemory[0]; + // if (BlockStartUnpWrite(OutMem,BlockLength); + // + // UnpSomeRead=true; + // WrittenFileSize+=BlockLength; + // WrittenBorder=BlockEnd; + // WriteSizeLeft=(UnpPtr-WrittenBorder)&MaxWinMask; + // } + // } + // else + // { + // // Current filter intersects the window write border, so we adjust + // // the window border to process this filter next time, not now. + // WrPtr=WrittenBorder; + // + // // Since Filter start position can only increase, we quit processing + // // all following filters for this data block and reset 'NextWindow' + // // flag for them. + // for (size_t J=I;JType!=FilterType.FILTER_NONE) + // flt->NextWindow=false; + // } + // + // // Do not write data left after current filter now. + // NotAllFiltersProcessed=true; + // break; + // } + // } + // } + // + // // Remove processed filters from queue. + // size_t EmptyCount=0; + // for (size_t I=0;I0) + // Filters[I-EmptyCount]=Filters[I]; + // if (Filters[I].Type==FilterType.FILTER_NONE) + // EmptyCount++; + // } + // if (EmptyCount>0) + // Filters.Alloc(Filters.Size()-EmptyCount); + // + // if (!NotAllFiltersProcessed) // Only if all filters are processed. + // { + // // Write data left after last filter. + // UnpWriteArea(WrittenBorder,UnpPtr); + // WrPtr=UnpPtr; + // } + // + // // We prefer to write data in blocks not exceeding UNPACK_MAX_WRITE + // // instead of potentially huge MaxWinSize blocks. It also allows us + // // to keep the size of Filters array reasonable. + // WriteBorder=(UnpPtr+Min(MaxWinSize,UNPACK_MAX_WRITE))&MaxWinMask; + // + // // Choose the nearest among WriteBorder and WrPtr actual written border. + // // If border is equal to UnpPtr, it means that we have MaxWinSize data ahead. + // if (WriteBorder==UnpPtr || + // WrPtr!=UnpPtr && ((WrPtr-UnpPtr)&MaxWinMask)<((WriteBorder-UnpPtr)&MaxWinMask)) + // WriteBorder=WrPtr; + // } + + + // unused + //x byte* ApplyFilter(byte *Data,uint DataSize,UnpackFilter *Flt) + // byte[] ApplyFilter(byte []Data, uint DataSize, UnpackFilter Flt) + // { + // //x byte *SrcData=Data; + // byte []SrcData=Data; + // switch(Flt.Type) + // { + // case (byte)FilterType.FILTER_E8: + // case (byte)FilterType.FILTER_E8E9: + // { + // uint FileOffset=(uint)WrittenFileSize; + // + // const uint FileSize=0x1000000; + // byte CmpByte2=Flt.Type==(byte)FilterType.FILTER_E8E9 ? (byte)0xe9 : (byte)0xe8; + // // DataSize is unsigned, so we use "CurPos+4" and not "DataSize-4" + // // to avoid overflow for DataSize<4. + // for (uint CurPos=0;CurPos+4=0 + // RawPut4(Addr+FileSize,Data); + // } + // else + // if (((Addr-FileSize) & 0x80000000)!=0) // Addr>8); + // D[2]=(byte)(Offset>>16); + // } + // } + // } + // return SrcData; + // case (byte)FilterType.FILTER_DELTA: + // { + // // Unlike RAR3, we do not need to reject excessive channel + // // values here, since RAR5 uses only 5 bits to store channel. + // uint Channels=Flt->Channels,SrcPos=0; + // + // FilterDstMemory.Alloc(DataSize); + // byte *DstData=&FilterDstMemory[0]; + // + // // Bytes from same channels are grouped to continual data blocks, + // // so we need to place them back to their interleaving positions. + // for (uint CurChannel=0;CurChannel0) + //// { + //// size_t BlockSize=FragWindow.GetBlockSize(StartPtr,SizeToWrite); + //// UnpWriteData(&FragWindow[StartPtr],BlockSize); + //// SizeToWrite-=BlockSize; + //// StartPtr=(StartPtr+BlockSize) & MaxWinMask; + //// } + //// } + //// else + // if (EndPtr=DestUnpSize) + // return; + // size_t WriteSize=Size; + // long LeftToWrite=DestUnpSize-WrittenFileSize; + // if ((long)WriteSize>LeftToWrite) + // WriteSize=(size_t)LeftToWrite; + // UnpIO->UnpWrite(Data,WriteSize); + // WrittenFileSize+=Size; + // } + + private void UnpInitData50(bool Solid) + { + if (!Solid) + { + TablesRead5 = false; + } + } + + private bool ReadBlockHeader() + { + Header.HeaderSize = 0; + + if (!Inp.ExternalBuffer && Inp.InAddr > ReadTop - 7) + { + if (!UnpReadBuf()) + { + return false; + } + } + + //Inp.faddbits((8-Inp.InBit)&7); + Inp.faddbits((uint)((8 - Inp.InBit) & 7)); + + var BlockFlags = (byte)(Inp.fgetbits() >> 8); + Inp.faddbits(8); + //uint ByteCount=((BlockFlags>>3)&3)+1; // Block size byte count. + var ByteCount = (uint)(((BlockFlags >> 3) & 3) + 1); // Block size byte count. + + if (ByteCount == 4) + { + return false; + } + + //Header.HeaderSize=2+ByteCount; + Header.HeaderSize = (int)(2 + ByteCount); + + Header.BlockBitSize = (BlockFlags & 7) + 1; + + var SavedCheckSum = (byte)(Inp.fgetbits() >> 8); + Inp.faddbits(8); + + var BlockSize = 0; + //for (uint I=0;I>8)<<(I*8); + BlockSize += (int)(Inp.fgetbits() >> 8) << (I * 8); + Inp.AddBits(8); + } + + Header.BlockSize = BlockSize; + var CheckSum = (byte)( + 0x5a ^ BlockFlags ^ BlockSize ^ (BlockSize >> 8) ^ (BlockSize >> 16) + ); + if (CheckSum != SavedCheckSum) + { + return false; + } + + Header.BlockStart = Inp.InAddr; + ReadBorder = Math.Min(ReadBorder, Header.BlockStart + Header.BlockSize - 1); + + Header.LastBlockInFile = (BlockFlags & 0x40) != 0; + Header.TablePresent = (BlockFlags & 0x80) != 0; + return true; + } + + //? + // bool ReadTables(BitInput Inp, ref UnpackBlockHeader Header, ref UnpackBlockTables Tables) + // { + // if (!Header.TablePresent) + // return true; + // + // if (!Inp.ExternalBuffer && Inp.InAddr>ReadTop-25) + // if (!UnpReadBuf()) + // return false; + // + // byte BitLength[BC]; + // for (uint I=0;I> 12); + // Inp.faddbits(4); + // if (Length==15) + // { + // uint ZeroCount=(byte)(Inp.fgetbits() >> 12); + // Inp.faddbits(4); + // if (ZeroCount==0) + // BitLength[I]=15; + // else + // { + // ZeroCount+=2; + // while (ZeroCount-- > 0 && IReadTop-5) + // if (!UnpReadBuf()) + // return false; + // uint Number=DecodeNumber(Inp,&Tables.BD); + // if (Number<16) + // { + // Table[I]=Number; + // I++; + // } + // else + // if (Number<18) + // { + // uint N; + // if (Number==16) + // { + // N=(Inp.fgetbits() >> 13)+3; + // Inp.faddbits(3); + // } + // else + // { + // N=(Inp.fgetbits() >> 9)+11; + // Inp.faddbits(7); + // } + // if (I==0) + // { + // // We cannot have "repeat previous" code at the first position. + // // Multiple such codes would shift Inp position without changing I, + // // which can lead to reading beyond of Inp boundary in mutithreading + // // mode, where Inp.ExternalBuffer disables bounds check and we just + // // reserve a lot of buffer space to not need such check normally. + // return false; + // } + // else + // while (N-- > 0 && I> 13)+3; + // Inp.faddbits(3); + // } + // else + // { + // N=(Inp.fgetbits() >> 9)+11; + // Inp.faddbits(7); + // } + // while (N-- > 0 && IReadTop) + // return false; + // MakeDecodeTables(&Table[0],&Tables.LD,NC); + // MakeDecodeTables(&Table[NC],&Tables.DD,DC); + // MakeDecodeTables(&Table[NC+DC],&Tables.LDD,LDC); + // MakeDecodeTables(&Table[NC+DC+LDC],&Tables.RD,RC); + // return true; + // } + + //? + // void InitFilters() + // { + // Filters.SoftReset(); + // } } #endif diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/UnpackFilter.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/UnpackFilter.cs index 82fb4e5e..adfa6856 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/UnpackFilter.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/UnpackFilter.cs @@ -1,41 +1,40 @@ using SharpCompress.Compressors.Rar.VM; -namespace SharpCompress.Compressors.Rar.UnpackV1 +namespace SharpCompress.Compressors.Rar.UnpackV1; + +internal class UnpackFilter { - internal class UnpackFilter + public byte Type; + public byte Channels; + + internal UnpackFilter() { - public byte Type; - public byte Channels; - - internal UnpackFilter() - { - Program = new VMPreparedProgram(); - } - - // TODO uint - internal uint uBlockStart - { - get { return (uint)BlockStart; } - set { BlockStart = (int)value; } - } - internal uint uBlockLength - { - get { return (uint)BlockLength; } - set { BlockLength = (int)value; } - } - - internal int BlockStart { get; set; } - - internal int BlockLength { get; set; } - - internal int ExecCount { get; set; } - - internal bool NextWindow { get; set; } - - // position of parent filter in Filters array used as prototype for filter - // in PrgStack array. Not defined for filters in Filters array. - internal int ParentFilter { get; set; } - - internal VMPreparedProgram Program { get; set; } + Program = new VMPreparedProgram(); } + + // TODO uint + internal uint uBlockStart + { + get { return (uint)BlockStart; } + set { BlockStart = (int)value; } + } + internal uint uBlockLength + { + get { return (uint)BlockLength; } + set { BlockLength = (int)value; } + } + + internal int BlockStart { get; set; } + + internal int BlockLength { get; set; } + + internal int ExecCount { get; set; } + + internal bool NextWindow { get; set; } + + // position of parent filter in Filters array used as prototype for filter + // in PrgStack array. Not defined for filters in Filters array. + internal int ParentFilter { get; set; } + + internal VMPreparedProgram Program { get; set; } } diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/UnpackInline.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/UnpackInline.cs index c49007f7..8148b250 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/UnpackInline.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/UnpackInline.cs @@ -1,30 +1,29 @@ -namespace SharpCompress.Compressors.Rar.UnpackV1 -{ - internal partial class Unpack - { - private uint SlotToLength(uint Slot) - { - //uint LBits,Length=2; - int LBits; - uint Length = 2; - if (Slot < 8) - { - LBits = 0; - Length += Slot; - } - else - { - //LBits=Slot/4-1; - LBits = (int)(Slot / 4 - 1); - Length += (4 | (Slot & 3)) << LBits; - } +namespace SharpCompress.Compressors.Rar.UnpackV1; - if (LBits > 0) - { - Length += getbits() >> (16 - LBits); - AddBits(LBits); - } - return Length; +internal partial class Unpack +{ + private uint SlotToLength(uint Slot) + { + //uint LBits,Length=2; + int LBits; + uint Length = 2; + if (Slot < 8) + { + LBits = 0; + Length += Slot; } + else + { + //LBits=Slot/4-1; + LBits = (int)((Slot / 4) - 1); + Length += (4 | (Slot & 3)) << LBits; + } + + if (LBits > 0) + { + Length += getbits() >> (16 - LBits); + AddBits(LBits); + } + return Length; } } diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/UnpackUtility.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/UnpackUtility.cs index b00ffcfa..1db60c89 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/UnpackUtility.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/UnpackUtility.cs @@ -1,233 +1,232 @@ -using System; +using System; using SharpCompress.Compressors.Rar.VM; -namespace SharpCompress.Compressors.Rar.UnpackV1 +namespace SharpCompress.Compressors.Rar.UnpackV1; + +internal static class UnpackUtility { - internal static class UnpackUtility + //!!! TODO rename methods + internal static uint DecodeNumber(this BitInput input, Decode.Decode dec) { - //!!! TODO rename methods - internal static uint DecodeNumber(this BitInput input, Decode.Decode dec) - { - return (uint)input.decodeNumber(dec); - } + return (uint)input.decodeNumber(dec); + } - internal static int decodeNumber(this BitInput input, Decode.Decode dec) - { - int bits; - long bitField = input.GetBits() & 0xfffe; + internal static int decodeNumber(this BitInput input, Decode.Decode dec) + { + int bits; + long bitField = input.GetBits() & 0xfffe; - // if (bitField < dec.getDecodeLen()[8]) { - // if (bitField < dec.getDecodeLen()[4]) { - // if (bitField < dec.getDecodeLen()[2]) { - // if (bitField < dec.getDecodeLen()[1]) { - // bits = 1; - // } else { - // bits = 2; - // } - // } else { - // if (bitField < dec.getDecodeLen()[3]) { - // bits = 3; - // } else { - // bits = 4; - // } - // } - // } else { - // if (bitField < dec.getDecodeLen()[6]) { - // if (bitField < dec.getDecodeLen()[5]) - // bits = 5; - // else - // bits = 6; - // } else { - // if (bitField < dec.getDecodeLen()[7]) { - // bits = 7; - // } else { - // bits = 8; - // } - // } - // } - // } else { - // if (bitField < dec.getDecodeLen()[12]) { - // if (bitField < dec.getDecodeLen()[10]) - // if (bitField < dec.getDecodeLen()[9]) - // bits = 9; - // else - // bits = 10; - // else if (bitField < dec.getDecodeLen()[11]) - // bits = 11; - // else - // bits = 12; - // } else { - // if (bitField < dec.getDecodeLen()[14]) { - // if (bitField < dec.getDecodeLen()[13]) { - // bits = 13; - // } else { - // bits = 14; - // } - // } else { - // bits = 15; - // } - // } - // } - // addbits(bits); - // int N = dec.getDecodePos()[bits] - // + (((int) bitField - dec.getDecodeLen()[bits - 1]) >>> (16 - bits)); - // if (N >= dec.getMaxNum()) { - // N = 0; - // } - // return (dec.getDecodeNum()[N]); - int[] decodeLen = dec.DecodeLen; - if (bitField < decodeLen[8]) + // if (bitField < dec.getDecodeLen()[8]) { + // if (bitField < dec.getDecodeLen()[4]) { + // if (bitField < dec.getDecodeLen()[2]) { + // if (bitField < dec.getDecodeLen()[1]) { + // bits = 1; + // } else { + // bits = 2; + // } + // } else { + // if (bitField < dec.getDecodeLen()[3]) { + // bits = 3; + // } else { + // bits = 4; + // } + // } + // } else { + // if (bitField < dec.getDecodeLen()[6]) { + // if (bitField < dec.getDecodeLen()[5]) + // bits = 5; + // else + // bits = 6; + // } else { + // if (bitField < dec.getDecodeLen()[7]) { + // bits = 7; + // } else { + // bits = 8; + // } + // } + // } + // } else { + // if (bitField < dec.getDecodeLen()[12]) { + // if (bitField < dec.getDecodeLen()[10]) + // if (bitField < dec.getDecodeLen()[9]) + // bits = 9; + // else + // bits = 10; + // else if (bitField < dec.getDecodeLen()[11]) + // bits = 11; + // else + // bits = 12; + // } else { + // if (bitField < dec.getDecodeLen()[14]) { + // if (bitField < dec.getDecodeLen()[13]) { + // bits = 13; + // } else { + // bits = 14; + // } + // } else { + // bits = 15; + // } + // } + // } + // addbits(bits); + // int N = dec.getDecodePos()[bits] + // + (((int) bitField - dec.getDecodeLen()[bits - 1]) >>> (16 - bits)); + // if (N >= dec.getMaxNum()) { + // N = 0; + // } + // return (dec.getDecodeNum()[N]); + var decodeLen = dec.DecodeLen; + if (bitField < decodeLen[8]) + { + if (bitField < decodeLen[4]) { - if (bitField < decodeLen[4]) + if (bitField < decodeLen[2]) { - if (bitField < decodeLen[2]) + if (bitField < decodeLen[1]) { - if (bitField < decodeLen[1]) - { - bits = 1; - } - else - { - bits = 2; - } + bits = 1; } else { - if (bitField < decodeLen[3]) - { - bits = 3; - } - else - { - bits = 4; - } + bits = 2; } } else { - if (bitField < decodeLen[6]) + if (bitField < decodeLen[3]) { - if (bitField < decodeLen[5]) - { - bits = 5; - } - else - { - bits = 6; - } + bits = 3; } else { - if (bitField < decodeLen[7]) - { - bits = 7; - } - else - { - bits = 8; - } + bits = 4; } } } else { - if (bitField < decodeLen[12]) + if (bitField < decodeLen[6]) { - if (bitField < decodeLen[10]) + if (bitField < decodeLen[5]) { - if (bitField < decodeLen[9]) - { - bits = 9; - } - else - { - bits = 10; - } - } - else if (bitField < decodeLen[11]) - { - bits = 11; + bits = 5; } else { - bits = 12; + bits = 6; } } else { - if (bitField < decodeLen[14]) + if (bitField < decodeLen[7]) { - if (bitField < decodeLen[13]) - { - bits = 13; - } - else - { - bits = 14; - } + bits = 7; } else { - bits = 15; + bits = 8; } } } - input.AddBits(bits); - int N = - dec.DecodePos[bits] - + (Utility.URShift(((int)bitField - decodeLen[bits - 1]), (16 - bits))); - if (N >= dec.MaxNum) - { - N = 0; - } - return (dec.DecodeNum[N]); } + else + { + if (bitField < decodeLen[12]) + { + if (bitField < decodeLen[10]) + { + if (bitField < decodeLen[9]) + { + bits = 9; + } + else + { + bits = 10; + } + } + else if (bitField < decodeLen[11]) + { + bits = 11; + } + else + { + bits = 12; + } + } + else + { + if (bitField < decodeLen[14]) + { + if (bitField < decodeLen[13]) + { + bits = 13; + } + else + { + bits = 14; + } + } + else + { + bits = 15; + } + } + } + input.AddBits(bits); + var N = + dec.DecodePos[bits] + + (Utility.URShift(((int)bitField - decodeLen[bits - 1]), (16 - bits))); + if (N >= dec.MaxNum) + { + N = 0; + } + return (dec.DecodeNum[N]); + } - internal static void makeDecodeTables( - byte[] lenTab, - int offset, - Decode.Decode dec, - int size + internal static void makeDecodeTables( + byte[] lenTab, + int offset, + Decode.Decode dec, + int size + ) + { + Span lenCount = stackalloc int[16]; + Span tmpPos = stackalloc int[16]; + int i; + long M, + N; + + new Span(dec.DecodeNum).Clear(); // memset(Dec->DecodeNum,0,Size*sizeof(*Dec->DecodeNum)); + + for (i = 0; i < size; i++) + { + lenCount[lenTab[offset + i] & 0xF]++; + } + lenCount[0] = 0; + for ( + tmpPos[0] = 0, dec.DecodePos[0] = 0, dec.DecodeLen[0] = 0, N = 0, i = 1; + i < 16; + i++ ) { - Span lenCount = stackalloc int[16]; - Span tmpPos = stackalloc int[16]; - int i; - long M, - N; - - new Span(dec.DecodeNum).Clear(); // memset(Dec->DecodeNum,0,Size*sizeof(*Dec->DecodeNum)); - - for (i = 0; i < size; i++) + N = 2 * (N + lenCount[i]); + M = N << (15 - i); + if (M > 0xFFFF) { - lenCount[lenTab[offset + i] & 0xF]++; + M = 0xFFFF; } - lenCount[0] = 0; - for ( - tmpPos[0] = 0, dec.DecodePos[0] = 0, dec.DecodeLen[0] = 0, N = 0, i = 1; - i < 16; - i++ - ) - { - N = 2 * (N + lenCount[i]); - M = N << (15 - i); - if (M > 0xFFFF) - { - M = 0xFFFF; - } - dec.DecodeLen[i] = (int)M; - tmpPos[i] = dec.DecodePos[i] = dec.DecodePos[i - 1] + lenCount[i - 1]; - } - - for (i = 0; i < size; i++) - { - if (lenTab[offset + i] != 0) - { - dec.DecodeNum[tmpPos[lenTab[offset + i] & 0xF]++] = i; - } - } - dec.MaxNum = size; + dec.DecodeLen[i] = (int)M; + tmpPos[i] = dec.DecodePos[i] = dec.DecodePos[i - 1] + lenCount[i - 1]; } + + for (i = 0; i < size; i++) + { + if (lenTab[offset + i] != 0) + { + dec.DecodeNum[tmpPos[lenTab[offset + i] & 0xF]++] = i; + } + } + dec.MaxNum = size; } } diff --git a/src/SharpCompress/Compressors/Rar/UnpackV2017/BitInput.getbits_cpp.cs b/src/SharpCompress/Compressors/Rar/UnpackV2017/BitInput.getbits_cpp.cs index b06d56a2..58af921b 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV2017/BitInput.getbits_cpp.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV2017/BitInput.getbits_cpp.cs @@ -1,6 +1,4 @@ -#if !Rar2017_64bit -using nint = System.Int32; -using nuint = System.UInt32; +#if !Rar2017_64bit using size_t = System.UInt32; #else using nint = System.Int64; @@ -10,57 +8,48 @@ using size_t = System.UInt64; #nullable disable -namespace SharpCompress.Compressors.Rar.UnpackV2017 +namespace SharpCompress.Compressors.Rar.UnpackV2017; + +internal partial class BitInput { - internal partial class BitInput + public BitInput(bool AllocBuffer) { - public BitInput(bool AllocBuffer) + ExternalBuffer = false; + if (AllocBuffer) { - ExternalBuffer = false; - if (AllocBuffer) - { - // getbits32 attempts to read data from InAddr, ... InAddr+3 positions. - // So let's allocate 3 additional bytes for situation, when we need to - // read only 1 byte from the last position of buffer and avoid a crash - // from access to next 3 bytes, which contents we do not need. - size_t BufSize = MAX_SIZE + 3; - InBuf = new byte[BufSize]; + // getbits32 attempts to read data from InAddr, ... InAddr+3 positions. + // So let's allocate 3 additional bytes for situation, when we need to + // read only 1 byte from the last position of buffer and avoid a crash + // from access to next 3 bytes, which contents we do not need. + size_t BufSize = MAX_SIZE + 3; + InBuf = new byte[BufSize]; - // Ensure that we get predictable results when accessing bytes in area - // not filled with read data. - //memset(InBuf,0,BufSize); - } - else - { - InBuf = null; - } + // Ensure that we get predictable results when accessing bytes in area + // not filled with read data. + //memset(InBuf,0,BufSize); } - - //BitInput::~BitInput() - //{ - // if (!ExternalBuffer) - // delete[] InBuf; - //} - // - - public void faddbits(uint Bits) + else { - // Function wrapped version of inline addbits to save code size. - addbits(Bits); - } - - public uint fgetbits() - { - // Function wrapped version of inline getbits to save code size. - return getbits(); - } - - private void SetExternalBuffer(byte[] Buf) - { - //if (InBuf!=NULL && !ExternalBuffer) - // delete[] InBuf; - InBuf = Buf; - ExternalBuffer = true; + InBuf = null; } } + + //BitInput::~BitInput() + //{ + // if (!ExternalBuffer) + // delete[] InBuf; + //} + // + + public void faddbits(uint Bits) + { + // Function wrapped version of inline addbits to save code size. + addbits(Bits); + } + + public uint fgetbits() + { + // Function wrapped version of inline getbits to save code size. + return getbits(); + } } diff --git a/src/SharpCompress/Compressors/Rar/UnpackV2017/BitInput.getbits_hpp.cs b/src/SharpCompress/Compressors/Rar/UnpackV2017/BitInput.getbits_hpp.cs index 3acb8f28..47409b0e 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV2017/BitInput.getbits_hpp.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV2017/BitInput.getbits_hpp.cs @@ -1,67 +1,56 @@ -namespace SharpCompress.Compressors.Rar.UnpackV2017 +namespace SharpCompress.Compressors.Rar.UnpackV2017; + +internal partial class BitInput { - internal partial class BitInput + public const int MAX_SIZE = 0x8000; // Size of input buffer. + + public int InAddr; // Curent byte position in the buffer. + public int InBit; // Current bit position in the current byte. + + public bool ExternalBuffer; + + //BitInput(bool AllocBuffer); + //~BitInput(); + + public byte[] InBuf; // Dynamically allocated input buffer. + + public void InitBitInput() { - public const int MAX_SIZE = 0x8000; // Size of input buffer. - - public int InAddr; // Curent byte position in the buffer. - public int InBit; // Current bit position in the current byte. - - public bool ExternalBuffer; - - //BitInput(bool AllocBuffer); - //~BitInput(); - - public byte[] InBuf; // Dynamically allocated input buffer. - - public void InitBitInput() - { - InAddr = InBit = 0; - } - - // Move forward by 'Bits' bits. - public void addbits(uint _Bits) - { - var Bits = checked((int)_Bits); - Bits += InBit; - InAddr += Bits >> 3; - InBit = Bits & 7; - } - - // Return 16 bits from current position in the buffer. - // Bit at (InAddr,InBit) has the highest position in returning data. - public uint getbits() - { - uint BitField = (uint)InBuf[InAddr] << 16; - BitField |= (uint)InBuf[InAddr + 1] << 8; - BitField |= (uint)InBuf[InAddr + 2]; - BitField >>= (8 - InBit); - return BitField & 0xffff; - } - - // Return 32 bits from current position in the buffer. - // Bit at (InAddr,InBit) has the highest position in returning data. - public uint getbits32() - { - uint BitField = (uint)InBuf[InAddr] << 24; - BitField |= (uint)InBuf[InAddr + 1] << 16; - BitField |= (uint)InBuf[InAddr + 2] << 8; - BitField |= (uint)InBuf[InAddr + 3]; - BitField <<= InBit; - BitField |= (uint)InBuf[InAddr + 4] >> (8 - InBit); - return BitField & 0xffffffff; - } - - //void faddbits(uint Bits); - //uint fgetbits(); - - // Check if buffer has enough space for IncPtr bytes. Returns 'true' - // if buffer will be overflown. - private bool Overflow(uint IncPtr) - { - return InAddr + IncPtr >= MAX_SIZE; - } - - //void SetExternalBuffer(byte *Buf); + InAddr = InBit = 0; } + + // Move forward by 'Bits' bits. + public void addbits(uint _Bits) + { + var Bits = checked((int)_Bits); + Bits += InBit; + InAddr += Bits >> 3; + InBit = Bits & 7; + } + + // Return 16 bits from current position in the buffer. + // Bit at (InAddr,InBit) has the highest position in returning data. + public uint getbits() + { + var BitField = (uint)InBuf[InAddr] << 16; + BitField |= (uint)InBuf[InAddr + 1] << 8; + BitField |= InBuf[InAddr + 2]; + BitField >>= (8 - InBit); + return BitField & 0xffff; + } + + // Return 32 bits from current position in the buffer. + // Bit at (InAddr,InBit) has the highest position in returning data. + public uint getbits32() + { + var BitField = (uint)InBuf[InAddr] << 24; + BitField |= (uint)InBuf[InAddr + 1] << 16; + BitField |= (uint)InBuf[InAddr + 2] << 8; + BitField |= InBuf[InAddr + 3]; + BitField <<= InBit; + BitField |= (uint)InBuf[InAddr + 4] >> (8 - InBit); + return BitField & 0xffffffff; + } + + //void SetExternalBuffer(byte *Buf); } diff --git a/src/SharpCompress/Compressors/Rar/UnpackV2017/FragmentedWindow.unpack50frag_cpp.cs b/src/SharpCompress/Compressors/Rar/UnpackV2017/FragmentedWindow.unpack50frag_cpp.cs index 7b2a378d..bfa69829 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV2017/FragmentedWindow.unpack50frag_cpp.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV2017/FragmentedWindow.unpack50frag_cpp.cs @@ -1,191 +1,181 @@ -#nullable disable +#nullable disable #if !Rar2017_64bit -using nint = System.Int32; -using nuint = System.UInt32; using size_t = System.UInt32; #else using nint = System.Int64; using nuint = System.UInt64; using size_t = System.UInt64; #endif -using int64 = System.Int64; - using System; -namespace SharpCompress.Compressors.Rar.UnpackV2017 +namespace SharpCompress.Compressors.Rar.UnpackV2017; + +internal partial class FragmentedWindow { - internal partial class FragmentedWindow + public FragmentedWindow() { - public FragmentedWindow() - { - //memset(Mem,0,sizeof(Mem)); - //memset(MemSize,0,sizeof(MemSize)); - } + //memset(Mem,0,sizeof(Mem)); + //memset(MemSize,0,sizeof(MemSize)); + } - //FragmentedWindow::~FragmentedWindow() - //{ - // Reset(); - //} + //FragmentedWindow::~FragmentedWindow() + //{ + // Reset(); + //} - private void Reset() + private void Reset() + { + for (uint I = 0; I < Mem.Length; I++) { - for (uint I = 0; I < Mem.Length; I++) + if (Mem[I] != null) { - if (Mem[I] != null) - { - //free(Mem[I]); - Mem[I] = null; - } + //free(Mem[I]); + Mem[I] = null; } } + } - public void Init(size_t WinSize) + public void Init(size_t WinSize) + { + Reset(); + + uint BlockNum = 0; + size_t TotalSize = 0; // Already allocated. + while (TotalSize < WinSize && BlockNum < Mem.Length) { - Reset(); + var Size = WinSize - TotalSize; // Size needed to allocate. - uint BlockNum = 0; - size_t TotalSize = 0; // Already allocated. - while (TotalSize < WinSize && BlockNum < Mem.Length) + // Minimum still acceptable block size. Next allocations cannot be larger + // than current, so we do not need blocks if they are smaller than + // "size left / attempts left". Also we do not waste time to blocks + // smaller than some arbitrary constant. + var MinSize = Math.Max(Size / (size_t)(Mem.Length - BlockNum), 0x400000); + + byte[] NewMem = null; + while (Size >= MinSize) { - size_t Size = WinSize - TotalSize; // Size needed to allocate. - - // Minimum still acceptable block size. Next allocations cannot be larger - // than current, so we do not need blocks if they are smaller than - // "size left / attempts left". Also we do not waste time to blocks - // smaller than some arbitrary constant. - size_t MinSize = Math.Max(Size / (size_t)(Mem.Length - BlockNum), 0x400000); - - byte[] NewMem = null; - while (Size >= MinSize) + NewMem = new byte[Size]; + if (NewMem != null) { - NewMem = new byte[Size]; - if (NewMem != null) - { - break; - } - - Size -= Size / 32; - } - if (NewMem == null) - //throw std::bad_alloc(); - { - throw new InvalidOperationException(); + break; } - // Clean the window to generate the same output when unpacking corrupt - // RAR files, which may access to unused areas of sliding dictionary. - // sharpcompress: don't need this, freshly allocated above - //Utility.Memset(NewMem,0,Size); + Size -= Size / 32; + } - Mem[BlockNum] = NewMem; - TotalSize += Size; - MemSize[BlockNum] = TotalSize; - BlockNum++; - } - if (TotalSize < WinSize) // Not found enough free blocks. - //throw std::bad_alloc(); - { - throw new InvalidOperationException(); - } + // Clean the window to generate the same output when unpacking corrupt + // RAR files, which may access to unused areas of sliding dictionary. + // sharpcompress: don't need this, freshly allocated above + //Utility.Memset(NewMem,0,Size); + + Mem[BlockNum] = NewMem ?? throw new InvalidOperationException(); + TotalSize += Size; + MemSize[BlockNum] = TotalSize; + BlockNum++; } - - public byte this[size_t Item] + if (TotalSize < WinSize) // Not found enough free blocks. + //throw std::bad_alloc(); { - get - { - if (Item < MemSize[0]) - { - return Mem[0][Item]; - } - - for (uint I = 1; I < MemSize.Length; I++) - { - if (Item < MemSize[I]) - { - return Mem[I][Item - MemSize[I - 1]]; - } - } - - return Mem[0][0]; // Must never happen; - } - set - { - if (Item < MemSize[0]) - { - Mem[0][Item] = value; - return; - } - for (uint I = 1; I < MemSize.Length; I++) - { - if (Item < MemSize[I]) - { - Mem[I][Item - MemSize[I - 1]] = value; - return; - } - } - - Mem[0][0] = value; // Must never happen; - } + throw new InvalidOperationException(); } + } - // sharpcompress: added the following code - public void GetBuffer(size_t Item, out byte[] buf, out uint offset) + public byte this[size_t Item] + { + get { if (Item < MemSize[0]) { - //return Mem[0][Item]; - buf = Mem[0]; - offset = Item; + return Mem[0][Item]; + } + + for (uint I = 1; I < MemSize.Length; I++) + { + if (Item < MemSize[I]) + { + return Mem[I][Item - MemSize[I - 1]]; + } + } + + return Mem[0][0]; // Must never happen; + } + set + { + if (Item < MemSize[0]) + { + Mem[0][Item] = value; return; } for (uint I = 1; I < MemSize.Length; I++) { if (Item < MemSize[I]) { - //return Mem[I][Item-MemSize[I-1]]; - buf = Mem[I]; - offset = Item - MemSize[I - 1]; + Mem[I][Item - MemSize[I - 1]] = value; return; } } - //return Mem[0][0]; // Must never happen; - buf = Mem[0]; - offset = 0; - return; // Must never happen; - } - public void CopyString(uint Length, uint Distance, ref size_t UnpPtr, size_t MaxWinMask) - { - size_t SrcPtr = UnpPtr - Distance; - while (Length-- > 0) - { - this[UnpPtr] = this[SrcPtr++ & MaxWinMask]; - // We need to have masked UnpPtr after quit from loop, so it must not - // be replaced with '(*this)[UnpPtr++ & MaxWinMask]' - UnpPtr = (UnpPtr + 1) & MaxWinMask; - } - } - - public void CopyData(byte[] Dest, size_t destOffset, size_t WinPos, size_t Size) - { - for (size_t I = 0; I < Size; I++) - { - Dest[destOffset + I] = this[WinPos + I]; - } - } - - public size_t GetBlockSize(size_t StartPos, size_t RequiredSize) - { - for (uint I = 0; I < MemSize.Length; I++) - { - if (StartPos < MemSize[I]) - { - return Math.Min(MemSize[I] - StartPos, RequiredSize); - } - } - - return 0; // Must never be here. + Mem[0][0] = value; // Must never happen; } } + + // sharpcompress: added the following code + public void GetBuffer(size_t Item, out byte[] buf, out uint offset) + { + if (Item < MemSize[0]) + { + //return Mem[0][Item]; + buf = Mem[0]; + offset = Item; + return; + } + for (uint I = 1; I < MemSize.Length; I++) + { + if (Item < MemSize[I]) + { + //return Mem[I][Item-MemSize[I-1]]; + buf = Mem[I]; + offset = Item - MemSize[I - 1]; + return; + } + } + //return Mem[0][0]; // Must never happen; + buf = Mem[0]; + offset = 0; + return; // Must never happen; + } + + public void CopyString(uint Length, uint Distance, ref size_t UnpPtr, size_t MaxWinMask) + { + var SrcPtr = UnpPtr - Distance; + while (Length-- > 0) + { + this[UnpPtr] = this[SrcPtr++ & MaxWinMask]; + // We need to have masked UnpPtr after quit from loop, so it must not + // be replaced with '(*this)[UnpPtr++ & MaxWinMask]' + UnpPtr = (UnpPtr + 1) & MaxWinMask; + } + } + + public void CopyData(byte[] Dest, size_t destOffset, size_t WinPos, size_t Size) + { + for (size_t I = 0; I < Size; I++) + { + Dest[destOffset + I] = this[WinPos + I]; + } + } + + public size_t GetBlockSize(size_t StartPos, size_t RequiredSize) + { + for (uint I = 0; I < MemSize.Length; I++) + { + if (StartPos < MemSize[I]) + { + return Math.Min(MemSize[I] - StartPos, RequiredSize); + } + } + + return 0; // Must never be here. + } } diff --git a/src/SharpCompress/Compressors/Rar/UnpackV2017/PackDef.compress_hpp.cs b/src/SharpCompress/Compressors/Rar/UnpackV2017/PackDef.compress_hpp.cs index 9863446d..ed4e74ea 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV2017/PackDef.compress_hpp.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV2017/PackDef.compress_hpp.cs @@ -1,54 +1,53 @@ -namespace SharpCompress.Compressors.Rar.UnpackV2017 +namespace SharpCompress.Compressors.Rar.UnpackV2017; + +internal static class PackDef { - internal static class PackDef - { - // Combine pack and unpack constants to class to avoid polluting global - // namespace with numerous short names. - public const uint MAX_LZ_MATCH = 0x1001; - public const uint MAX3_LZ_MATCH = 0x101; // Maximum match length for RAR v3. - public const uint LOW_DIST_REP_COUNT = 16; + // Combine pack and unpack constants to class to avoid polluting global + // namespace with numerous short names. + public const uint MAX_LZ_MATCH = 0x1001; + public const uint MAX3_LZ_MATCH = 0x101; // Maximum match length for RAR v3. + public const uint LOW_DIST_REP_COUNT = 16; - public const uint NC = 306; /* alphabet = {0, 1, 2, ..., NC - 1} */ - public const uint DC = 64; - public const uint LDC = 16; - public const uint RC = 44; - public const uint HUFF_TABLE_SIZE = NC + DC + RC + LDC; - public const uint BC = 20; + public const uint NC = 306; /* alphabet = {0, 1, 2, ..., NC - 1} */ + public const uint DC = 64; + public const uint LDC = 16; + public const uint RC = 44; + public const uint HUFF_TABLE_SIZE = NC + DC + RC + LDC; + public const uint BC = 20; - public const uint NC30 = 299; /* alphabet = {0, 1, 2, ..., NC - 1} */ - public const uint DC30 = 60; - public const uint LDC30 = 17; - public const uint RC30 = 28; - public const uint BC30 = 20; - public const uint HUFF_TABLE_SIZE30 = NC30 + DC30 + RC30 + LDC30; + public const uint NC30 = 299; /* alphabet = {0, 1, 2, ..., NC - 1} */ + public const uint DC30 = 60; + public const uint LDC30 = 17; + public const uint RC30 = 28; + public const uint BC30 = 20; + public const uint HUFF_TABLE_SIZE30 = NC30 + DC30 + RC30 + LDC30; - public const uint NC20 = 298; /* alphabet = {0, 1, 2, ..., NC - 1} */ - public const uint DC20 = 48; - public const uint RC20 = 28; - public const uint BC20 = 19; - public const uint MC20 = 257; + public const uint NC20 = 298; /* alphabet = {0, 1, 2, ..., NC - 1} */ + public const uint DC20 = 48; + public const uint RC20 = 28; + public const uint BC20 = 19; + public const uint MC20 = 257; - // Largest alphabet size among all values listed above. - public const uint LARGEST_TABLE_SIZE = 306; + // Largest alphabet size among all values listed above. + public const uint LARGEST_TABLE_SIZE = 306; - // enum { - // CODE_HUFFMAN, CODE_LZ, CODE_REPEATLZ, CODE_CACHELZ, CODE_STARTFILE, - // CODE_ENDFILE, CODE_FILTER, CODE_FILTERDATA - // }; + // enum { + // CODE_HUFFMAN, CODE_LZ, CODE_REPEATLZ, CODE_CACHELZ, CODE_STARTFILE, + // CODE_ENDFILE, CODE_FILTER, CODE_FILTERDATA + // }; - //enum FilterType { - // These values must not be changed, because we use them directly - // in RAR5 compression and decompression code. - public const int FILTER_DELTA = 0; - public const int FILTER_E8 = 1; - public const int FILTER_E8E9 = 2; - public const int FILTER_ARM = 3; - public const int FILTER_AUDIO = 4; - public const int FILTER_RGB = 5; - public const int FILTER_ITANIUM = 6; - public const int FILTER_PPM = 7; - public const int FILTER_NONE = 8; - //} - } + //enum FilterType { + // These values must not be changed, because we use them directly + // in RAR5 compression and decompression code. + public const int FILTER_DELTA = 0; + public const int FILTER_E8 = 1; + public const int FILTER_E8E9 = 2; + public const int FILTER_ARM = 3; + public const int FILTER_AUDIO = 4; + public const int FILTER_RGB = 5; + public const int FILTER_ITANIUM = 6; + public const int FILTER_PPM = 7; + public const int FILTER_NONE = 8; + //} } diff --git a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.cs b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.cs index f840edf7..93ed3e64 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.cs @@ -1,122 +1,117 @@ -#if !Rar2017_64bit -using nint = System.Int32; -using nuint = System.UInt32; +#if !Rar2017_64bit using size_t = System.UInt32; #else using nint = System.Int64; using nuint = System.UInt64; using size_t = System.UInt64; #endif -using int64 = System.Int64; - using System; using System.IO; using SharpCompress.Common.Rar.Headers; -namespace SharpCompress.Compressors.Rar.UnpackV2017 +namespace SharpCompress.Compressors.Rar.UnpackV2017; + +internal partial class Unpack : IRarUnpack { - internal partial class Unpack : IRarUnpack + private FileHeader fileHeader; + private Stream readStream; + private Stream writeStream; + + private void _UnpackCtor() { - private FileHeader fileHeader; - private Stream readStream; - private Stream writeStream; - - private void _UnpackCtor() + for (var i = 0; i < AudV.Length; i++) { - for (int i = 0; i < AudV.Length; i++) - { - AudV[i] = new AudioVariables(); - } - } - - private int UnpIO_UnpRead(byte[] buf, int offset, int count) - { - // NOTE: caller has logic to check for -1 for error we throw instead. - return readStream.Read(buf, offset, count); - } - - private void UnpIO_UnpWrite(byte[] buf, size_t offset, uint count) - { - writeStream.Write(buf, checked((int)offset), checked((int)count)); - } - - public void DoUnpack(FileHeader fileHeader, Stream readStream, Stream writeStream) - { - // as of 12/2017 .NET limits array indexing to using a signed integer - // MaxWinSize causes unpack to use a fragmented window when the file - // window size exceeds MaxWinSize - // uggh, that's not how this variable is used, it's the size of the currently allocated window buffer - //x MaxWinSize = ((uint)int.MaxValue) + 1; - - // may be long.MaxValue which could indicate unknown size (not present in header) - DestUnpSize = fileHeader.UncompressedSize; - this.fileHeader = fileHeader; - this.readStream = readStream; - this.writeStream = writeStream; - if (!fileHeader.IsStored) - { - Init(fileHeader.WindowSize, fileHeader.IsSolid); - } - Suspended = false; - DoUnpack(); - } - - public void DoUnpack() - { - if (fileHeader.IsStored) - { - UnstoreFile(); - } - else - { - DoUnpack(fileHeader.CompressionAlgorithm, fileHeader.IsSolid); - } - } - - private void UnstoreFile() - { - var b = new byte[0x10000]; - do - { - int n = readStream.Read(b, 0, (int)Math.Min(b.Length, DestUnpSize)); - if (n == 0) - { - break; - } - writeStream.Write(b, 0, n); - DestUnpSize -= n; - } while (!Suspended); - } - - public bool Suspended { get; set; } - - public long DestSize - { - get => DestUnpSize; - } - - public int Char - { - get - { - // TODO: coderb: not sure where the "MAXSIZE-30" comes from, ported from V1 code - if (InAddr > MAX_SIZE - 30) - { - UnpReadBuf(); - } - return InBuf[InAddr++]; - } - } - - public int PpmEscChar - { - get => PPMEscChar; - set => PPMEscChar = value; - } - - public static byte[] EnsureCapacity(byte[] array, int length) - { - return array.Length < length ? new byte[length] : array; + AudV[i] = new AudioVariables(); } } + + private int UnpIO_UnpRead(byte[] buf, int offset, int count) + { + // NOTE: caller has logic to check for -1 for error we throw instead. + return readStream.Read(buf, offset, count); + } + + private void UnpIO_UnpWrite(byte[] buf, size_t offset, uint count) + { + writeStream.Write(buf, checked((int)offset), checked((int)count)); + } + + public void DoUnpack(FileHeader fileHeader, Stream readStream, Stream writeStream) + { + // as of 12/2017 .NET limits array indexing to using a signed integer + // MaxWinSize causes unpack to use a fragmented window when the file + // window size exceeds MaxWinSize + // uggh, that's not how this variable is used, it's the size of the currently allocated window buffer + //x MaxWinSize = ((uint)int.MaxValue) + 1; + + // may be long.MaxValue which could indicate unknown size (not present in header) + DestUnpSize = fileHeader.UncompressedSize; + this.fileHeader = fileHeader; + this.readStream = readStream; + this.writeStream = writeStream; + if (!fileHeader.IsStored) + { + Init(fileHeader.WindowSize, fileHeader.IsSolid); + } + Suspended = false; + DoUnpack(); + } + + public void DoUnpack() + { + if (fileHeader.IsStored) + { + UnstoreFile(); + } + else + { + DoUnpack(fileHeader.CompressionAlgorithm, fileHeader.IsSolid); + } + } + + private void UnstoreFile() + { + var b = new byte[0x10000]; + do + { + var n = readStream.Read(b, 0, (int)Math.Min(b.Length, DestUnpSize)); + if (n == 0) + { + break; + } + writeStream.Write(b, 0, n); + DestUnpSize -= n; + } while (!Suspended); + } + + public bool Suspended { get; set; } + + public long DestSize + { + get => DestUnpSize; + } + + public int Char + { + get + { + // TODO: coderb: not sure where the "MAXSIZE-30" comes from, ported from V1 code + if (InAddr > MAX_SIZE - 30) + { + UnpReadBuf(); + } + return InBuf[InAddr++]; + } + } + + public int PpmEscChar + { + get => PPMEscChar; + set => PPMEscChar = value; + } + + public static byte[] EnsureCapacity(byte[] array, int length) + { + return array.Length < length ? new byte[length] : array; + } } diff --git a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.rawint_hpp.cs b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.rawint_hpp.cs index 69281b36..cb572e9d 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.rawint_hpp.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.rawint_hpp.cs @@ -1,123 +1,118 @@ -#if !Rar2017_64bit -using nint = System.Int32; -using nuint = System.UInt32; -using size_t = System.UInt32; +#if !Rar2017_64bit #else using nint = System.Int64; using nuint = System.UInt64; using size_t = System.UInt64; #endif -using int64 = System.Int64; using uint32 = System.UInt32; -namespace SharpCompress.Compressors.Rar.UnpackV2017 +namespace SharpCompress.Compressors.Rar.UnpackV2017; + +internal partial class Unpack { - internal partial class Unpack + //#define rotls(x,n,xsize) (((x)<<(n)) | ((x)>>(xsize-(n)))) + //#define rotrs(x,n,xsize) (((x)>>(n)) | ((x)<<(xsize-(n)))) + //#define rotl32(x,n) rotls(x,n,32) + //#define rotr32(x,n) rotrs(x,n,32) + // + //inline uint RawGet2(const void *Data) + //{ + // byte *D=(byte *)Data; + // return D[0]+(D[1]<<8); + //} + + private uint32 RawGet4(byte[] D, int offset) { - //#define rotls(x,n,xsize) (((x)<<(n)) | ((x)>>(xsize-(n)))) - //#define rotrs(x,n,xsize) (((x)>>(n)) | ((x)<<(xsize-(n)))) - //#define rotl32(x,n) rotls(x,n,32) - //#define rotr32(x,n) rotrs(x,n,32) - // - //inline uint RawGet2(const void *Data) - //{ - // byte *D=(byte *)Data; - // return D[0]+(D[1]<<8); - //} - - private uint32 RawGet4(byte[] D, int offset) - { - return (uint)( - D[offset] + (D[offset + 1] << 8) + (D[offset + 2] << 16) + (D[offset + 3] << 24) - ); - } - - //inline uint64 RawGet8(const void *Data) - //{ - //#if defined(BIG_ENDIAN) || !defined(ALLOW_MISALIGNED) - // byte *D=(byte *)Data; - // return INT32TO64(RawGet4(D+4),RawGet4(D)); - //#else - // return *(uint64 *)Data; - //#endif - //} - // - // - //inline void RawPut2(uint Field,void *Data) - //{ - // byte *D=(byte *)Data; - // D[0]=(byte)(Field); - // D[1]=(byte)(Field>>8); - //} - - private void RawPut4(uint32 Field, byte[] D, int offset) - { - D[offset] = (byte)(Field); - D[offset + 1] = (byte)(Field >> 8); - D[offset + 2] = (byte)(Field >> 16); - D[offset + 3] = (byte)(Field >> 24); - } - - //inline void RawPut8(uint64 Field,void *Data) - //{ - //#if defined(BIG_ENDIAN) || !defined(ALLOW_MISALIGNED) - // byte *D=(byte *)Data; - // D[0]=(byte)(Field); - // D[1]=(byte)(Field>>8); - // D[2]=(byte)(Field>>16); - // D[3]=(byte)(Field>>24); - // D[4]=(byte)(Field>>32); - // D[5]=(byte)(Field>>40); - // D[6]=(byte)(Field>>48); - // D[7]=(byte)(Field>>56); - //#else - // *(uint64 *)Data=Field; - //#endif - //} - - - //#if defined(LITTLE_ENDIAN) && defined(ALLOW_MISALIGNED) - //#define USE_MEM_BYTESWAP - //#endif - - // Load 4 big endian bytes from memory and return uint32. - //inline uint32 RawGetBE4(const byte *m) - //{ - //#if defined(USE_MEM_BYTESWAP) && defined(_MSC_VER) - // return _byteswap_ulong(*(uint32 *)m); - //#elif defined(USE_MEM_BYTESWAP) && (__GNUC__ > 3) && (__GNUC_MINOR__ > 2) - // return __builtin_bswap32(*(uint32 *)m); - //#else - // return uint32(m[0]<<24) | uint32(m[1]<<16) | uint32(m[2]<<8) | m[3]; - //#endif - //} - - - // Save integer to memory as big endian. - //inline void RawPutBE4(uint32 i,byte *mem) - //{ - //#if defined(USE_MEM_BYTESWAP) && defined(_MSC_VER) - // *(uint32*)mem = _byteswap_ulong(i); - //#elif defined(USE_MEM_BYTESWAP) && (__GNUC__ > 3) && (__GNUC_MINOR__ > 2) - // *(uint32*)mem = __builtin_bswap32(i); - //#else - // mem[0]=byte(i>>24); - // mem[1]=byte(i>>16); - // mem[2]=byte(i>>8); - // mem[3]=byte(i); - //#endif - //} - - - //inline uint32 ByteSwap32(uint32 i) - //{ - //#ifdef _MSC_VER - // return _byteswap_ulong(i); - //#elif (__GNUC__ > 3) && (__GNUC_MINOR__ > 2) - // return __builtin_bswap32(i); - //#else - // return (rotl32(i,24)&0xFF00FF00)|(rotl32(i,8)&0x00FF00FF); - //#endif - //} + return (uint)( + D[offset] + (D[offset + 1] << 8) + (D[offset + 2] << 16) + (D[offset + 3] << 24) + ); } + + //inline uint64 RawGet8(const void *Data) + //{ + //#if defined(BIG_ENDIAN) || !defined(ALLOW_MISALIGNED) + // byte *D=(byte *)Data; + // return INT32TO64(RawGet4(D+4),RawGet4(D)); + //#else + // return *(uint64 *)Data; + //#endif + //} + // + // + //inline void RawPut2(uint Field,void *Data) + //{ + // byte *D=(byte *)Data; + // D[0]=(byte)(Field); + // D[1]=(byte)(Field>>8); + //} + + private void RawPut4(uint32 Field, byte[] D, int offset) + { + D[offset] = (byte)(Field); + D[offset + 1] = (byte)(Field >> 8); + D[offset + 2] = (byte)(Field >> 16); + D[offset + 3] = (byte)(Field >> 24); + } + + //inline void RawPut8(uint64 Field,void *Data) + //{ + //#if defined(BIG_ENDIAN) || !defined(ALLOW_MISALIGNED) + // byte *D=(byte *)Data; + // D[0]=(byte)(Field); + // D[1]=(byte)(Field>>8); + // D[2]=(byte)(Field>>16); + // D[3]=(byte)(Field>>24); + // D[4]=(byte)(Field>>32); + // D[5]=(byte)(Field>>40); + // D[6]=(byte)(Field>>48); + // D[7]=(byte)(Field>>56); + //#else + // *(uint64 *)Data=Field; + //#endif + //} + + + //#if defined(LITTLE_ENDIAN) && defined(ALLOW_MISALIGNED) + //#define USE_MEM_BYTESWAP + //#endif + + // Load 4 big endian bytes from memory and return uint32. + //inline uint32 RawGetBE4(const byte *m) + //{ + //#if defined(USE_MEM_BYTESWAP) && defined(_MSC_VER) + // return _byteswap_ulong(*(uint32 *)m); + //#elif defined(USE_MEM_BYTESWAP) && (__GNUC__ > 3) && (__GNUC_MINOR__ > 2) + // return __builtin_bswap32(*(uint32 *)m); + //#else + // return uint32(m[0]<<24) | uint32(m[1]<<16) | uint32(m[2]<<8) | m[3]; + //#endif + //} + + + // Save integer to memory as big endian. + //inline void RawPutBE4(uint32 i,byte *mem) + //{ + //#if defined(USE_MEM_BYTESWAP) && defined(_MSC_VER) + // *(uint32*)mem = _byteswap_ulong(i); + //#elif defined(USE_MEM_BYTESWAP) && (__GNUC__ > 3) && (__GNUC_MINOR__ > 2) + // *(uint32*)mem = __builtin_bswap32(i); + //#else + // mem[0]=byte(i>>24); + // mem[1]=byte(i>>16); + // mem[2]=byte(i>>8); + // mem[3]=byte(i); + //#endif + //} + + + //inline uint32 ByteSwap32(uint32 i) + //{ + //#ifdef _MSC_VER + // return _byteswap_ulong(i); + //#elif (__GNUC__ > 3) && (__GNUC_MINOR__ > 2) + // return __builtin_bswap32(i); + //#else + // return (rotl32(i,24)&0xFF00FF00)|(rotl32(i,8)&0x00FF00FF); + //#endif + //} } diff --git a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack15_cpp.cs b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack15_cpp.cs index b661725d..80c2d03c 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack15_cpp.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack15_cpp.cs @@ -1,394 +1,367 @@ -using System; +using System; using static SharpCompress.Compressors.Rar.UnpackV2017.Unpack.Unpack15Local; -namespace SharpCompress.Compressors.Rar.UnpackV2017 +namespace SharpCompress.Compressors.Rar.UnpackV2017; + +internal partial class Unpack { - internal partial class Unpack + private const int STARTL1 = 2; + + private static readonly uint[] DecL1 = { - private const int STARTL1 = 2; + 0x8000, + 0xa000, + 0xc000, + 0xd000, + 0xe000, + 0xea00, + 0xee00, + 0xf000, + 0xf200, + 0xf200, + 0xffff + }; - private static readonly uint[] DecL1 = + private static readonly uint[] PosL1 = { 0, 0, 0, 2, 3, 5, 7, 11, 16, 20, 24, 32, 32 }; + + private const int STARTL2 = 3; + + private static readonly uint[] DecL2 = + { + 0xa000, + 0xc000, + 0xd000, + 0xe000, + 0xea00, + 0xee00, + 0xf000, + 0xf200, + 0xf240, + 0xffff + }; + + private static readonly uint[] PosL2 = { 0, 0, 0, 0, 5, 7, 9, 13, 18, 22, 26, 34, 36 }; + + private const int STARTHF0 = 4; + + private static readonly uint[] DecHf0 = + { + 0x8000, + 0xc000, + 0xe000, + 0xf200, + 0xf200, + 0xf200, + 0xf200, + 0xf200, + 0xffff + }; + + private static readonly uint[] PosHf0 = { 0, 0, 0, 0, 0, 8, 16, 24, 33, 33, 33, 33, 33 }; + + private const int STARTHF1 = 5; + + private static readonly uint[] DecHf1 = + { + 0x2000, + 0xc000, + 0xe000, + 0xf000, + 0xf200, + 0xf200, + 0xf7e0, + 0xffff + }; + + private static readonly uint[] PosHf1 = { 0, 0, 0, 0, 0, 0, 4, 44, 60, 76, 80, 80, 127 }; + + private const int STARTHF2 = 5; + + private static readonly uint[] DecHf2 = + { + 0x1000, + 0x2400, + 0x8000, + 0xc000, + 0xfa00, + 0xffff, + 0xffff, + 0xffff + }; + + private static readonly uint[] PosHf2 = { 0, 0, 0, 0, 0, 0, 2, 7, 53, 117, 233, 0, 0 }; + + private const int STARTHF3 = 6; + + private static readonly uint[] DecHf3 = + { + 0x800, + 0x2400, + 0xee00, + 0xfe80, + 0xffff, + 0xffff, + 0xffff + }; + + private static readonly uint[] PosHf3 = { 0, 0, 0, 0, 0, 0, 0, 2, 16, 218, 251, 0, 0 }; + + private const int STARTHF4 = 8; + private static readonly uint[] DecHf4 = { 0xff00, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff }; + private static readonly uint[] PosHf4 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0 }; + + private void Unpack15(bool Solid) + { + UnpInitData(Solid); + UnpInitData15(Solid); + UnpReadBuf(); + if (!Solid) { - 0x8000, - 0xa000, - 0xc000, - 0xd000, - 0xe000, - 0xea00, - 0xee00, - 0xf000, - 0xf200, - 0xf200, - 0xffff - }; - - private static readonly uint[] PosL1 = { 0, 0, 0, 2, 3, 5, 7, 11, 16, 20, 24, 32, 32 }; - - private const int STARTL2 = 3; - - private static readonly uint[] DecL2 = + InitHuff(); + UnpPtr = 0; + } + else { - 0xa000, - 0xc000, - 0xd000, - 0xe000, - 0xea00, - 0xee00, - 0xf000, - 0xf200, - 0xf240, - 0xffff - }; + UnpPtr = WrPtr; + } - private static readonly uint[] PosL2 = { 0, 0, 0, 0, 5, 7, 9, 13, 18, 22, 26, 34, 36 }; - - private const int STARTHF0 = 4; - - private static readonly uint[] DecHf0 = + --DestUnpSize; + if (DestUnpSize >= 0) { - 0x8000, - 0xc000, - 0xe000, - 0xf200, - 0xf200, - 0xf200, - 0xf200, - 0xf200, - 0xffff - }; + GetFlagsBuf(); + FlagsCnt = 8; + } - private static readonly uint[] PosHf0 = { 0, 0, 0, 0, 0, 8, 16, 24, 33, 33, 33, 33, 33 }; - - private const int STARTHF1 = 5; - - private static readonly uint[] DecHf1 = + while (DestUnpSize >= 0) { - 0x2000, - 0xc000, - 0xe000, - 0xf000, - 0xf200, - 0xf200, - 0xf7e0, - 0xffff - }; + UnpPtr &= MaxWinMask; - private static readonly uint[] PosHf1 = { 0, 0, 0, 0, 0, 0, 4, 44, 60, 76, 80, 80, 127 }; - - private const int STARTHF2 = 5; - - private static readonly uint[] DecHf2 = - { - 0x1000, - 0x2400, - 0x8000, - 0xc000, - 0xfa00, - 0xffff, - 0xffff, - 0xffff - }; - - private static readonly uint[] PosHf2 = { 0, 0, 0, 0, 0, 0, 2, 7, 53, 117, 233, 0, 0 }; - - private const int STARTHF3 = 6; - - private static readonly uint[] DecHf3 = - { - 0x800, - 0x2400, - 0xee00, - 0xfe80, - 0xffff, - 0xffff, - 0xffff - }; - - private static readonly uint[] PosHf3 = { 0, 0, 0, 0, 0, 0, 0, 2, 16, 218, 251, 0, 0 }; - - private const int STARTHF4 = 8; - private static readonly uint[] DecHf4 = { 0xff00, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff }; - private static readonly uint[] PosHf4 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0 }; - - private void Unpack15(bool Solid) - { - UnpInitData(Solid); - UnpInitData15(Solid); - UnpReadBuf(); - if (!Solid) + if (Inp.InAddr > ReadTop - 30 && !UnpReadBuf()) { - InitHuff(); - UnpPtr = 0; + break; + } + + if (((WrPtr - UnpPtr) & MaxWinMask) < 270 && WrPtr != UnpPtr) + { + UnpWriteBuf20(); + } + + if (StMode != 0) + { + HuffDecode(); + continue; + } + + if (--FlagsCnt < 0) + { + GetFlagsBuf(); + FlagsCnt = 7; + } + + if ((FlagBuf & 0x80) != 0) + { + FlagBuf <<= 1; + if (Nlzb > Nhfb) + { + LongLZ(); + } + else + { + HuffDecode(); + } } else { - UnpPtr = WrPtr; - } - - --DestUnpSize; - if (DestUnpSize >= 0) - { - GetFlagsBuf(); - FlagsCnt = 8; - } - - while (DestUnpSize >= 0) - { - UnpPtr &= MaxWinMask; - - if (Inp.InAddr > ReadTop - 30 && !UnpReadBuf()) - { - break; - } - - if (((WrPtr - UnpPtr) & MaxWinMask) < 270 && WrPtr != UnpPtr) - { - UnpWriteBuf20(); - } - - if (StMode != 0) - { - HuffDecode(); - continue; - } - + FlagBuf <<= 1; if (--FlagsCnt < 0) { GetFlagsBuf(); FlagsCnt = 7; } - if ((FlagBuf & 0x80) != 0) { FlagBuf <<= 1; if (Nlzb > Nhfb) { - LongLZ(); + HuffDecode(); } else { - HuffDecode(); + LongLZ(); } } else { FlagBuf <<= 1; - if (--FlagsCnt < 0) - { - GetFlagsBuf(); - FlagsCnt = 7; - } - if ((FlagBuf & 0x80) != 0) - { - FlagBuf <<= 1; - if (Nlzb > Nhfb) - { - HuffDecode(); - } - else - { - LongLZ(); - } - } - else - { - FlagBuf <<= 1; - ShortLZ(); - } + ShortLZ(); } } - UnpWriteBuf20(); + } + UnpWriteBuf20(); + } + + //#define GetShortLen1(pos) ((pos)==1 ? Buf60+3:ShortLen1[pos]) + private uint GetShortLen1(uint pos) + { + return ((pos) == 1 ? (uint)(Buf60 + 3) : ShortLen1[pos]); + } + + //#define GetShortLen2(pos) ((pos)==3 ? Buf60+3:ShortLen2[pos]) + private uint GetShortLen2(uint pos) + { + return ((pos) == 3 ? (uint)(Buf60 + 3) : ShortLen2[pos]); + } + + internal static class Unpack15Local + { + public static readonly uint[] ShortLen1 = + { + 1, + 3, + 4, + 4, + 5, + 6, + 7, + 8, + 8, + 4, + 4, + 5, + 6, + 6, + 4, + 0 + }; + public static readonly uint[] ShortXor1 = + { + 0, + 0xa0, + 0xd0, + 0xe0, + 0xf0, + 0xf8, + 0xfc, + 0xfe, + 0xff, + 0xc0, + 0x80, + 0x90, + 0x98, + 0x9c, + 0xb0 + }; + public static readonly uint[] ShortLen2 = + { + 2, + 3, + 3, + 3, + 4, + 4, + 5, + 6, + 6, + 4, + 4, + 5, + 6, + 6, + 4, + 0 + }; + public static readonly uint[] ShortXor2 = + { + 0, + 0x40, + 0x60, + 0xa0, + 0xd0, + 0xe0, + 0xf0, + 0xf8, + 0xfc, + 0xc0, + 0x80, + 0x90, + 0x98, + 0x9c, + 0xb0 + }; + } + + private void ShortLZ() + { + uint Length, + SaveLength; + uint LastDistance; + uint Distance; + int DistancePlace; + NumHuf = 0; + + var BitField = Inp.fgetbits(); + if (LCount == 2) + { + Inp.faddbits(1); + if (BitField >= 0x8000) + { + CopyString15(LastDist, LastLength); + return; + } + BitField <<= 1; + LCount = 0; } - //#define GetShortLen1(pos) ((pos)==1 ? Buf60+3:ShortLen1[pos]) - private uint GetShortLen1(uint pos) - { - return ((pos) == 1 ? (uint)(Buf60 + 3) : ShortLen1[pos]); - } + BitField >>= 8; - //#define GetShortLen2(pos) ((pos)==3 ? Buf60+3:ShortLen2[pos]) - private uint GetShortLen2(uint pos) - { - return ((pos) == 3 ? (uint)(Buf60 + 3) : ShortLen2[pos]); - } + // not thread safe, replaced by GetShortLen1 and GetShortLen2 macro + // ShortLen1[1]=ShortLen2[3]=Buf60+3; - internal static class Unpack15Local + if (AvrLn1 < 37) { - public static readonly uint[] ShortLen1 = + for (Length = 0; ; Length++) { - 1, - 3, - 4, - 4, - 5, - 6, - 7, - 8, - 8, - 4, - 4, - 5, - 6, - 6, - 4, - 0 - }; - public static readonly uint[] ShortXor1 = - { - 0, - 0xa0, - 0xd0, - 0xe0, - 0xf0, - 0xf8, - 0xfc, - 0xfe, - 0xff, - 0xc0, - 0x80, - 0x90, - 0x98, - 0x9c, - 0xb0 - }; - public static readonly uint[] ShortLen2 = - { - 2, - 3, - 3, - 3, - 4, - 4, - 5, - 6, - 6, - 4, - 4, - 5, - 6, - 6, - 4, - 0 - }; - public static readonly uint[] ShortXor2 = - { - 0, - 0x40, - 0x60, - 0xa0, - 0xd0, - 0xe0, - 0xf0, - 0xf8, - 0xfc, - 0xc0, - 0x80, - 0x90, - 0x98, - 0x9c, - 0xb0 - }; - } - - private void ShortLZ() - { - uint Length, - SaveLength; - uint LastDistance; - uint Distance; - int DistancePlace; - NumHuf = 0; - - uint BitField = Inp.fgetbits(); - if (LCount == 2) - { - Inp.faddbits(1); - if (BitField >= 0x8000) + if ( + ((BitField ^ ShortXor1[Length]) & (~(0xff >> (int)GetShortLen1(Length)))) + == 0 + ) { - CopyString15((uint)LastDist, LastLength); - return; + break; } - BitField <<= 1; + } + + Inp.faddbits(GetShortLen1(Length)); + } + else + { + for (Length = 0; ; Length++) + { + if ( + ((BitField ^ ShortXor2[Length]) & (~(0xff >> (int)GetShortLen2(Length)))) + == 0 + ) + { + break; + } + } + + Inp.faddbits(GetShortLen2(Length)); + } + + if (Length >= 9) + { + if (Length == 9) + { + LCount++; + CopyString15(LastDist, LastLength); + return; + } + if (Length == 14) + { LCount = 0; - } - - BitField >>= 8; - - // not thread safe, replaced by GetShortLen1 and GetShortLen2 macro - // ShortLen1[1]=ShortLen2[3]=Buf60+3; - - if (AvrLn1 < 37) - { - for (Length = 0; ; Length++) - { - if ( - ((BitField ^ ShortXor1[Length]) & (~(0xff >> (int)GetShortLen1(Length)))) - == 0 - ) - { - break; - } - } - - Inp.faddbits(GetShortLen1(Length)); - } - else - { - for (Length = 0; ; Length++) - { - if ( - ((BitField ^ ShortXor2[Length]) & (~(0xff >> (int)GetShortLen2(Length)))) - == 0 - ) - { - break; - } - } - - Inp.faddbits(GetShortLen2(Length)); - } - - if (Length >= 9) - { - if (Length == 9) - { - LCount++; - CopyString15((uint)LastDist, LastLength); - return; - } - if (Length == 14) - { - LCount = 0; - Length = DecodeNum(Inp.fgetbits(), STARTL2, DecL2, PosL2) + 5; - Distance = (Inp.fgetbits() >> 1) | 0x8000; - Inp.faddbits(15); - LastLength = Length; - LastDist = Distance; - CopyString15(Distance, Length); - return; - } - - LCount = 0; - SaveLength = Length; - Distance = OldDist[(OldDistPtr - (Length - 9)) & 3]; - Length = DecodeNum(Inp.fgetbits(), STARTL1, DecL1, PosL1) + 2; - if (Length == 0x101 && SaveLength == 10) - { - Buf60 ^= 1; - return; - } - if (Distance > 256) - { - Length++; - } - - if (Distance >= MaxDist3) - { - Length++; - } - - OldDist[OldDistPtr++] = Distance; - OldDistPtr = OldDistPtr & 3; + Length = DecodeNum(Inp.fgetbits(), STARTL2, DecL2, PosL2) + 5; + Distance = (Inp.fgetbits() >> 1) | 0x8000; + Inp.faddbits(15); LastLength = Length; LastDist = Distance; CopyString15(Distance, Length); @@ -396,345 +369,373 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 } LCount = 0; - AvrLn1 += Length; - AvrLn1 -= AvrLn1 >> 4; - - DistancePlace = (int)(DecodeNum(Inp.fgetbits(), STARTHF2, DecHf2, PosHf2) & 0xff); - Distance = ChSetA[DistancePlace]; - if (--DistancePlace != -1) + SaveLength = Length; + Distance = OldDist[(OldDistPtr - (Length - 9)) & 3]; + Length = DecodeNum(Inp.fgetbits(), STARTL1, DecL1, PosL1) + 2; + if (Length == 0x101 && SaveLength == 10) { - LastDistance = ChSetA[DistancePlace]; - ChSetA[DistancePlace + 1] = (ushort)LastDistance; - ChSetA[DistancePlace] = (ushort)Distance; + Buf60 ^= 1; + return; } - Length += 2; - OldDist[OldDistPtr++] = ++Distance; - OldDistPtr = OldDistPtr & 3; - LastLength = Length; - LastDist = Distance; - CopyString15(Distance, Length); - } - - private void LongLZ() - { - uint Length; - uint Distance; - uint DistancePlace, - NewDistancePlace; - uint OldAvr2, - OldAvr3; - - NumHuf = 0; - Nlzb += 16; - if (Nlzb > 0xff) + if (Distance > 256) { - Nlzb = 0x90; - Nhfb >>= 1; - } - OldAvr2 = AvrLn2; - - uint BitField = Inp.fgetbits(); - if (AvrLn2 >= 122) - { - Length = DecodeNum(BitField, STARTL2, DecL2, PosL2); - } - else if (AvrLn2 >= 64) - { - Length = DecodeNum(BitField, STARTL1, DecL1, PosL1); - } - else if (BitField < 0x100) - { - Length = BitField; - Inp.faddbits(16); - } - else - { - for (Length = 0; ((BitField << (int)Length) & 0x8000) == 0; Length++) - { - ; - } - - Inp.faddbits(Length + 1); + Length++; } - AvrLn2 += Length; - AvrLn2 -= AvrLn2 >> 5; - - BitField = Inp.fgetbits(); - if (AvrPlcB > 0x28ff) - { - DistancePlace = DecodeNum(BitField, STARTHF2, DecHf2, PosHf2); - } - else if (AvrPlcB > 0x6ff) - { - DistancePlace = DecodeNum(BitField, STARTHF1, DecHf1, PosHf1); - } - else - { - DistancePlace = DecodeNum(BitField, STARTHF0, DecHf0, PosHf0); - } - - AvrPlcB += DistancePlace; - AvrPlcB -= AvrPlcB >> 8; - while (true) - { - Distance = ChSetB[DistancePlace & 0xff]; - NewDistancePlace = NToPlB[Distance++ & 0xff]++; - if ((Distance & 0xff) != 0) - { - CorrHuff(ChSetB, NToPlB); - } - else - { - break; - } - } - - ChSetB[DistancePlace & 0xff] = ChSetB[NewDistancePlace]; - ChSetB[NewDistancePlace] = (ushort)Distance; - - Distance = ((Distance & 0xff00) | (Inp.fgetbits() >> 8)) >> 1; - Inp.faddbits(7); - - OldAvr3 = AvrLn3; - if (Length != 1 && Length != 4) - { - if (Length == 0 && Distance <= MaxDist3) - { - AvrLn3++; - AvrLn3 -= AvrLn3 >> 8; - } - else if (AvrLn3 > 0) - { - AvrLn3--; - } - } - - Length += 3; if (Distance >= MaxDist3) { Length++; } - if (Distance <= 256) - { - Length += 8; - } - - if (OldAvr3 > 0xb0 || AvrPlc >= 0x2a00 && OldAvr2 < 0x40) - { - MaxDist3 = 0x7f00; - } - else - { - MaxDist3 = 0x2001; - } - OldDist[OldDistPtr++] = Distance; - OldDistPtr = OldDistPtr & 3; + OldDistPtr &= 3; LastLength = Length; LastDist = Distance; CopyString15(Distance, Length); + return; } - private void HuffDecode() + LCount = 0; + AvrLn1 += Length; + AvrLn1 -= AvrLn1 >> 4; + + DistancePlace = (int)(DecodeNum(Inp.fgetbits(), STARTHF2, DecHf2, PosHf2) & 0xff); + Distance = ChSetA[DistancePlace]; + if (--DistancePlace != -1) { - uint CurByte, - NewBytePlace; - uint Length; - uint Distance; - int BytePlace; + LastDistance = ChSetA[DistancePlace]; + ChSetA[DistancePlace + 1] = (ushort)LastDistance; + ChSetA[DistancePlace] = (ushort)Distance; + } + Length += 2; + OldDist[OldDistPtr++] = ++Distance; + OldDistPtr &= 3; + LastLength = Length; + LastDist = Distance; + CopyString15(Distance, Length); + } - uint BitField = Inp.fgetbits(); + private void LongLZ() + { + uint Length; + uint Distance; + uint DistancePlace, + NewDistancePlace; + uint OldAvr2, + OldAvr3; - if (AvrPlc > 0x75ff) + NumHuf = 0; + Nlzb += 16; + if (Nlzb > 0xff) + { + Nlzb = 0x90; + Nhfb >>= 1; + } + OldAvr2 = AvrLn2; + + var BitField = Inp.fgetbits(); + if (AvrLn2 >= 122) + { + Length = DecodeNum(BitField, STARTL2, DecL2, PosL2); + } + else if (AvrLn2 >= 64) + { + Length = DecodeNum(BitField, STARTL1, DecL1, PosL1); + } + else if (BitField < 0x100) + { + Length = BitField; + Inp.faddbits(16); + } + else + { + for (Length = 0; ((BitField << (int)Length) & 0x8000) == 0; Length++) { - BytePlace = (int)DecodeNum(BitField, STARTHF4, DecHf4, PosHf4); + ; } - else if (AvrPlc > 0x5dff) + + Inp.faddbits(Length + 1); + } + + AvrLn2 += Length; + AvrLn2 -= AvrLn2 >> 5; + + BitField = Inp.fgetbits(); + if (AvrPlcB > 0x28ff) + { + DistancePlace = DecodeNum(BitField, STARTHF2, DecHf2, PosHf2); + } + else if (AvrPlcB > 0x6ff) + { + DistancePlace = DecodeNum(BitField, STARTHF1, DecHf1, PosHf1); + } + else + { + DistancePlace = DecodeNum(BitField, STARTHF0, DecHf0, PosHf0); + } + + AvrPlcB += DistancePlace; + AvrPlcB -= AvrPlcB >> 8; + while (true) + { + Distance = ChSetB[DistancePlace & 0xff]; + NewDistancePlace = NToPlB[Distance++ & 0xff]++; + if ((Distance & 0xff) != 0) { - BytePlace = (int)DecodeNum(BitField, STARTHF3, DecHf3, PosHf3); - } - else if (AvrPlc > 0x35ff) - { - BytePlace = (int)DecodeNum(BitField, STARTHF2, DecHf2, PosHf2); - } - else if (AvrPlc > 0x0dff) - { - BytePlace = (int)DecodeNum(BitField, STARTHF1, DecHf1, PosHf1); + CorrHuff(ChSetB, NToPlB); } else { - BytePlace = (int)DecodeNum(BitField, STARTHF0, DecHf0, PosHf0); + break; + } + } + + ChSetB[DistancePlace & 0xff] = ChSetB[NewDistancePlace]; + ChSetB[NewDistancePlace] = (ushort)Distance; + + Distance = ((Distance & 0xff00) | (Inp.fgetbits() >> 8)) >> 1; + Inp.faddbits(7); + + OldAvr3 = AvrLn3; + if (Length != 1 && Length != 4) + { + if (Length == 0 && Distance <= MaxDist3) + { + AvrLn3++; + AvrLn3 -= AvrLn3 >> 8; + } + else if (AvrLn3 > 0) + { + AvrLn3--; + } + } + + Length += 3; + if (Distance >= MaxDist3) + { + Length++; + } + + if (Distance <= 256) + { + Length += 8; + } + + if (OldAvr3 > 0xb0 || AvrPlc >= 0x2a00 && OldAvr2 < 0x40) + { + MaxDist3 = 0x7f00; + } + else + { + MaxDist3 = 0x2001; + } + + OldDist[OldDistPtr++] = Distance; + OldDistPtr &= 3; + LastLength = Length; + LastDist = Distance; + CopyString15(Distance, Length); + } + + private void HuffDecode() + { + uint CurByte, + NewBytePlace; + uint Length; + uint Distance; + int BytePlace; + + var BitField = Inp.fgetbits(); + + if (AvrPlc > 0x75ff) + { + BytePlace = (int)DecodeNum(BitField, STARTHF4, DecHf4, PosHf4); + } + else if (AvrPlc > 0x5dff) + { + BytePlace = (int)DecodeNum(BitField, STARTHF3, DecHf3, PosHf3); + } + else if (AvrPlc > 0x35ff) + { + BytePlace = (int)DecodeNum(BitField, STARTHF2, DecHf2, PosHf2); + } + else if (AvrPlc > 0x0dff) + { + BytePlace = (int)DecodeNum(BitField, STARTHF1, DecHf1, PosHf1); + } + else + { + BytePlace = (int)DecodeNum(BitField, STARTHF0, DecHf0, PosHf0); + } + + BytePlace &= 0xff; + if (StMode != 0) + { + if (BytePlace == 0 && BitField > 0xfff) + { + BytePlace = 0x100; } - BytePlace &= 0xff; - if (StMode != 0) + if (--BytePlace == -1) { - if (BytePlace == 0 && BitField > 0xfff) + BitField = Inp.fgetbits(); + Inp.faddbits(1); + if ((BitField & 0x8000) != 0) { - BytePlace = 0x100; - } - - if (--BytePlace == -1) - { - BitField = Inp.fgetbits(); - Inp.faddbits(1); - if ((BitField & 0x8000) != 0) - { - NumHuf = StMode = 0; - return; - } - else - { - Length = (BitField & 0x4000) != 0 ? 4U : 3; - Inp.faddbits(1); - Distance = DecodeNum(Inp.fgetbits(), STARTHF2, DecHf2, PosHf2); - Distance = (Distance << 5) | (Inp.fgetbits() >> 11); - Inp.faddbits(5); - CopyString15(Distance, Length); - return; - } - } - } - else if (NumHuf++ >= 16 && FlagsCnt == 0) - { - StMode = 1; - } - - AvrPlc += (uint)BytePlace; - AvrPlc -= AvrPlc >> 8; - Nhfb += 16; - if (Nhfb > 0xff) - { - Nhfb = 0x90; - Nlzb >>= 1; - } - - Window[UnpPtr++] = (byte)(ChSet[BytePlace] >> 8); - --DestUnpSize; - - while (true) - { - CurByte = ChSet[BytePlace]; - NewBytePlace = NToPl[CurByte++ & 0xff]++; - if ((CurByte & 0xff) > 0xa1) - { - CorrHuff(ChSet, NToPl); + NumHuf = StMode = 0; + return; } else { - break; + Length = (BitField & 0x4000) != 0 ? 4U : 3; + Inp.faddbits(1); + Distance = DecodeNum(Inp.fgetbits(), STARTHF2, DecHf2, PosHf2); + Distance = (Distance << 5) | (Inp.fgetbits() >> 11); + Inp.faddbits(5); + CopyString15(Distance, Length); + return; } } - - ChSet[BytePlace] = ChSet[NewBytePlace]; - ChSet[NewBytePlace] = (ushort)CurByte; + } + else if (NumHuf++ >= 16 && FlagsCnt == 0) + { + StMode = 1; } - private void GetFlagsBuf() + AvrPlc += (uint)BytePlace; + AvrPlc -= AvrPlc >> 8; + Nhfb += 16; + if (Nhfb > 0xff) { - uint Flags, - NewFlagsPlace; - uint FlagsPlace = DecodeNum(Inp.fgetbits(), STARTHF2, DecHf2, PosHf2); - - // Our Huffman table stores 257 items and needs all them in other parts - // of code such as when StMode is on, so the first item is control item. - // While normally we do not use the last item to code the flags byte here, - // we need to check for value 256 when unpacking in case we unpack - // a corrupt archive. - if (FlagsPlace >= ChSetC.Length) - { - return; - } - - while (true) - { - Flags = ChSetC[FlagsPlace]; - FlagBuf = Flags >> 8; - NewFlagsPlace = NToPlC[Flags++ & 0xff]++; - if ((Flags & 0xff) != 0) - { - break; - } - - CorrHuff(ChSetC, NToPlC); - } - - ChSetC[FlagsPlace] = ChSetC[NewFlagsPlace]; - ChSetC[NewFlagsPlace] = (ushort)Flags; + Nhfb = 0x90; + Nlzb >>= 1; } - private void UnpInitData15(bool Solid) + Window[UnpPtr++] = (byte)(ChSet[BytePlace] >> 8); + --DestUnpSize; + + while (true) { - if (!Solid) + CurByte = ChSet[BytePlace]; + NewBytePlace = NToPl[CurByte++ & 0xff]++; + if ((CurByte & 0xff) > 0xa1) { - AvrPlcB = AvrLn1 = AvrLn2 = AvrLn3 = 0; - NumHuf = Buf60 = 0; - AvrPlc = 0x3500; - MaxDist3 = 0x2001; - Nhfb = Nlzb = 0x80; + CorrHuff(ChSet, NToPl); } - FlagsCnt = 0; - FlagBuf = 0; - StMode = 0; - LCount = 0; - ReadTop = 0; - } - - private void InitHuff() - { - for (uint I = 0; I < 256; I++) + else { - ChSet[I] = ChSetB[I] = (ushort)(I << 8); - ChSetA[I] = (ushort)I; - ChSetC[I] = (ushort)(((~I + 1) & 0xff) << 8); - } - new Span(NToPl).Clear(); - new Span(NToPlB).Clear(); - new Span(NToPlC).Clear(); - CorrHuff(ChSetB, NToPlB); - } - - private void CorrHuff(ushort[] CharSet, byte[] NumToPlace) - { - int I, - J; - for (I = 7; I >= 0; I--) - for (J = 0; J < 32; J++) - { - CharSet[J] = (ushort)((CharSet[J] & ~0xff) | I); - } - - new Span(NumToPlace, 0, NToPl.Length).Clear(); - for (I = 6; I >= 0; I--) - { - NumToPlace[I] = (byte)((7 - I) * 32); + break; } } - private void CopyString15(uint Distance, uint Length) + ChSet[BytePlace] = ChSet[NewBytePlace]; + ChSet[NewBytePlace] = (ushort)CurByte; + } + + private void GetFlagsBuf() + { + uint Flags, + NewFlagsPlace; + var FlagsPlace = DecodeNum(Inp.fgetbits(), STARTHF2, DecHf2, PosHf2); + + // Our Huffman table stores 257 items and needs all them in other parts + // of code such as when StMode is on, so the first item is control item. + // While normally we do not use the last item to code the flags byte here, + // we need to check for value 256 when unpacking in case we unpack + // a corrupt archive. + if (FlagsPlace >= ChSetC.Length) { - DestUnpSize -= Length; - while (Length-- != 0) + return; + } + + while (true) + { + Flags = ChSetC[FlagsPlace]; + FlagBuf = Flags >> 8; + NewFlagsPlace = NToPlC[Flags++ & 0xff]++; + if ((Flags & 0xff) != 0) { - Window[UnpPtr] = Window[(UnpPtr - Distance) & MaxWinMask]; - UnpPtr = (UnpPtr + 1) & MaxWinMask; + break; + } + + CorrHuff(ChSetC, NToPlC); + } + + ChSetC[FlagsPlace] = ChSetC[NewFlagsPlace]; + ChSetC[NewFlagsPlace] = (ushort)Flags; + } + + private void UnpInitData15(bool Solid) + { + if (!Solid) + { + AvrPlcB = AvrLn1 = AvrLn2 = AvrLn3 = 0; + NumHuf = Buf60 = 0; + AvrPlc = 0x3500; + MaxDist3 = 0x2001; + Nhfb = Nlzb = 0x80; + } + FlagsCnt = 0; + FlagBuf = 0; + StMode = 0; + LCount = 0; + ReadTop = 0; + } + + private void InitHuff() + { + for (uint I = 0; I < 256; I++) + { + ChSet[I] = ChSetB[I] = (ushort)(I << 8); + ChSetA[I] = (ushort)I; + ChSetC[I] = (ushort)(((~I + 1) & 0xff) << 8); + } + new Span(NToPl).Clear(); + new Span(NToPlB).Clear(); + new Span(NToPlC).Clear(); + CorrHuff(ChSetB, NToPlB); + } + + private void CorrHuff(ushort[] CharSet, byte[] NumToPlace) + { + int I, + J; + for (I = 7; I >= 0; I--) + { + for (J = 0; J < 32; J++) + { + CharSet[J] = (ushort)((CharSet[J] & ~0xff) | I); } } - private uint DecodeNum(uint Num, uint StartPos, uint[] DecTab, uint[] PosTab) + new Span(NumToPlace, 0, NToPl.Length).Clear(); + for (I = 6; I >= 0; I--) { - int I; - for (Num &= 0xfff0, I = 0; DecTab[I] <= Num; I++) - { - StartPos++; - } - - Inp.faddbits(StartPos); - return ( - ((Num - (I != 0 ? DecTab[I - 1] : 0)) >> (int)(16 - StartPos)) + PosTab[StartPos] - ); + NumToPlace[I] = (byte)((7 - I) * 32); } } + + private void CopyString15(uint Distance, uint Length) + { + DestUnpSize -= Length; + while (Length-- != 0) + { + Window[UnpPtr] = Window[(UnpPtr - Distance) & MaxWinMask]; + UnpPtr = (UnpPtr + 1) & MaxWinMask; + } + } + + private uint DecodeNum(uint Num, uint StartPos, uint[] DecTab, uint[] PosTab) + { + int I; + for (Num &= 0xfff0, I = 0; DecTab[I] <= Num; I++) + { + StartPos++; + } + + Inp.faddbits(StartPos); + return ( + ((Num - (I != 0 ? DecTab[I - 1] : 0)) >> (int)(16 - StartPos)) + PosTab[StartPos] + ); + } } diff --git a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack20_cpp.cs b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack20_cpp.cs index 52133cf9..d43a4ff2 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack20_cpp.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack20_cpp.cs @@ -1,304 +1,244 @@ -#if !Rar2017_64bit -using nint = System.Int32; -using nuint = System.UInt32; -using size_t = System.UInt32; +#if !Rar2017_64bit #else using nint = System.Int64; using nuint = System.UInt64; using size_t = System.UInt64; #endif -using int64 = System.Int64; - using System; using static SharpCompress.Compressors.Rar.UnpackV2017.PackDef; using static SharpCompress.Compressors.Rar.UnpackV2017.Unpack.Unpack20Local; -namespace SharpCompress.Compressors.Rar.UnpackV2017 +namespace SharpCompress.Compressors.Rar.UnpackV2017; + +internal partial class Unpack { - internal partial class Unpack + private void CopyString20(uint Length, uint Distance) { - private void CopyString20(uint Length, uint Distance) + LastDist = OldDist[OldDistPtr++ & 3] = Distance; + LastLength = Length; + DestUnpSize -= Length; + CopyString(Length, Distance); + } + + internal static class Unpack20Local + { + public static readonly byte[] LDecode = { - LastDist = OldDist[OldDistPtr++ & 3] = Distance; - LastLength = Length; - DestUnpSize -= Length; - CopyString(Length, Distance); + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 10, + 12, + 14, + 16, + 20, + 24, + 28, + 32, + 40, + 48, + 56, + 64, + 80, + 96, + 112, + 128, + 160, + 192, + 224 + }; + public static readonly byte[] LBits = + { + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 4, + 4, + 4, + 4, + 5, + 5, + 5, + 5 + }; + public static readonly uint[] DDecode = + { + 0, + 1, + 2, + 3, + 4, + 6, + 8, + 12, + 16, + 24, + 32, + 48, + 64, + 96, + 128, + 192, + 256, + 384, + 512, + 768, + 1024, + 1536, + 2048, + 3072, + 4096, + 6144, + 8192, + 12288, + 16384, + 24576, + 32768U, + 49152U, + 65536, + 98304, + 131072, + 196608, + 262144, + 327680, + 393216, + 458752, + 524288, + 589824, + 655360, + 720896, + 786432, + 851968, + 917504, + 983040 + }; + public static readonly byte[] DBits = + { + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 2, + 3, + 3, + 4, + 4, + 5, + 5, + 6, + 6, + 7, + 7, + 8, + 8, + 9, + 9, + 10, + 10, + 11, + 11, + 12, + 12, + 13, + 13, + 14, + 14, + 15, + 15, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16 + }; + public static readonly byte[] SDDecode = { 0, 4, 8, 16, 32, 64, 128, 192 }; + public static readonly byte[] SDBits = { 2, 2, 3, 4, 5, 6, 6, 6 }; + } + + private void Unpack20(bool Solid) + { + uint Bits; + + if (Suspended) + { + UnpPtr = WrPtr; } - - internal static class Unpack20Local + else { - public static readonly byte[] LDecode = + UnpInitData(Solid); + if (!UnpReadBuf()) { - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 10, - 12, - 14, - 16, - 20, - 24, - 28, - 32, - 40, - 48, - 56, - 64, - 80, - 96, - 112, - 128, - 160, - 192, - 224 - }; - public static readonly byte[] LBits = - { - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1, - 1, - 1, - 1, - 2, - 2, - 2, - 2, - 3, - 3, - 3, - 3, - 4, - 4, - 4, - 4, - 5, - 5, - 5, - 5 - }; - public static readonly uint[] DDecode = - { - 0, - 1, - 2, - 3, - 4, - 6, - 8, - 12, - 16, - 24, - 32, - 48, - 64, - 96, - 128, - 192, - 256, - 384, - 512, - 768, - 1024, - 1536, - 2048, - 3072, - 4096, - 6144, - 8192, - 12288, - 16384, - 24576, - 32768U, - 49152U, - 65536, - 98304, - 131072, - 196608, - 262144, - 327680, - 393216, - 458752, - 524288, - 589824, - 655360, - 720896, - 786432, - 851968, - 917504, - 983040 - }; - public static readonly byte[] DBits = - { - 0, - 0, - 0, - 0, - 1, - 1, - 2, - 2, - 3, - 3, - 4, - 4, - 5, - 5, - 6, - 6, - 7, - 7, - 8, - 8, - 9, - 9, - 10, - 10, - 11, - 11, - 12, - 12, - 13, - 13, - 14, - 14, - 15, - 15, - 16, - 16, - 16, - 16, - 16, - 16, - 16, - 16, - 16, - 16, - 16, - 16, - 16, - 16 - }; - public static readonly byte[] SDDecode = { 0, 4, 8, 16, 32, 64, 128, 192 }; - public static readonly byte[] SDBits = { 2, 2, 3, 4, 5, 6, 6, 6 }; - } - - private void Unpack20(bool Solid) - { - uint Bits; - - if (Suspended) - { - UnpPtr = WrPtr; + return; } - else + + if ((!Solid || !TablesRead2) && !ReadTables20()) + { + return; + } + + --DestUnpSize; + } + + while (DestUnpSize >= 0) + { + UnpPtr &= MaxWinMask; + + if (Inp.InAddr > ReadTop - 30) { - UnpInitData(Solid); if (!UnpReadBuf()) { - return; + break; } - - if ((!Solid || !TablesRead2) && !ReadTables20()) - { - return; - } - - --DestUnpSize; } - while (DestUnpSize >= 0) + if (((WrPtr - UnpPtr) & MaxWinMask) < 270 && WrPtr != UnpPtr) { - UnpPtr &= MaxWinMask; - - if (Inp.InAddr > ReadTop - 30) + UnpWriteBuf20(); + if (Suspended) { - if (!UnpReadBuf()) - { - break; - } + return; } + } + if (UnpAudioBlock) + { + var AudioNumber = DecodeNumber(Inp, MD[UnpCurChannel]); - if (((WrPtr - UnpPtr) & MaxWinMask) < 270 && WrPtr != UnpPtr) - { - UnpWriteBuf20(); - if (Suspended) - { - return; - } - } - if (UnpAudioBlock) - { - uint AudioNumber = DecodeNumber(Inp, MD[UnpCurChannel]); - - if (AudioNumber == 256) - { - if (!ReadTables20()) - { - break; - } - - continue; - } - Window[UnpPtr++] = DecodeAudio((int)AudioNumber); - if (++UnpCurChannel == UnpChannels) - { - UnpCurChannel = 0; - } - - --DestUnpSize; - continue; - } - - uint Number = DecodeNumber(Inp, BlockTables.LD); - if (Number < 256) - { - Window[UnpPtr++] = (byte)Number; - --DestUnpSize; - continue; - } - if (Number > 269) - { - uint Length = (uint)(LDecode[Number -= 270] + 3); - if ((Bits = LBits[Number]) > 0) - { - Length += Inp.getbits() >> (int)(16 - Bits); - Inp.addbits(Bits); - } - - uint DistNumber = DecodeNumber(Inp, BlockTables.DD); - uint Distance = DDecode[DistNumber] + 1; - if ((Bits = DBits[DistNumber]) > 0) - { - Distance += Inp.getbits() >> (int)(16 - Bits); - Inp.addbits(Bits); - } - - if (Distance >= 0x2000) - { - Length++; - if (Distance >= 0x40000L) - { - Length++; - } - } - - CopyString20(Length, Distance); - continue; - } - if (Number == 269) + if (AudioNumber == 256) { if (!ReadTables20()) { @@ -307,78 +247,176 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 continue; } - if (Number == 256) + Window[UnpPtr++] = DecodeAudio((int)AudioNumber); + if (++UnpCurChannel == UnpChannels) { - CopyString20(LastLength, LastDist); - continue; + UnpCurChannel = 0; } - if (Number < 261) + + --DestUnpSize; + continue; + } + + var Number = DecodeNumber(Inp, BlockTables.LD); + if (Number < 256) + { + Window[UnpPtr++] = (byte)Number; + --DestUnpSize; + continue; + } + if (Number > 269) + { + var Length = (uint)(LDecode[Number -= 270] + 3); + if ((Bits = LBits[Number]) > 0) { - uint Distance = OldDist[(OldDistPtr - (Number - 256)) & 3]; - uint LengthNumber = DecodeNumber(Inp, BlockTables.RD); - uint Length = (uint)(LDecode[LengthNumber] + 2); - if ((Bits = LBits[LengthNumber]) > 0) - { - Length += Inp.getbits() >> (int)(16 - Bits); - Inp.addbits(Bits); - } - if (Distance >= 0x101) + Length += Inp.getbits() >> (int)(16 - Bits); + Inp.addbits(Bits); + } + + var DistNumber = DecodeNumber(Inp, BlockTables.DD); + var Distance = DDecode[DistNumber] + 1; + if ((Bits = DBits[DistNumber]) > 0) + { + Distance += Inp.getbits() >> (int)(16 - Bits); + Inp.addbits(Bits); + } + + if (Distance >= 0x2000) + { + Length++; + if (Distance >= 0x40000L) { Length++; - if (Distance >= 0x2000) + } + } + + CopyString20(Length, Distance); + continue; + } + if (Number == 269) + { + if (!ReadTables20()) + { + break; + } + + continue; + } + if (Number == 256) + { + CopyString20(LastLength, LastDist); + continue; + } + if (Number < 261) + { + var Distance = OldDist[(OldDistPtr - (Number - 256)) & 3]; + var LengthNumber = DecodeNumber(Inp, BlockTables.RD); + var Length = (uint)(LDecode[LengthNumber] + 2); + if ((Bits = LBits[LengthNumber]) > 0) + { + Length += Inp.getbits() >> (int)(16 - Bits); + Inp.addbits(Bits); + } + if (Distance >= 0x101) + { + Length++; + if (Distance >= 0x2000) + { + Length++; + if (Distance >= 0x40000) { Length++; - if (Distance >= 0x40000) - { - Length++; - } } } - CopyString20(Length, Distance); - continue; } - if (Number < 270) + CopyString20(Length, Distance); + continue; + } + if (Number < 270) + { + var Distance = (uint)(SDDecode[Number -= 261] + 1); + if ((Bits = SDBits[Number]) > 0) { - uint Distance = (uint)(SDDecode[Number -= 261] + 1); - if ((Bits = SDBits[Number]) > 0) - { - Distance += Inp.getbits() >> (int)(16 - Bits); - Inp.addbits(Bits); - } - CopyString20(2, Distance); - continue; + Distance += Inp.getbits() >> (int)(16 - Bits); + Inp.addbits(Bits); } + CopyString20(2, Distance); + continue; } - ReadLastTables(); - UnpWriteBuf20(); + } + ReadLastTables(); + UnpWriteBuf20(); + } + + private void UnpWriteBuf20() + { + if (UnpPtr != WrPtr) + { + UnpSomeRead = true; } - private void UnpWriteBuf20() + if (UnpPtr < WrPtr) { - if (UnpPtr != WrPtr) - { - UnpSomeRead = true; - } - - if (UnpPtr < WrPtr) - { - UnpIO_UnpWrite(Window, WrPtr, (uint)(-(int)WrPtr & MaxWinMask)); - UnpIO_UnpWrite(Window, 0, UnpPtr); - UnpAllBuf = true; - } - else - { - UnpIO_UnpWrite(Window, WrPtr, UnpPtr - WrPtr); - } - - WrPtr = UnpPtr; + UnpIO_UnpWrite(Window, WrPtr, (uint)(-(int)WrPtr & MaxWinMask)); + UnpIO_UnpWrite(Window, 0, UnpPtr); + UnpAllBuf = true; + } + else + { + UnpIO_UnpWrite(Window, WrPtr, UnpPtr - WrPtr); } - private bool ReadTables20() + WrPtr = UnpPtr; + } + + private bool ReadTables20() + { + var BitLength = new byte[BC20]; + var Table = new byte[MC20 * 4]; + if (Inp.InAddr > ReadTop - 25) { - byte[] BitLength = new byte[BC20]; - byte[] Table = new byte[MC20 * 4]; - if (Inp.InAddr > ReadTop - 25) + if (!UnpReadBuf()) + { + return false; + } + } + + var BitField = Inp.getbits(); + UnpAudioBlock = (BitField & 0x8000) != 0; + + if ((BitField & 0x4000) != 0) + { + new Span(UnpOldTable20).Clear(); + } + + Inp.addbits(2); + + uint TableSize; + if (UnpAudioBlock) + { + UnpChannels = ((BitField >> 12) & 3) + 1; + if (UnpCurChannel >= UnpChannels) + { + UnpCurChannel = 0; + } + + Inp.addbits(2); + TableSize = MC20 * UnpChannels; + } + else + { + TableSize = NC20 + DC20 + RC20; + } + + for (uint I = 0; I < BC20; I++) + { + BitLength[I] = (byte)(Inp.getbits() >> 12); + Inp.addbits(4); + } + MakeDecodeTables(BitLength, 0, BlockTables.BD, BC20); + for (uint I = 0; I < TableSize;) + { + if (Inp.InAddr > ReadTop - 5) { if (!UnpReadBuf()) { @@ -386,279 +424,235 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 } } - uint BitField = Inp.getbits(); - UnpAudioBlock = (BitField & 0x8000) != 0; - - if ((BitField & 0x4000) != 0) + var Number = DecodeNumber(Inp, BlockTables.BD); + if (Number < 16) { - new Span(UnpOldTable20).Clear(); + Table[I] = (byte)((Number + UnpOldTable20[I]) & 0xf); + I++; } - - Inp.addbits(2); - - uint TableSize; - if (UnpAudioBlock) + else if (Number == 16) { - UnpChannels = ((BitField >> 12) & 3) + 1; - if (UnpCurChannel >= UnpChannels) - { - UnpCurChannel = 0; - } - + var N = (Inp.getbits() >> 14) + 3; Inp.addbits(2); - TableSize = MC20 * UnpChannels; - } - else - { - TableSize = NC20 + DC20 + RC20; - } - - for (uint I = 0; I < BC20; I++) - { - BitLength[I] = (byte)(Inp.getbits() >> 12); - Inp.addbits(4); - } - MakeDecodeTables(BitLength, 0, BlockTables.BD, BC20); - for (uint I = 0; I < TableSize; ) - { - if (Inp.InAddr > ReadTop - 5) + if (I == 0) { - if (!UnpReadBuf()) - { - return false; - } - } - - uint Number = DecodeNumber(Inp, BlockTables.BD); - if (Number < 16) - { - Table[I] = (byte)((Number + UnpOldTable20[I]) & 0xf); - I++; - } - else if (Number == 16) - { - uint N = (Inp.getbits() >> 14) + 3; - Inp.addbits(2); - if (I == 0) - { - return false; // We cannot have "repeat previous" code at the first position. - } - else - { - while (N-- > 0 && I < TableSize) - { - Table[I] = Table[I - 1]; - I++; - } - } + return false; // We cannot have "repeat previous" code at the first position. } else { - uint N; - if (Number == 17) - { - N = (Inp.getbits() >> 13) + 3; - Inp.addbits(3); - } - else - { - N = (Inp.getbits() >> 9) + 11; - Inp.addbits(7); - } while (N-- > 0 && I < TableSize) { - Table[I++] = 0; + Table[I] = Table[I - 1]; + I++; } } } - TablesRead2 = true; - if (Inp.InAddr > ReadTop) - { - return true; - } - - if (UnpAudioBlock) - { - for (uint I = 0; I < UnpChannels; I++) - { - MakeDecodeTables(Table, (int)(I * MC20), MD[I], MC20); - } - } else { - MakeDecodeTables(Table, 0, BlockTables.LD, NC20); - MakeDecodeTables(Table, (int)NC20, BlockTables.DD, DC20); - MakeDecodeTables(Table, (int)(NC20 + DC20), BlockTables.RD, RC20); + uint N; + if (Number == 17) + { + N = (Inp.getbits() >> 13) + 3; + Inp.addbits(3); + } + else + { + N = (Inp.getbits() >> 9) + 11; + Inp.addbits(7); + } + while (N-- > 0 && I < TableSize) + { + Table[I++] = 0; + } } - //x memcpy(UnpOldTable20,Table,sizeof(UnpOldTable20)); - Array.Copy(Table, UnpOldTable20, UnpOldTable20.Length); + } + TablesRead2 = true; + if (Inp.InAddr > ReadTop) + { return true; } - private void ReadLastTables() + if (UnpAudioBlock) { - if (ReadTop >= Inp.InAddr + 5) + for (uint I = 0; I < UnpChannels; I++) { - if (UnpAudioBlock) - { - if (DecodeNumber(Inp, MD[UnpCurChannel]) == 256) - { - ReadTables20(); - } - } - else if (DecodeNumber(Inp, BlockTables.LD) == 269) + MakeDecodeTables(Table, (int)(I * MC20), MD[I], MC20); + } + } + else + { + MakeDecodeTables(Table, 0, BlockTables.LD, NC20); + MakeDecodeTables(Table, (int)NC20, BlockTables.DD, DC20); + MakeDecodeTables(Table, (int)(NC20 + DC20), BlockTables.RD, RC20); + } + //x memcpy(UnpOldTable20,Table,sizeof(UnpOldTable20)); + Array.Copy(Table, UnpOldTable20, UnpOldTable20.Length); + return true; + } + + private void ReadLastTables() + { + if (ReadTop >= Inp.InAddr + 5) + { + if (UnpAudioBlock) + { + if (DecodeNumber(Inp, MD[UnpCurChannel]) == 256) { ReadTables20(); } } - } - - private void UnpInitData20(bool Solid) - { - if (!Solid) + else if (DecodeNumber(Inp, BlockTables.LD) == 269) { - TablesRead2 = false; - UnpAudioBlock = false; - UnpChannelDelta = 0; - UnpCurChannel = 0; - UnpChannels = 1; - - //memset(AudV,0,sizeof(AudV)); - AudV = new AudioVariables[4]; - new Span(UnpOldTable20).Clear(); - //memset(MD,0,sizeof(MD)); - MD = new DecodeTable[4]; + ReadTables20(); } } - - private byte DecodeAudio(int Delta) - { - AudioVariables V = AudV[UnpCurChannel]; - V.ByteCount++; - V.D4 = V.D3; - V.D3 = V.D2; - V.D2 = V.LastDelta - V.D1; - V.D1 = V.LastDelta; - int PCh = - 8 * V.LastChar - + V.K1 * V.D1 - + V.K2 * V.D2 - + V.K3 * V.D3 - + V.K4 * V.D4 - + V.K5 * UnpChannelDelta; - PCh = (PCh >> 3) & 0xFF; - - uint Ch = (uint)(PCh - Delta); - - int D = (sbyte)Delta; - // Left shift of negative value is undefined behavior in C++, - // so we cast it to unsigned to follow the standard. - D = (int)((uint)D << 3); - - V.Dif[0] += (uint)Math.Abs(D); - V.Dif[1] += (uint)Math.Abs(D - V.D1); - V.Dif[2] += (uint)Math.Abs(D + V.D1); - V.Dif[3] += (uint)Math.Abs(D - V.D2); - V.Dif[4] += (uint)Math.Abs(D + V.D2); - V.Dif[5] += (uint)Math.Abs(D - V.D3); - V.Dif[6] += (uint)Math.Abs(D + V.D3); - V.Dif[7] += (uint)Math.Abs(D - V.D4); - V.Dif[8] += (uint)Math.Abs(D + V.D4); - V.Dif[9] += (uint)Math.Abs(D - UnpChannelDelta); - V.Dif[10] += (uint)Math.Abs(D + UnpChannelDelta); - - UnpChannelDelta = V.LastDelta = (sbyte)(Ch - V.LastChar); - V.LastChar = (int)Ch; - - if ((V.ByteCount & 0x1F) == 0) - { - uint MinDif = V.Dif[0], - NumMinDif = 0; - V.Dif[0] = 0; - for (uint I = 1; I < V.Dif.Length; I++) - { - if (V.Dif[I] < MinDif) - { - MinDif = V.Dif[I]; - NumMinDif = I; - } - V.Dif[I] = 0; - } - switch (NumMinDif) - { - case 1: - if (V.K1 >= -16) - { - V.K1--; - } - - break; - case 2: - if (V.K1 < 16) - { - V.K1++; - } - - break; - case 3: - if (V.K2 >= -16) - { - V.K2--; - } - - break; - case 4: - if (V.K2 < 16) - { - V.K2++; - } - - break; - case 5: - if (V.K3 >= -16) - { - V.K3--; - } - - break; - case 6: - if (V.K3 < 16) - { - V.K3++; - } - - break; - case 7: - if (V.K4 >= -16) - { - V.K4--; - } - - break; - case 8: - if (V.K4 < 16) - { - V.K4++; - } - - break; - case 9: - if (V.K5 >= -16) - { - V.K5--; - } - - break; - case 10: - if (V.K5 < 16) - { - V.K5++; - } - - break; - } - } - return (byte)Ch; - } + } + + private void UnpInitData20(bool Solid) + { + if (!Solid) + { + TablesRead2 = false; + UnpAudioBlock = false; + UnpChannelDelta = 0; + UnpCurChannel = 0; + UnpChannels = 1; + + //memset(AudV,0,sizeof(AudV)); + AudV = new AudioVariables[4]; + new Span(UnpOldTable20).Clear(); + //memset(MD,0,sizeof(MD)); + MD = new DecodeTable[4]; + } + } + + private byte DecodeAudio(int Delta) + { + var V = AudV[UnpCurChannel]; + V.ByteCount++; + V.D4 = V.D3; + V.D3 = V.D2; + V.D2 = V.LastDelta - V.D1; + V.D1 = V.LastDelta; + var PCh = + (8 * V.LastChar) + + (V.K1 * V.D1) + + (V.K2 * V.D2) + + (V.K3 * V.D3) + + (V.K4 * V.D4) + + (V.K5 * UnpChannelDelta); + PCh = (PCh >> 3) & 0xFF; + + var Ch = (uint)(PCh - Delta); + + int D = (sbyte)Delta; + // Left shift of negative value is undefined behavior in C++, + // so we cast it to unsigned to follow the standard. + D = (int)((uint)D << 3); + + V.Dif[0] += (uint)Math.Abs(D); + V.Dif[1] += (uint)Math.Abs(D - V.D1); + V.Dif[2] += (uint)Math.Abs(D + V.D1); + V.Dif[3] += (uint)Math.Abs(D - V.D2); + V.Dif[4] += (uint)Math.Abs(D + V.D2); + V.Dif[5] += (uint)Math.Abs(D - V.D3); + V.Dif[6] += (uint)Math.Abs(D + V.D3); + V.Dif[7] += (uint)Math.Abs(D - V.D4); + V.Dif[8] += (uint)Math.Abs(D + V.D4); + V.Dif[9] += (uint)Math.Abs(D - UnpChannelDelta); + V.Dif[10] += (uint)Math.Abs(D + UnpChannelDelta); + + UnpChannelDelta = V.LastDelta = (sbyte)(Ch - V.LastChar); + V.LastChar = (int)Ch; + + if ((V.ByteCount & 0x1F) == 0) + { + uint MinDif = V.Dif[0], + NumMinDif = 0; + V.Dif[0] = 0; + for (uint I = 1; I < V.Dif.Length; I++) + { + if (V.Dif[I] < MinDif) + { + MinDif = V.Dif[I]; + NumMinDif = I; + } + V.Dif[I] = 0; + } + switch (NumMinDif) + { + case 1: + if (V.K1 >= -16) + { + V.K1--; + } + + break; + case 2: + if (V.K1 < 16) + { + V.K1++; + } + + break; + case 3: + if (V.K2 >= -16) + { + V.K2--; + } + + break; + case 4: + if (V.K2 < 16) + { + V.K2++; + } + + break; + case 5: + if (V.K3 >= -16) + { + V.K3--; + } + + break; + case 6: + if (V.K3 < 16) + { + V.K3++; + } + + break; + case 7: + if (V.K4 >= -16) + { + V.K4--; + } + + break; + case 8: + if (V.K4 < 16) + { + V.K4++; + } + + break; + case 9: + if (V.K5 >= -16) + { + V.K5--; + } + + break; + case 10: + if (V.K5 < 16) + { + V.K5++; + } + + break; + } + } + return (byte)Ch; } } diff --git a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack30_cpp.cs b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack30_cpp.cs index 8491f7af..7a5caee0 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack30_cpp.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack30_cpp.cs @@ -1,13 +1,9 @@ -#if !Rar2017_64bit -using nint = System.Int32; -using nuint = System.UInt32; -using size_t = System.UInt32; +#if !Rar2017_64bit #else using nint = System.Int64; using nuint = System.UInt64; using size_t = System.UInt64; #endif -using int64 = System.Int64; //using static SharpCompress.Compressors.Rar.UnpackV2017.Unpack.Unpack30Local; /* diff --git a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack50_cpp.cs b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack50_cpp.cs index 32897c44..08f58601 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack50_cpp.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack50_cpp.cs @@ -1,8 +1,6 @@ -#nullable disable +#nullable disable #if !Rar2017_64bit -using nint = System.Int32; -using nuint = System.UInt32; using size_t = System.UInt32; #else using nint = System.Int64; @@ -15,748 +13,792 @@ using System; using static SharpCompress.Compressors.Rar.UnpackV2017.PackDef; using static SharpCompress.Compressors.Rar.UnpackV2017.UnpackGlobal; -namespace SharpCompress.Compressors.Rar.UnpackV2017 +namespace SharpCompress.Compressors.Rar.UnpackV2017; + +internal partial class Unpack { - internal partial class Unpack + private void Unpack5(bool Solid) { - private void Unpack5(bool Solid) + FileExtracted = true; + + if (!Suspended) { - FileExtracted = true; - - if (!Suspended) - { - UnpInitData(Solid); - if (!UnpReadBuf()) - { - return; - } - - // Check TablesRead5 to be sure that we read tables at least once - // regardless of current block header TablePresent flag. - // So we can safefly use these tables below. - if ( - !ReadBlockHeader(Inp, ref BlockHeader) - || !ReadTables(Inp, ref BlockHeader, ref BlockTables) - || !TablesRead5 - ) - { - return; - } - } - - while (true) - { - UnpPtr &= MaxWinMask; - - if (Inp.InAddr >= ReadBorder) - { - bool FileDone = false; - - // We use 'while', because for empty block containing only Huffman table, - // we'll be on the block border once again just after reading the table. - while ( - Inp.InAddr > BlockHeader.BlockStart + BlockHeader.BlockSize - 1 - || Inp.InAddr == BlockHeader.BlockStart + BlockHeader.BlockSize - 1 - && Inp.InBit >= BlockHeader.BlockBitSize - ) - { - if (BlockHeader.LastBlockInFile) - { - FileDone = true; - break; - } - if ( - !ReadBlockHeader(Inp, ref BlockHeader) - || !ReadTables(Inp, ref BlockHeader, ref BlockTables) - ) - { - return; - } - } - if (FileDone || !UnpReadBuf()) - { - break; - } - } - - if ( - ((WriteBorder - UnpPtr) & MaxWinMask) < MAX_LZ_MATCH + 3 - && WriteBorder != UnpPtr - ) - { - UnpWriteBuf(); - if (WrittenFileSize > DestUnpSize) - { - return; - } - - if (Suspended) - { - FileExtracted = false; - return; - } - } - - uint MainSlot = DecodeNumber(Inp, BlockTables.LD); - if (MainSlot < 256) - { - if (Fragmented) - { - FragWindow[UnpPtr++] = (byte)MainSlot; - } - else - { - Window[UnpPtr++] = (byte)MainSlot; - } - - continue; - } - if (MainSlot >= 262) - { - uint Length = SlotToLength(Inp, MainSlot - 262); - - uint DBits, - Distance = 1, - DistSlot = DecodeNumber(Inp, BlockTables.DD); - if (DistSlot < 4) - { - DBits = 0; - Distance += DistSlot; - } - else - { - DBits = DistSlot / 2 - 1; - Distance += (2 | (DistSlot & 1)) << (int)DBits; - } - - if (DBits > 0) - { - if (DBits >= 4) - { - if (DBits > 4) - { - Distance += ((Inp.getbits32() >> (int)(36 - DBits)) << 4); - Inp.addbits(DBits - 4); - } - uint LowDist = DecodeNumber(Inp, BlockTables.LDD); - Distance += LowDist; - } - else - { - Distance += Inp.getbits32() >> (int)(32 - DBits); - Inp.addbits(DBits); - } - } - - if (Distance > 0x100) - { - Length++; - if (Distance > 0x2000) - { - Length++; - if (Distance > 0x40000) - { - Length++; - } - } - } - - InsertOldDist(Distance); - LastLength = Length; - if (Fragmented) - { - FragWindow.CopyString(Length, Distance, ref UnpPtr, MaxWinMask); - } - else - { - CopyString(Length, Distance); - } - - continue; - } - if (MainSlot == 256) - { - UnpackFilter Filter = new UnpackFilter(); - if (!ReadFilter(Inp, Filter) || !AddFilter(Filter)) - { - break; - } - - continue; - } - if (MainSlot == 257) - { - if (LastLength != 0) - { - if (Fragmented) - { - FragWindow.CopyString(LastLength, OldDist[0], ref UnpPtr, MaxWinMask); - } - else - { - CopyString(LastLength, OldDist[0]); - } - } - - continue; - } - if (MainSlot < 262) - { - uint DistNum = MainSlot - 258; - uint Distance = OldDist[DistNum]; - for (uint I = DistNum; I > 0; I--) - { - OldDist[I] = OldDist[I - 1]; - } - - OldDist[0] = Distance; - - uint LengthSlot = DecodeNumber(Inp, BlockTables.RD); - uint Length = SlotToLength(Inp, LengthSlot); - LastLength = Length; - if (Fragmented) - { - FragWindow.CopyString(Length, Distance, ref UnpPtr, MaxWinMask); - } - else - { - CopyString(Length, Distance); - } - - continue; - } - } - UnpWriteBuf(); - } - - private uint ReadFilterData(BitInput Inp) - { - uint ByteCount = (Inp.fgetbits() >> 14) + 1; - Inp.addbits(2); - - uint Data = 0; - for (uint I = 0; I < ByteCount; I++) - { - Data += (Inp.fgetbits() >> 8) << (int)(I * 8); - Inp.addbits(8); - } - return Data; - } - - private bool ReadFilter(BitInput Inp, UnpackFilter Filter) - { - if (!Inp.ExternalBuffer && Inp.InAddr > ReadTop - 16) - { - if (!UnpReadBuf()) - { - return false; - } - } - - Filter.BlockStart = ReadFilterData(Inp); - Filter.BlockLength = ReadFilterData(Inp); - if (Filter.BlockLength > MAX_FILTER_BLOCK_SIZE) - { - Filter.BlockLength = 0; - } - - Filter.Type = (byte)(Inp.fgetbits() >> 13); - Inp.faddbits(3); - - if (Filter.Type == FILTER_DELTA) - { - Filter.Channels = (byte)((Inp.fgetbits() >> 11) + 1); - Inp.faddbits(5); - } - - return true; - } - - private bool AddFilter(UnpackFilter Filter) - { - if (Filters.Count >= MAX_UNPACK_FILTERS) - { - UnpWriteBuf(); // Write data, apply and flush filters. - if (Filters.Count >= MAX_UNPACK_FILTERS) - { - InitFilters(); // Still too many filters, prevent excessive memory use. - } - } - - // If distance to filter start is that large that due to circular dictionary - // mode now it points to old not written yet data, then we set 'NextWindow' - // flag and process this filter only after processing that older data. - Filter.NextWindow = - WrPtr != UnpPtr && ((WrPtr - UnpPtr) & MaxWinMask) <= Filter.BlockStart; - - Filter.BlockStart = (uint)((Filter.BlockStart + UnpPtr) & MaxWinMask); - Filters.Add(Filter); - return true; - } - - private bool UnpReadBuf() - { - int DataSize = ReadTop - Inp.InAddr; // Data left to process. - if (DataSize < 0) - { - return false; - } - - BlockHeader.BlockSize -= Inp.InAddr - BlockHeader.BlockStart; - if (Inp.InAddr > MAX_SIZE / 2) - { - // If we already processed more than half of buffer, let's move - // remaining data into beginning to free more space for new data - // and ensure that calling function does not cross the buffer border - // even if we did not read anything here. Also it ensures that read size - // is not less than CRYPT_BLOCK_SIZE, so we can align it without risk - // to make it zero. - if (DataSize > 0) - //x memmove(Inp.InBuf,Inp.InBuf+Inp.InAddr,DataSize); - { - Buffer.BlockCopy(Inp.InBuf, Inp.InAddr, Inp.InBuf, 0, DataSize); - } - - Inp.InAddr = 0; - ReadTop = DataSize; - } - else - { - DataSize = ReadTop; - } - - int ReadCode = 0; - if (MAX_SIZE != DataSize) - { - ReadCode = UnpIO_UnpRead(Inp.InBuf, DataSize, MAX_SIZE - DataSize); - } - - if (ReadCode > 0) // Can be also -1. - { - ReadTop += ReadCode; - } - - ReadBorder = ReadTop - 30; - BlockHeader.BlockStart = Inp.InAddr; - if (BlockHeader.BlockSize != -1) // '-1' means not defined yet. - { - // We may need to quit from main extraction loop and read new block header - // and trees earlier than data in input buffer ends. - ReadBorder = Math.Min( - ReadBorder, - BlockHeader.BlockStart + BlockHeader.BlockSize - 1 - ); - } - return ReadCode != -1; - } - - private void UnpWriteBuf() - { - size_t WrittenBorder = WrPtr; - size_t FullWriteSize = (UnpPtr - WrittenBorder) & MaxWinMask; - size_t WriteSizeLeft = FullWriteSize; - bool NotAllFiltersProcessed = false; - //for (size_t I=0;I int - for (int I = 0; I < Filters.Count; I++) - { - // Here we apply filters to data which we need to write. - // We always copy data to another memory block before processing. - // We cannot process them just in place in Window buffer, because - // these data can be used for future string matches, so we must - // preserve them in original form. - - UnpackFilter flt = Filters[I]; - if (flt.Type == FILTER_NONE) - { - continue; - } - - if (flt.NextWindow) - { - // Here we skip filters which have block start in current data range - // due to address wrap around in circular dictionary, but actually - // belong to next dictionary block. If such filter start position - // is included to current write range, then we reset 'NextWindow' flag. - // In fact we can reset it even without such check, because current - // implementation seems to guarantee 'NextWindow' flag reset after - // buffer writing for all existing filters. But let's keep this check - // just in case. Compressor guarantees that distance between - // filter block start and filter storing position cannot exceed - // the dictionary size. So if we covered the filter block start with - // our write here, we can safely assume that filter is applicable - // to next block on no further wrap arounds is possible. - if (((flt.BlockStart - WrPtr) & MaxWinMask) <= FullWriteSize) - { - flt.NextWindow = false; - } - - continue; - } - uint BlockStart = flt.BlockStart; - uint BlockLength = flt.BlockLength; - if (((BlockStart - WrittenBorder) & MaxWinMask) < WriteSizeLeft) - { - if (WrittenBorder != BlockStart) - { - UnpWriteArea(WrittenBorder, BlockStart); - WrittenBorder = BlockStart; - WriteSizeLeft = (UnpPtr - WrittenBorder) & MaxWinMask; - } - if (BlockLength <= WriteSizeLeft) - { - if (BlockLength > 0) // We set it to 0 also for invalid filters. - { - uint BlockEnd = (BlockStart + BlockLength) & MaxWinMask; - - //x FilterSrcMemory.Alloc(BlockLength); - FilterSrcMemory = EnsureCapacity( - FilterSrcMemory, - checked((int)BlockLength) - ); - byte[] Mem = FilterSrcMemory; - if (BlockStart < BlockEnd || BlockEnd == 0) - { - if (Fragmented) - { - FragWindow.CopyData(Mem, 0, BlockStart, BlockLength); - } - else - //x memcpy(Mem,Window+BlockStart,BlockLength); - { - Utility.Copy(Window, BlockStart, Mem, 0, BlockLength); - } - } - else - { - size_t FirstPartLength = (size_t)(MaxWinSize - BlockStart); - if (Fragmented) - { - FragWindow.CopyData(Mem, 0, BlockStart, FirstPartLength); - FragWindow.CopyData(Mem, FirstPartLength, 0, BlockEnd); - } - else - { - //x memcpy(Mem,Window+BlockStart,FirstPartLength); - Utility.Copy(Window, BlockStart, Mem, 0, FirstPartLength); - //x memcpy(Mem+FirstPartLength,Window,BlockEnd); - Utility.Copy(Window, 0, Mem, FirstPartLength, BlockEnd); - } - } - - byte[] OutMem = ApplyFilter(Mem, BlockLength, flt); - - Filters[I].Type = FILTER_NONE; - - if (OutMem != null) - { - UnpIO_UnpWrite(OutMem, 0, BlockLength); - } - - UnpSomeRead = true; - WrittenFileSize += BlockLength; - WrittenBorder = BlockEnd; - WriteSizeLeft = (UnpPtr - WrittenBorder) & MaxWinMask; - } - } - else - { - // Current filter intersects the window write border, so we adjust - // the window border to process this filter next time, not now. - WrPtr = WrittenBorder; - - // Since Filter start position can only increase, we quit processing - // all following filters for this data block and reset 'NextWindow' - // flag for them. - //for (size_t J=I;J int - for (int J = I; J < Filters.Count; J++) - { - UnpackFilter _flt = Filters[J]; - if (_flt.Type != FILTER_NONE) - { - _flt.NextWindow = false; - } - } - - // Do not write data left after current filter now. - NotAllFiltersProcessed = true; - break; - } - } - } - - // Remove processed filters from queue. - // sharpcompress: size_t -> int - int EmptyCount = 0; - // sharpcompress: size_t -> int - for (int I = 0; I < Filters.Count; I++) - { - if (EmptyCount > 0) - { - Filters[I - EmptyCount] = Filters[I]; - } - - if (Filters[I].Type == FILTER_NONE) - { - EmptyCount++; - } - } - if (EmptyCount > 0) - //Filters.Alloc(Filters.Count-EmptyCount); - { - Filters.RemoveRange(Filters.Count - EmptyCount, EmptyCount); - } - - if (!NotAllFiltersProcessed) // Only if all filters are processed. - { - // Write data left after last filter. - UnpWriteArea(WrittenBorder, UnpPtr); - WrPtr = UnpPtr; - } - - // We prefer to write data in blocks not exceeding UNPACK_MAX_WRITE - // instead of potentially huge MaxWinSize blocks. It also allows us - // to keep the size of Filters array reasonable. - WriteBorder = (UnpPtr + Math.Min(MaxWinSize, UNPACK_MAX_WRITE)) & MaxWinMask; - - // Choose the nearest among WriteBorder and WrPtr actual written border. - // If border is equal to UnpPtr, it means that we have MaxWinSize data ahead. - if ( - WriteBorder == UnpPtr - || WrPtr != UnpPtr - && ((WrPtr - UnpPtr) & MaxWinMask) < ((WriteBorder - UnpPtr) & MaxWinMask) - ) - { - WriteBorder = WrPtr; - } - } - - private byte[] ApplyFilter(byte[] __d, uint DataSize, UnpackFilter Flt) - { - int Data = 0; - byte[] SrcData = __d; - switch (Flt.Type) - { - case FILTER_E8: - case FILTER_E8E9: - - { - uint FileOffset = (uint)WrittenFileSize; - - const uint FileSize = 0x1000000; - byte CmpByte2 = Flt.Type == FILTER_E8E9 ? (byte)0xe9 : (byte)0xe8; - // DataSize is unsigned, so we use "CurPos+4" and not "DataSize-4" - // to avoid overflow for DataSize<4. - for (uint CurPos = 0; CurPos + 4 < DataSize; ) - { - //x byte CurByte=*(Data++); - byte CurByte = __d[Data++]; - CurPos++; - if (CurByte == 0xe8 || CurByte == CmpByte2) - { - uint Offset = (CurPos + FileOffset) % FileSize; - uint Addr = RawGet4(__d, Data); - - // We check 0x80000000 bit instead of '< 0' comparison - // not assuming int32 presence or uint size and endianness. - if ((Addr & 0x80000000) != 0) // Addr<0 - { - if (((Addr + Offset) & 0x80000000) == 0) // Addr+Offset>=0 - { - RawPut4(Addr + FileSize, __d, Data); - } - } - else if (((Addr - FileSize) & 0x80000000) != 0) // Addr> 8); - __d[D + 2] = (byte)(Offset >> 16); - } - } - } - return SrcData; - case FILTER_DELTA: - { - // Unlike RAR3, we do not need to reject excessive channel - // values here, since RAR5 uses only 5 bits to store channel. - uint Channels = Flt.Channels, - SrcPos = 0; - - //x FilterDstMemory.Alloc(DataSize); - FilterDstMemory = EnsureCapacity(FilterDstMemory, checked((int)DataSize)); - - byte[] DstData = FilterDstMemory; - - // Bytes from same channels are grouped to continual data blocks, - // so we need to place them back to their interleaving positions. - for (uint CurChannel = 0; CurChannel < Channels; CurChannel++) - { - byte PrevByte = 0; - for (uint DestPos = CurChannel; DestPos < DataSize; DestPos += Channels) - { - DstData[DestPos] = (PrevByte -= __d[Data + SrcPos++]); - } - } - return DstData; - } - } - return null; - } - - private void UnpWriteArea(size_t StartPtr, size_t EndPtr) - { - if (EndPtr != StartPtr) - { - UnpSomeRead = true; - } - - if (EndPtr < StartPtr) - { - UnpAllBuf = true; - } - - if (Fragmented) - { - size_t SizeToWrite = (EndPtr - StartPtr) & MaxWinMask; - while (SizeToWrite > 0) - { - size_t BlockSize = FragWindow.GetBlockSize(StartPtr, SizeToWrite); - //UnpWriteData(&FragWindow[StartPtr],BlockSize); - FragWindow.GetBuffer(StartPtr, out var __buffer, out var __offset); - UnpWriteData(__buffer, __offset, BlockSize); - SizeToWrite -= BlockSize; - StartPtr = (StartPtr + BlockSize) & MaxWinMask; - } - } - else if (EndPtr < StartPtr) - { - UnpWriteData(Window, StartPtr, MaxWinSize - StartPtr); - UnpWriteData(Window, 0, EndPtr); - } - else - { - UnpWriteData(Window, StartPtr, EndPtr - StartPtr); - } - } - - private void UnpWriteData(byte[] Data, size_t offset, size_t Size) - { - if (WrittenFileSize >= DestUnpSize) + UnpInitData(Solid); + if (!UnpReadBuf()) { return; } - size_t WriteSize = Size; - int64 LeftToWrite = DestUnpSize - WrittenFileSize; - if ((int64)WriteSize > LeftToWrite) + // Check TablesRead5 to be sure that we read tables at least once + // regardless of current block header TablePresent flag. + // So we can safefly use these tables below. + if ( + !ReadBlockHeader(Inp, ref BlockHeader) + || !ReadTables(Inp, ref BlockHeader, ref BlockTables) + || !TablesRead5 + ) { - WriteSize = (size_t)LeftToWrite; - } - - UnpIO_UnpWrite(Data, offset, WriteSize); - WrittenFileSize += Size; - } - - private void UnpInitData50(bool Solid) - { - if (!Solid) - { - TablesRead5 = false; + return; } } - private bool ReadBlockHeader(BitInput Inp, ref UnpackBlockHeader Header) + while (true) { - Header.HeaderSize = 0; + UnpPtr &= MaxWinMask; - if (!Inp.ExternalBuffer && Inp.InAddr > ReadTop - 7) + if (Inp.InAddr >= ReadBorder) { - if (!UnpReadBuf()) + var FileDone = false; + + // We use 'while', because for empty block containing only Huffman table, + // we'll be on the block border once again just after reading the table. + while ( + Inp.InAddr > BlockHeader.BlockStart + BlockHeader.BlockSize - 1 + || Inp.InAddr == BlockHeader.BlockStart + BlockHeader.BlockSize - 1 + && Inp.InBit >= BlockHeader.BlockBitSize + ) { - return false; + if (BlockHeader.LastBlockInFile) + { + FileDone = true; + break; + } + if ( + !ReadBlockHeader(Inp, ref BlockHeader) + || !ReadTables(Inp, ref BlockHeader, ref BlockTables) + ) + { + return; + } + } + if (FileDone || !UnpReadBuf()) + { + break; } } - Inp.faddbits((uint)((8 - Inp.InBit) & 7)); + if ( + ((WriteBorder - UnpPtr) & MaxWinMask) < MAX_LZ_MATCH + 3 + && WriteBorder != UnpPtr + ) + { + UnpWriteBuf(); + if (WrittenFileSize > DestUnpSize) + { + return; + } - byte BlockFlags = (byte)(Inp.fgetbits() >> 8); - Inp.faddbits(8); - uint ByteCount = (uint)(((BlockFlags >> 3) & 3) + 1); // Block size byte count. + if (Suspended) + { + FileExtracted = false; + return; + } + } - if (ByteCount == 4) + var MainSlot = DecodeNumber(Inp, BlockTables.LD); + if (MainSlot < 256) + { + if (Fragmented) + { + FragWindow[UnpPtr++] = (byte)MainSlot; + } + else + { + Window[UnpPtr++] = (byte)MainSlot; + } + + continue; + } + if (MainSlot >= 262) + { + var Length = SlotToLength(Inp, MainSlot - 262); + + uint DBits, + Distance = 1, + DistSlot = DecodeNumber(Inp, BlockTables.DD); + if (DistSlot < 4) + { + DBits = 0; + Distance += DistSlot; + } + else + { + DBits = (DistSlot / 2) - 1; + Distance += (2 | (DistSlot & 1)) << (int)DBits; + } + + if (DBits > 0) + { + if (DBits >= 4) + { + if (DBits > 4) + { + Distance += ((Inp.getbits32() >> (int)(36 - DBits)) << 4); + Inp.addbits(DBits - 4); + } + var LowDist = DecodeNumber(Inp, BlockTables.LDD); + Distance += LowDist; + } + else + { + Distance += Inp.getbits32() >> (int)(32 - DBits); + Inp.addbits(DBits); + } + } + + if (Distance > 0x100) + { + Length++; + if (Distance > 0x2000) + { + Length++; + if (Distance > 0x40000) + { + Length++; + } + } + } + + InsertOldDist(Distance); + LastLength = Length; + if (Fragmented) + { + FragWindow.CopyString(Length, Distance, ref UnpPtr, MaxWinMask); + } + else + { + CopyString(Length, Distance); + } + + continue; + } + if (MainSlot == 256) + { + var Filter = new UnpackFilter(); + if (!ReadFilter(Inp, Filter) || !AddFilter(Filter)) + { + break; + } + + continue; + } + if (MainSlot == 257) + { + if (LastLength != 0) + { + if (Fragmented) + { + FragWindow.CopyString(LastLength, OldDist[0], ref UnpPtr, MaxWinMask); + } + else + { + CopyString(LastLength, OldDist[0]); + } + } + + continue; + } + if (MainSlot < 262) + { + var DistNum = MainSlot - 258; + var Distance = OldDist[DistNum]; + for (var I = DistNum; I > 0; I--) + { + OldDist[I] = OldDist[I - 1]; + } + + OldDist[0] = Distance; + + var LengthSlot = DecodeNumber(Inp, BlockTables.RD); + var Length = SlotToLength(Inp, LengthSlot); + LastLength = Length; + if (Fragmented) + { + FragWindow.CopyString(Length, Distance, ref UnpPtr, MaxWinMask); + } + else + { + CopyString(Length, Distance); + } + + continue; + } + } + UnpWriteBuf(); + } + + private uint ReadFilterData(BitInput Inp) + { + var ByteCount = (Inp.fgetbits() >> 14) + 1; + Inp.addbits(2); + + uint Data = 0; + for (uint I = 0; I < ByteCount; I++) + { + Data += (Inp.fgetbits() >> 8) << (int)(I * 8); + Inp.addbits(8); + } + return Data; + } + + private bool ReadFilter(BitInput Inp, UnpackFilter Filter) + { + if (!Inp.ExternalBuffer && Inp.InAddr > ReadTop - 16) + { + if (!UnpReadBuf()) { return false; } - - Header.HeaderSize = (int)(2 + ByteCount); - - Header.BlockBitSize = (BlockFlags & 7) + 1; - - byte SavedCheckSum = (byte)(Inp.fgetbits() >> 8); - Inp.faddbits(8); - - int BlockSize = 0; - for (uint I = 0; I < ByteCount; I++) - { - BlockSize += (int)((Inp.fgetbits() >> 8) << (int)(I * 8)); - Inp.addbits(8); - } - - Header.BlockSize = BlockSize; - byte CheckSum = (byte)( - 0x5a ^ BlockFlags ^ BlockSize ^ (BlockSize >> 8) ^ (BlockSize >> 16) - ); - if (CheckSum != SavedCheckSum) - { - return false; - } - - Header.BlockStart = Inp.InAddr; - ReadBorder = Math.Min(ReadBorder, Header.BlockStart + Header.BlockSize - 1); - - Header.LastBlockInFile = (BlockFlags & 0x40) != 0; - Header.TablePresent = (BlockFlags & 0x80) != 0; - return true; } - private bool ReadTables( - BitInput Inp, - ref UnpackBlockHeader Header, - ref UnpackBlockTables Tables + Filter.BlockStart = ReadFilterData(Inp); + Filter.BlockLength = ReadFilterData(Inp); + if (Filter.BlockLength > MAX_FILTER_BLOCK_SIZE) + { + Filter.BlockLength = 0; + } + + Filter.Type = (byte)(Inp.fgetbits() >> 13); + Inp.faddbits(3); + + if (Filter.Type == FILTER_DELTA) + { + Filter.Channels = (byte)((Inp.fgetbits() >> 11) + 1); + Inp.faddbits(5); + } + + return true; + } + + private bool AddFilter(UnpackFilter Filter) + { + if (Filters.Count >= MAX_UNPACK_FILTERS) + { + UnpWriteBuf(); // Write data, apply and flush filters. + if (Filters.Count >= MAX_UNPACK_FILTERS) + { + InitFilters(); // Still too many filters, prevent excessive memory use. + } + } + + // If distance to filter start is that large that due to circular dictionary + // mode now it points to old not written yet data, then we set 'NextWindow' + // flag and process this filter only after processing that older data. + Filter.NextWindow = + WrPtr != UnpPtr && ((WrPtr - UnpPtr) & MaxWinMask) <= Filter.BlockStart; + + Filter.BlockStart = (Filter.BlockStart + UnpPtr) & MaxWinMask; + Filters.Add(Filter); + return true; + } + + private bool UnpReadBuf() + { + var DataSize = ReadTop - Inp.InAddr; // Data left to process. + if (DataSize < 0) + { + return false; + } + + BlockHeader.BlockSize -= Inp.InAddr - BlockHeader.BlockStart; + if (Inp.InAddr > MAX_SIZE / 2) + { + // If we already processed more than half of buffer, let's move + // remaining data into beginning to free more space for new data + // and ensure that calling function does not cross the buffer border + // even if we did not read anything here. Also it ensures that read size + // is not less than CRYPT_BLOCK_SIZE, so we can align it without risk + // to make it zero. + if (DataSize > 0) + //x memmove(Inp.InBuf,Inp.InBuf+Inp.InAddr,DataSize); + { + Buffer.BlockCopy(Inp.InBuf, Inp.InAddr, Inp.InBuf, 0, DataSize); + } + + Inp.InAddr = 0; + ReadTop = DataSize; + } + else + { + DataSize = ReadTop; + } + + var ReadCode = 0; + if (MAX_SIZE != DataSize) + { + ReadCode = UnpIO_UnpRead(Inp.InBuf, DataSize, MAX_SIZE - DataSize); + } + + if (ReadCode > 0) // Can be also -1. + { + ReadTop += ReadCode; + } + + ReadBorder = ReadTop - 30; + BlockHeader.BlockStart = Inp.InAddr; + if (BlockHeader.BlockSize != -1) // '-1' means not defined yet. + { + // We may need to quit from main extraction loop and read new block header + // and trees earlier than data in input buffer ends. + ReadBorder = Math.Min( + ReadBorder, + BlockHeader.BlockStart + BlockHeader.BlockSize - 1 + ); + } + return ReadCode != -1; + } + + private void UnpWriteBuf() + { + var WrittenBorder = WrPtr; + var FullWriteSize = (UnpPtr - WrittenBorder) & MaxWinMask; + var WriteSizeLeft = FullWriteSize; + var NotAllFiltersProcessed = false; + //for (size_t I=0;I int + for (var I = 0; I < Filters.Count; I++) + { + // Here we apply filters to data which we need to write. + // We always copy data to another memory block before processing. + // We cannot process them just in place in Window buffer, because + // these data can be used for future string matches, so we must + // preserve them in original form. + + var flt = Filters[I]; + if (flt.Type == FILTER_NONE) + { + continue; + } + + if (flt.NextWindow) + { + // Here we skip filters which have block start in current data range + // due to address wrap around in circular dictionary, but actually + // belong to next dictionary block. If such filter start position + // is included to current write range, then we reset 'NextWindow' flag. + // In fact we can reset it even without such check, because current + // implementation seems to guarantee 'NextWindow' flag reset after + // buffer writing for all existing filters. But let's keep this check + // just in case. Compressor guarantees that distance between + // filter block start and filter storing position cannot exceed + // the dictionary size. So if we covered the filter block start with + // our write here, we can safely assume that filter is applicable + // to next block on no further wrap arounds is possible. + if (((flt.BlockStart - WrPtr) & MaxWinMask) <= FullWriteSize) + { + flt.NextWindow = false; + } + + continue; + } + var BlockStart = flt.BlockStart; + var BlockLength = flt.BlockLength; + if (((BlockStart - WrittenBorder) & MaxWinMask) < WriteSizeLeft) + { + if (WrittenBorder != BlockStart) + { + UnpWriteArea(WrittenBorder, BlockStart); + WrittenBorder = BlockStart; + WriteSizeLeft = (UnpPtr - WrittenBorder) & MaxWinMask; + } + if (BlockLength <= WriteSizeLeft) + { + if (BlockLength > 0) // We set it to 0 also for invalid filters. + { + var BlockEnd = (BlockStart + BlockLength) & MaxWinMask; + + //x FilterSrcMemory.Alloc(BlockLength); + FilterSrcMemory = EnsureCapacity( + FilterSrcMemory, + checked((int)BlockLength) + ); + var Mem = FilterSrcMemory; + if (BlockStart < BlockEnd || BlockEnd == 0) + { + if (Fragmented) + { + FragWindow.CopyData(Mem, 0, BlockStart, BlockLength); + } + else + //x memcpy(Mem,Window+BlockStart,BlockLength); + { + Utility.Copy(Window, BlockStart, Mem, 0, BlockLength); + } + } + else + { + var FirstPartLength = MaxWinSize - BlockStart; + if (Fragmented) + { + FragWindow.CopyData(Mem, 0, BlockStart, FirstPartLength); + FragWindow.CopyData(Mem, FirstPartLength, 0, BlockEnd); + } + else + { + //x memcpy(Mem,Window+BlockStart,FirstPartLength); + Utility.Copy(Window, BlockStart, Mem, 0, FirstPartLength); + //x memcpy(Mem+FirstPartLength,Window,BlockEnd); + Utility.Copy(Window, 0, Mem, FirstPartLength, BlockEnd); + } + } + + var OutMem = ApplyFilter(Mem, BlockLength, flt); + + Filters[I].Type = FILTER_NONE; + + if (OutMem != null) + { + UnpIO_UnpWrite(OutMem, 0, BlockLength); + } + + UnpSomeRead = true; + WrittenFileSize += BlockLength; + WrittenBorder = BlockEnd; + WriteSizeLeft = (UnpPtr - WrittenBorder) & MaxWinMask; + } + } + else + { + // Current filter intersects the window write border, so we adjust + // the window border to process this filter next time, not now. + WrPtr = WrittenBorder; + + // Since Filter start position can only increase, we quit processing + // all following filters for this data block and reset 'NextWindow' + // flag for them. + //for (size_t J=I;J int + for (var J = I; J < Filters.Count; J++) + { + var _flt = Filters[J]; + if (_flt.Type != FILTER_NONE) + { + _flt.NextWindow = false; + } + } + + // Do not write data left after current filter now. + NotAllFiltersProcessed = true; + break; + } + } + } + + // Remove processed filters from queue. + // sharpcompress: size_t -> int + var EmptyCount = 0; + // sharpcompress: size_t -> int + for (var I = 0; I < Filters.Count; I++) + { + if (EmptyCount > 0) + { + Filters[I - EmptyCount] = Filters[I]; + } + + if (Filters[I].Type == FILTER_NONE) + { + EmptyCount++; + } + } + if (EmptyCount > 0) + //Filters.Alloc(Filters.Count-EmptyCount); + { + Filters.RemoveRange(Filters.Count - EmptyCount, EmptyCount); + } + + if (!NotAllFiltersProcessed) // Only if all filters are processed. + { + // Write data left after last filter. + UnpWriteArea(WrittenBorder, UnpPtr); + WrPtr = UnpPtr; + } + + // We prefer to write data in blocks not exceeding UNPACK_MAX_WRITE + // instead of potentially huge MaxWinSize blocks. It also allows us + // to keep the size of Filters array reasonable. + WriteBorder = (UnpPtr + Math.Min(MaxWinSize, UNPACK_MAX_WRITE)) & MaxWinMask; + + // Choose the nearest among WriteBorder and WrPtr actual written border. + // If border is equal to UnpPtr, it means that we have MaxWinSize data ahead. + if ( + WriteBorder == UnpPtr + || WrPtr != UnpPtr + && ((WrPtr - UnpPtr) & MaxWinMask) < ((WriteBorder - UnpPtr) & MaxWinMask) ) { - if (!Header.TablePresent) - { - return true; - } + WriteBorder = WrPtr; + } + } - if (!Inp.ExternalBuffer && Inp.InAddr > ReadTop - 25) + private byte[] ApplyFilter(byte[] __d, uint DataSize, UnpackFilter Flt) + { + var Data = 0; + var SrcData = __d; + switch (Flt.Type) + { + case FILTER_E8: + case FILTER_E8E9: + + { + var FileOffset = (uint)WrittenFileSize; + + const uint FileSize = 0x1000000; + var CmpByte2 = Flt.Type == FILTER_E8E9 ? (byte)0xe9 : (byte)0xe8; + // DataSize is unsigned, so we use "CurPos+4" and not "DataSize-4" + // to avoid overflow for DataSize<4. + for (uint CurPos = 0; CurPos + 4 < DataSize;) + { + //x byte CurByte=*(Data++); + var CurByte = __d[Data++]; + CurPos++; + if (CurByte == 0xe8 || CurByte == CmpByte2) + { + var Offset = (CurPos + FileOffset) % FileSize; + var Addr = RawGet4(__d, Data); + + // We check 0x80000000 bit instead of '< 0' comparison + // not assuming int32 presence or uint size and endianness. + if ((Addr & 0x80000000) != 0) // Addr<0 + { + if (((Addr + Offset) & 0x80000000) == 0) // Addr+Offset>=0 + { + RawPut4(Addr + FileSize, __d, Data); + } + } + else if (((Addr - FileSize) & 0x80000000) != 0) // Addr> 8); + __d[D + 2] = (byte)(Offset >> 16); + } + } + } + return SrcData; + case FILTER_DELTA: + { + // Unlike RAR3, we do not need to reject excessive channel + // values here, since RAR5 uses only 5 bits to store channel. + uint Channels = Flt.Channels, + SrcPos = 0; + + //x FilterDstMemory.Alloc(DataSize); + FilterDstMemory = EnsureCapacity(FilterDstMemory, checked((int)DataSize)); + + var DstData = FilterDstMemory; + + // Bytes from same channels are grouped to continual data blocks, + // so we need to place them back to their interleaving positions. + for (uint CurChannel = 0; CurChannel < Channels; CurChannel++) + { + byte PrevByte = 0; + for (var DestPos = CurChannel; DestPos < DataSize; DestPos += Channels) + { + DstData[DestPos] = (PrevByte -= __d[Data + SrcPos++]); + } + } + return DstData; + } + } + return null; + } + + private void UnpWriteArea(size_t StartPtr, size_t EndPtr) + { + if (EndPtr != StartPtr) + { + UnpSomeRead = true; + } + + if (EndPtr < StartPtr) + { + UnpAllBuf = true; + } + + if (Fragmented) + { + var SizeToWrite = (EndPtr - StartPtr) & MaxWinMask; + while (SizeToWrite > 0) + { + var BlockSize = FragWindow.GetBlockSize(StartPtr, SizeToWrite); + //UnpWriteData(&FragWindow[StartPtr],BlockSize); + FragWindow.GetBuffer(StartPtr, out var __buffer, out var __offset); + UnpWriteData(__buffer, __offset, BlockSize); + SizeToWrite -= BlockSize; + StartPtr = (StartPtr + BlockSize) & MaxWinMask; + } + } + else if (EndPtr < StartPtr) + { + UnpWriteData(Window, StartPtr, MaxWinSize - StartPtr); + UnpWriteData(Window, 0, EndPtr); + } + else + { + UnpWriteData(Window, StartPtr, EndPtr - StartPtr); + } + } + + private void UnpWriteData(byte[] Data, size_t offset, size_t Size) + { + if (WrittenFileSize >= DestUnpSize) + { + return; + } + + var WriteSize = Size; + var LeftToWrite = DestUnpSize - WrittenFileSize; + if (WriteSize > LeftToWrite) + { + WriteSize = (size_t)LeftToWrite; + } + + UnpIO_UnpWrite(Data, offset, WriteSize); + WrittenFileSize += Size; + } + + private void UnpInitData50(bool Solid) + { + if (!Solid) + { + TablesRead5 = false; + } + } + + private bool ReadBlockHeader(BitInput Inp, ref UnpackBlockHeader Header) + { + Header.HeaderSize = 0; + + if (!Inp.ExternalBuffer && Inp.InAddr > ReadTop - 7) + { + if (!UnpReadBuf()) + { + return false; + } + } + + Inp.faddbits((uint)((8 - Inp.InBit) & 7)); + + var BlockFlags = (byte)(Inp.fgetbits() >> 8); + Inp.faddbits(8); + var ByteCount = (uint)(((BlockFlags >> 3) & 3) + 1); // Block size byte count. + + if (ByteCount == 4) + { + return false; + } + + Header.HeaderSize = (int)(2 + ByteCount); + + Header.BlockBitSize = (BlockFlags & 7) + 1; + + var SavedCheckSum = (byte)(Inp.fgetbits() >> 8); + Inp.faddbits(8); + + var BlockSize = 0; + for (uint I = 0; I < ByteCount; I++) + { + BlockSize += (int)((Inp.fgetbits() >> 8) << (int)(I * 8)); + Inp.addbits(8); + } + + Header.BlockSize = BlockSize; + var CheckSum = (byte)( + 0x5a ^ BlockFlags ^ BlockSize ^ (BlockSize >> 8) ^ (BlockSize >> 16) + ); + if (CheckSum != SavedCheckSum) + { + return false; + } + + Header.BlockStart = Inp.InAddr; + ReadBorder = Math.Min(ReadBorder, Header.BlockStart + Header.BlockSize - 1); + + Header.LastBlockInFile = (BlockFlags & 0x40) != 0; + Header.TablePresent = (BlockFlags & 0x80) != 0; + return true; + } + + private bool ReadTables( + BitInput Inp, + ref UnpackBlockHeader Header, + ref UnpackBlockTables Tables + ) + { + if (!Header.TablePresent) + { + return true; + } + + if (!Inp.ExternalBuffer && Inp.InAddr > ReadTop - 25) + { + if (!UnpReadBuf()) + { + return false; + } + } + + var BitLength = new byte[BC]; + for (uint I = 0; I < BC; I++) + { + uint Length = (byte)(Inp.fgetbits() >> 12); + Inp.faddbits(4); + if (Length == 15) + { + uint ZeroCount = (byte)(Inp.fgetbits() >> 12); + Inp.faddbits(4); + if (ZeroCount == 0) + { + BitLength[I] = 15; + } + else + { + ZeroCount += 2; + while (ZeroCount-- > 0 && I < BitLength.Length) + { + BitLength[I++] = 0; + } + + I--; + } + } + else + { + BitLength[I] = (byte)Length; + } + } + + MakeDecodeTables(BitLength, 0, Tables.BD, BC); + + var Table = new byte[HUFF_TABLE_SIZE]; + const uint TableSize = HUFF_TABLE_SIZE; + for (uint I = 0; I < TableSize;) + { + if (!Inp.ExternalBuffer && Inp.InAddr > ReadTop - 5) { if (!UnpReadBuf()) { @@ -764,123 +806,78 @@ namespace SharpCompress.Compressors.Rar.UnpackV2017 } } - byte[] BitLength = new byte[BC]; - for (uint I = 0; I < BC; I++) + var Number = DecodeNumber(Inp, Tables.BD); + if (Number < 16) { - uint Length = (byte)(Inp.fgetbits() >> 12); - Inp.faddbits(4); - if (Length == 15) - { - uint ZeroCount = (byte)(Inp.fgetbits() >> 12); - Inp.faddbits(4); - if (ZeroCount == 0) - { - BitLength[I] = 15; - } - else - { - ZeroCount += 2; - while (ZeroCount-- > 0 && I < BitLength.Length) - { - BitLength[I++] = 0; - } - - I--; - } - } - else - { - BitLength[I] = (byte)Length; - } + Table[I] = (byte)Number; + I++; } - - MakeDecodeTables(BitLength, 0, Tables.BD, BC); - - byte[] Table = new byte[HUFF_TABLE_SIZE]; - const uint TableSize = HUFF_TABLE_SIZE; - for (uint I = 0; I < TableSize; ) + else if (Number < 18) { - if (!Inp.ExternalBuffer && Inp.InAddr > ReadTop - 5) + uint N; + if (Number == 16) { - if (!UnpReadBuf()) - { - return false; - } - } - - uint Number = DecodeNumber(Inp, Tables.BD); - if (Number < 16) - { - Table[I] = (byte)Number; - I++; - } - else if (Number < 18) - { - uint N; - if (Number == 16) - { - N = (Inp.fgetbits() >> 13) + 3; - Inp.faddbits(3); - } - else - { - N = (Inp.fgetbits() >> 9) + 11; - Inp.faddbits(7); - } - if (I == 0) - { - // We cannot have "repeat previous" code at the first position. - // Multiple such codes would shift Inp position without changing I, - // which can lead to reading beyond of Inp boundary in mutithreading - // mode, where Inp.ExternalBuffer disables bounds check and we just - // reserve a lot of buffer space to not need such check normally. - return false; - } - else - { - while (N-- > 0 && I < TableSize) - { - Table[I] = Table[I - 1]; - I++; - } - } + N = (Inp.fgetbits() >> 13) + 3; + Inp.faddbits(3); + } + else + { + N = (Inp.fgetbits() >> 9) + 11; + Inp.faddbits(7); + } + if (I == 0) + { + // We cannot have "repeat previous" code at the first position. + // Multiple such codes would shift Inp position without changing I, + // which can lead to reading beyond of Inp boundary in mutithreading + // mode, where Inp.ExternalBuffer disables bounds check and we just + // reserve a lot of buffer space to not need such check normally. + return false; } else { - uint N; - if (Number == 18) - { - N = (Inp.fgetbits() >> 13) + 3; - Inp.faddbits(3); - } - else - { - N = (Inp.fgetbits() >> 9) + 11; - Inp.faddbits(7); - } while (N-- > 0 && I < TableSize) { - Table[I++] = 0; + Table[I] = Table[I - 1]; + I++; } } } - TablesRead5 = true; - if (!Inp.ExternalBuffer && Inp.InAddr > ReadTop) + else { - return false; + uint N; + if (Number == 18) + { + N = (Inp.fgetbits() >> 13) + 3; + Inp.faddbits(3); + } + else + { + N = (Inp.fgetbits() >> 9) + 11; + Inp.faddbits(7); + } + while (N-- > 0 && I < TableSize) + { + Table[I++] = 0; + } } - - MakeDecodeTables(Table, 0, Tables.LD, NC); - MakeDecodeTables(Table, (int)NC, Tables.DD, DC); - MakeDecodeTables(Table, (int)(NC + DC), Tables.LDD, LDC); - MakeDecodeTables(Table, (int)(NC + DC + LDC), Tables.RD, RC); - return true; } - - private void InitFilters() + TablesRead5 = true; + if (!Inp.ExternalBuffer && Inp.InAddr > ReadTop) { - //Filters.SoftReset(); - Filters.Clear(); + return false; } + + MakeDecodeTables(Table, 0, Tables.LD, NC); + MakeDecodeTables(Table, (int)NC, Tables.DD, DC); + MakeDecodeTables(Table, (int)(NC + DC), Tables.LDD, LDC); + MakeDecodeTables(Table, (int)(NC + DC + LDC), Tables.RD, RC); + return true; + } + + private void InitFilters() + { + //Filters.SoftReset(); + Filters.Clear(); } } diff --git a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack_cpp.cs b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack_cpp.cs index 17eecba5..69b35200 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack_cpp.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack_cpp.cs @@ -1,8 +1,6 @@ -#nullable disable +#nullable disable #if !Rar2017_64bit -using nint = System.Int32; -using nuint = System.UInt32; using size_t = System.UInt32; #else using nint = System.Int64; @@ -15,401 +13,400 @@ using SharpCompress.Common; using static SharpCompress.Compressors.Rar.UnpackV2017.UnpackGlobal; using static SharpCompress.Compressors.Rar.UnpackV2017.PackDef; -namespace SharpCompress.Compressors.Rar.UnpackV2017 +namespace SharpCompress.Compressors.Rar.UnpackV2017; + +internal sealed partial class Unpack : BitInput { - internal sealed partial class Unpack : BitInput + public Unpack( /* ComprDataIO *DataIO */ + ) + //:Inp(true),VMCodeInp(true) + : base(true) { - public Unpack( /* ComprDataIO *DataIO */ - ) - //:Inp(true),VMCodeInp(true) - : base(true) - { - _UnpackCtor(); + _UnpackCtor(); - //UnpIO=DataIO; - Window = null; - Fragmented = false; - Suspended = false; - UnpAllBuf = false; - UnpSomeRead = false; + //UnpIO=DataIO; + Window = null; + Fragmented = false; + Suspended = false; + UnpAllBuf = false; + UnpSomeRead = false; #if RarV2017_RAR_SMP - MaxUserThreads = 1; - UnpThreadPool = CreateThreadPool(); - ReadBufMT = null; - UnpThreadData = null; + MaxUserThreads = 1; + UnpThreadPool = CreateThreadPool(); + ReadBufMT = null; + UnpThreadData = null; #endif - MaxWinSize = 0; - MaxWinMask = 0; + MaxWinSize = 0; + MaxWinMask = 0; - // Perform initialization, which should be done only once for all files. - // It prevents crash if first DoUnpack call is later made with wrong - // (true) 'Solid' value. - UnpInitData(false); + // Perform initialization, which should be done only once for all files. + // It prevents crash if first DoUnpack call is later made with wrong + // (true) 'Solid' value. + UnpInitData(false); #if !RarV2017_SFX_MODULE - // RAR 1.5 decompression initialization - UnpInitData15(false); - InitHuff(); + // RAR 1.5 decompression initialization + UnpInitData15(false); + InitHuff(); #endif + } + + // later: may need Dispose() if we support thread pool + //Unpack::~Unpack() + //{ + // InitFilters30(false); + // + // if (Window!=null) + // free(Window); + //#if RarV2017_RAR_SMP + // DestroyThreadPool(UnpThreadPool); + // delete[] ReadBufMT; + // delete[] UnpThreadData; + //#endif + //} + + private void Init(size_t WinSize, bool Solid) + { + // If 32-bit RAR unpacks an archive with 4 GB dictionary, the window size + // will be 0 because of size_t overflow. Let's issue the memory error. + if (WinSize == 0) + //ErrHandler.MemoryError(); + { + throw new InvalidFormatException( + "invalid window size (possibly due to a rar file with a 4GB being unpacked on a 32-bit platform)" + ); } - // later: may need Dispose() if we support thread pool - //Unpack::~Unpack() - //{ - // InitFilters30(false); - // - // if (Window!=null) - // free(Window); - //#if RarV2017_RAR_SMP - // DestroyThreadPool(UnpThreadPool); - // delete[] ReadBufMT; - // delete[] UnpThreadData; - //#endif - //} - - private void Init(size_t WinSize, bool Solid) + // Minimum window size must be at least twice more than maximum possible + // size of filter block, which is 0x10000 in RAR now. If window size is + // smaller, we can have a block with never cleared flt->NextWindow flag + // in UnpWriteBuf(). Minimum window size 0x20000 would be enough, but let's + // use 0x40000 for extra safety and possible filter area size expansion. + const size_t MinAllocSize = 0x40000; + if (WinSize < MinAllocSize) { - // If 32-bit RAR unpacks an archive with 4 GB dictionary, the window size - // will be 0 because of size_t overflow. Let's issue the memory error. - if (WinSize == 0) - //ErrHandler.MemoryError(); - { - throw new InvalidFormatException( - "invalid window size (possibly due to a rar file with a 4GB being unpacked on a 32-bit platform)" - ); - } - - // Minimum window size must be at least twice more than maximum possible - // size of filter block, which is 0x10000 in RAR now. If window size is - // smaller, we can have a block with never cleared flt->NextWindow flag - // in UnpWriteBuf(). Minimum window size 0x20000 would be enough, but let's - // use 0x40000 for extra safety and possible filter area size expansion. - const size_t MinAllocSize = 0x40000; - if (WinSize < MinAllocSize) - { - WinSize = MinAllocSize; - } - - if (WinSize <= MaxWinSize) // Use the already allocated window. - { - return; - } - - if ((WinSize >> 16) > 0x10000) // Window size must not exceed 4 GB. - { - return; - } - - // Archiving code guarantees that window size does not grow in the same - // solid stream. So if we are here, we are either creating a new window - // or increasing the size of non-solid window. So we could safely reject - // current window data without copying them to a new window, though being - // extra cautious, we still handle the solid window grow case below. - bool Grow = Solid && (Window != null || Fragmented); - - // We do not handle growth for existing fragmented window. - if (Grow && Fragmented) - //throw std::bad_alloc(); - { - throw new InvalidFormatException("Grow && Fragmented"); - } - - byte[] NewWindow = Fragmented ? null : new byte[WinSize]; - - if (NewWindow == null) - { - if (Grow || WinSize < 0x1000000) - { - // We do not support growth for new fragmented window. - // Also exclude RAR4 and small dictionaries. - //throw std::bad_alloc(); - throw new InvalidFormatException("Grow || WinSize<0x1000000"); - } - else - { - if (Window != null) // If allocated by preceding files. - { - //free(Window); - Window = null; - } - FragWindow.Init(WinSize); - Fragmented = true; - } - } - - if (!Fragmented) - { - // Clean the window to generate the same output when unpacking corrupt - // RAR files, which may access unused areas of sliding dictionary. - // sharpcompress: don't need this, freshly allocated above - //memset(NewWindow,0,WinSize); - - - // If Window is not NULL, it means that window size has grown. - // In solid streams we need to copy data to a new window in such case. - // RAR archiving code does not allow it in solid streams now, - // but let's implement it anyway just in case we'll change it sometimes. - if (Grow) - { - for (size_t I = 1; I <= MaxWinSize; I++) - { - NewWindow[(UnpPtr - I) & (WinSize - 1)] = Window[ - (UnpPtr - I) & (MaxWinSize - 1) - ]; - } - } - - //if (Window!=null) - // free(Window); - Window = NewWindow; - } - - MaxWinSize = WinSize; - MaxWinMask = MaxWinSize - 1; + WinSize = MinAllocSize; } - private void DoUnpack(uint Method, bool Solid) + if (WinSize <= MaxWinSize) // Use the already allocated window. { - // Methods <50 will crash in Fragmented mode when accessing NULL Window. - // They cannot be called in such mode now, but we check it below anyway - // just for extra safety. - switch (Method) + return; + } + + if ((WinSize >> 16) > 0x10000) // Window size must not exceed 4 GB. + { + return; + } + + // Archiving code guarantees that window size does not grow in the same + // solid stream. So if we are here, we are either creating a new window + // or increasing the size of non-solid window. So we could safely reject + // current window data without copying them to a new window, though being + // extra cautious, we still handle the solid window grow case below. + var Grow = Solid && (Window != null || Fragmented); + + // We do not handle growth for existing fragmented window. + if (Grow && Fragmented) + //throw std::bad_alloc(); + { + throw new InvalidFormatException("Grow && Fragmented"); + } + + var NewWindow = Fragmented ? null : new byte[WinSize]; + + if (NewWindow == null) + { + if (Grow || WinSize < 0x1000000) { + // We do not support growth for new fragmented window. + // Also exclude RAR4 and small dictionaries. + //throw std::bad_alloc(); + throw new InvalidFormatException("Grow || WinSize<0x1000000"); + } + else + { + if (Window != null) // If allocated by preceding files. + { + //free(Window); + Window = null; + } + FragWindow.Init(WinSize); + Fragmented = true; + } + } + + if (!Fragmented) + { + // Clean the window to generate the same output when unpacking corrupt + // RAR files, which may access unused areas of sliding dictionary. + // sharpcompress: don't need this, freshly allocated above + //memset(NewWindow,0,WinSize); + + + // If Window is not NULL, it means that window size has grown. + // In solid streams we need to copy data to a new window in such case. + // RAR archiving code does not allow it in solid streams now, + // but let's implement it anyway just in case we'll change it sometimes. + if (Grow) + { + for (size_t I = 1; I <= MaxWinSize; I++) + { + NewWindow[(UnpPtr - I) & (WinSize - 1)] = Window[ + (UnpPtr - I) & (MaxWinSize - 1) + ]; + } + } + + //if (Window!=null) + // free(Window); + Window = NewWindow; + } + + MaxWinSize = WinSize; + MaxWinMask = MaxWinSize - 1; + } + + private void DoUnpack(uint Method, bool Solid) + { + // Methods <50 will crash in Fragmented mode when accessing NULL Window. + // They cannot be called in such mode now, but we check it below anyway + // just for extra safety. + switch (Method) + { #if !RarV2017_SFX_MODULE - case 15: // rar 1.5 compression - if (!Fragmented) - { - Unpack15(Solid); - } + case 15: // rar 1.5 compression + if (!Fragmented) + { + Unpack15(Solid); + } - break; - case 20: // rar 2.x compression - case 26: // files larger than 2GB - if (!Fragmented) - { - Unpack20(Solid); - } + break; + case 20: // rar 2.x compression + case 26: // files larger than 2GB + if (!Fragmented) + { + Unpack20(Solid); + } - break; + break; #endif #if !RarV2017_RAR5ONLY - case 29: // rar 3.x compression + case 29: // rar 3.x compression + if (!Fragmented) + { + throw new NotImplementedException(); + } + + break; +#endif + case 50: // RAR 5.0 compression algorithm. +#if RarV2017_RAR_SMP + if (MaxUserThreads > 1) + { + // We do not use the multithreaded unpack routine to repack RAR archives + // in 'suspended' mode, because unlike the single threaded code it can + // write more than one dictionary for same loop pass. So we would need + // larger buffers of unknown size. Also we do not support multithreading + // in fragmented window mode. if (!Fragmented) { - throw new NotImplementedException(); + Unpack5MT(Solid); + break; } - - break; + } #endif - case 50: // RAR 5.0 compression algorithm. -#if RarV2017_RAR_SMP - if (MaxUserThreads > 1) - { - // We do not use the multithreaded unpack routine to repack RAR archives - // in 'suspended' mode, because unlike the single threaded code it can - // write more than one dictionary for same loop pass. So we would need - // larger buffers of unknown size. Also we do not support multithreading - // in fragmented window mode. - if (!Fragmented) - { - Unpack5MT(Solid); - break; - } - } -#endif - Unpack5(Solid); - break; + Unpack5(Solid); + break; #if !Rar2017_NOSTRICT - default: - throw new InvalidFormatException("unknown compression method " + Method); + default: + throw new InvalidFormatException("unknown compression method " + Method); #endif - } } + } - private void UnpInitData(bool Solid) + private void UnpInitData(bool Solid) + { + if (!Solid) { - if (!Solid) - { - new Span(OldDist).Clear(); - OldDistPtr = 0; - LastDist = LastLength = 0; - // memset(Window,0,MaxWinSize); - //memset(&BlockTables,0,sizeof(BlockTables)); - BlockTables = new UnpackBlockTables(); - // sharpcompress: no default ctor for struct - BlockTables.Init(); - UnpPtr = WrPtr = 0; - WriteBorder = Math.Min(MaxWinSize, UNPACK_MAX_WRITE) & MaxWinMask; - } - // Filters never share several solid files, so we can safely reset them - // even in solid archive. - InitFilters(); + new Span(OldDist).Clear(); + OldDistPtr = 0; + LastDist = LastLength = 0; + // memset(Window,0,MaxWinSize); + //memset(&BlockTables,0,sizeof(BlockTables)); + BlockTables = new UnpackBlockTables(); + // sharpcompress: no default ctor for struct + BlockTables.Init(); + UnpPtr = WrPtr = 0; + WriteBorder = Math.Min(MaxWinSize, UNPACK_MAX_WRITE) & MaxWinMask; + } + // Filters never share several solid files, so we can safely reset them + // even in solid archive. + InitFilters(); - Inp.InitBitInput(); - WrittenFileSize = 0; - ReadTop = 0; - ReadBorder = 0; + Inp.InitBitInput(); + WrittenFileSize = 0; + ReadTop = 0; + ReadBorder = 0; - //memset(&BlockHeader,0,sizeof(BlockHeader)); - BlockHeader = new UnpackBlockHeader(); - BlockHeader.BlockSize = -1; // '-1' means not defined yet. + //memset(&BlockHeader,0,sizeof(BlockHeader)); + BlockHeader = new UnpackBlockHeader(); + BlockHeader.BlockSize = -1; // '-1' means not defined yet. #if !RarV2017_SFX_MODULE - UnpInitData20(Solid); + UnpInitData20(Solid); #endif - //UnpInitData30(Solid); - UnpInitData50(Solid); + //UnpInitData30(Solid); + UnpInitData50(Solid); + } + + // LengthTable contains the length in bits for every element of alphabet. + // Dec is the structure to decode Huffman code/ + // Size is size of length table and DecodeNum field in Dec structure, + private void MakeDecodeTables(byte[] LengthTable, int offset, DecodeTable Dec, uint Size) + { + // Size of alphabet and DecodePos array. + Dec.MaxNum = Size; + + // Calculate how many entries for every bit length in LengthTable we have. + var LengthCount = new uint[16]; + //memset(LengthCount,0,sizeof(LengthCount)); + for (size_t I = 0; I < Size; I++) + { + LengthCount[LengthTable[offset + I] & 0xf]++; } - // LengthTable contains the length in bits for every element of alphabet. - // Dec is the structure to decode Huffman code/ - // Size is size of length table and DecodeNum field in Dec structure, - private void MakeDecodeTables(byte[] LengthTable, int offset, DecodeTable Dec, uint Size) + // We must not calculate the number of zero length codes. + LengthCount[0] = 0; + + // Set the entire DecodeNum to zero. + //memset(Dec->DecodeNum,0,Size*sizeof(*Dec->DecodeNum)); + new Span(Dec.DecodeNum).Clear(); + + // Initialize not really used entry for zero length code. + Dec.DecodePos[0] = 0; + + // Start code for bit length 1 is 0. + Dec.DecodeLen[0] = 0; + + // Right aligned upper limit code for current bit length. + uint UpperLimit = 0; + + for (var I = 1; I < 16; I++) { - // Size of alphabet and DecodePos array. - Dec.MaxNum = Size; + // Adjust the upper limit code. + UpperLimit += LengthCount[I]; - // Calculate how many entries for every bit length in LengthTable we have. - uint[] LengthCount = new uint[16]; - //memset(LengthCount,0,sizeof(LengthCount)); - for (size_t I = 0; I < Size; I++) + // Left aligned upper limit code. + var LeftAligned = UpperLimit << (16 - I); + + // Prepare the upper limit code for next bit length. + UpperLimit *= 2; + + // Store the left aligned upper limit code. + Dec.DecodeLen[I] = LeftAligned; + + // Every item of this array contains the sum of all preceding items. + // So it contains the start position in code list for every bit length. + Dec.DecodePos[I] = Dec.DecodePos[I - 1] + LengthCount[I - 1]; + } + + // Prepare the copy of DecodePos. We'll modify this copy below, + // so we cannot use the original DecodePos. + var CopyDecodePos = new uint[Dec.DecodePos.Length]; + //memcpy(CopyDecodePos,Dec->DecodePos,sizeof(CopyDecodePos)); + Array.Copy(Dec.DecodePos, CopyDecodePos, CopyDecodePos.Length); + + // For every bit length in the bit length table and so for every item + // of alphabet. + for (uint I = 0; I < Size; I++) + { + // Get the current bit length. + var _CurBitLength = (byte)(LengthTable[offset + I] & 0xf); + + if (_CurBitLength != 0) { - LengthCount[LengthTable[offset + I] & 0xf]++; + // Last position in code list for current bit length. + var LastPos = CopyDecodePos[_CurBitLength]; + + // Prepare the decode table, so this position in code list will be + // decoded to current alphabet item number. + Dec.DecodeNum[LastPos] = (ushort)I; + + // We'll use next position number for this bit length next time. + // So we pass through the entire range of positions available + // for every bit length. + CopyDecodePos[_CurBitLength]++; + } + } + + // Define the number of bits to process in quick mode. We use more bits + // for larger alphabets. More bits means that more codes will be processed + // in quick mode, but also that more time will be spent to preparation + // of tables for quick decode. + switch (Size) + { + case NC: + case NC20: + case NC30: + Dec.QuickBits = MAX_QUICK_DECODE_BITS; + break; + default: + Dec.QuickBits = MAX_QUICK_DECODE_BITS - 3; + break; + } + + // Size of tables for quick mode. + var QuickDataSize = 1U << (int)Dec.QuickBits; + + // Bit length for current code, start from 1 bit codes. It is important + // to use 1 bit instead of 0 for minimum code length, so we are moving + // forward even when processing a corrupt archive. + //uint CurBitLength=1; + byte CurBitLength = 1; + + // For every right aligned bit string which supports the quick decoding. + for (uint Code = 0; Code < QuickDataSize; Code++) + { + // Left align the current code, so it will be in usual bit field format. + var BitField = Code << (int)(16 - Dec.QuickBits); + + // Prepare the table for quick decoding of bit lengths. + + // Find the upper limit for current bit field and adjust the bit length + // accordingly if necessary. + while ( + CurBitLength < Dec.DecodeLen.Length && BitField >= Dec.DecodeLen[CurBitLength] + ) + { + CurBitLength++; } - // We must not calculate the number of zero length codes. - LengthCount[0] = 0; + // Translation of right aligned bit string to bit length. + Dec.QuickLen[Code] = CurBitLength; - // Set the entire DecodeNum to zero. - //memset(Dec->DecodeNum,0,Size*sizeof(*Dec->DecodeNum)); - new Span(Dec.DecodeNum).Clear(); + // Prepare the table for quick translation of position in code list + // to position in alphabet. - // Initialize not really used entry for zero length code. - Dec.DecodePos[0] = 0; + // Calculate the distance from the start code for current bit length. + var Dist = BitField - Dec.DecodeLen[CurBitLength - 1]; - // Start code for bit length 1 is 0. - Dec.DecodeLen[0] = 0; + // Right align the distance. + Dist >>= (16 - CurBitLength); - // Right aligned upper limit code for current bit length. - uint UpperLimit = 0; - - for (int I = 1; I < 16; I++) + // Now we can calculate the position in the code list. It is the sum + // of first position for current bit length and right aligned distance + // between our bit field and start code for current bit length. + uint Pos; + if ( + CurBitLength < Dec.DecodePos.Length + && (Pos = Dec.DecodePos[CurBitLength] + Dist) < Size + ) { - // Adjust the upper limit code. - UpperLimit += LengthCount[I]; - - // Left aligned upper limit code. - uint LeftAligned = UpperLimit << (16 - I); - - // Prepare the upper limit code for next bit length. - UpperLimit *= 2; - - // Store the left aligned upper limit code. - Dec.DecodeLen[I] = (uint)LeftAligned; - - // Every item of this array contains the sum of all preceding items. - // So it contains the start position in code list for every bit length. - Dec.DecodePos[I] = Dec.DecodePos[I - 1] + LengthCount[I - 1]; + // Define the code to alphabet number translation. + Dec.QuickNum[Code] = Dec.DecodeNum[Pos]; } - - // Prepare the copy of DecodePos. We'll modify this copy below, - // so we cannot use the original DecodePos. - uint[] CopyDecodePos = new uint[Dec.DecodePos.Length]; - //memcpy(CopyDecodePos,Dec->DecodePos,sizeof(CopyDecodePos)); - Array.Copy(Dec.DecodePos, CopyDecodePos, CopyDecodePos.Length); - - // For every bit length in the bit length table and so for every item - // of alphabet. - for (uint I = 0; I < Size; I++) + else { - // Get the current bit length. - byte _CurBitLength = (byte)(LengthTable[offset + I] & 0xf); - - if (_CurBitLength != 0) - { - // Last position in code list for current bit length. - uint LastPos = CopyDecodePos[_CurBitLength]; - - // Prepare the decode table, so this position in code list will be - // decoded to current alphabet item number. - Dec.DecodeNum[LastPos] = (ushort)I; - - // We'll use next position number for this bit length next time. - // So we pass through the entire range of positions available - // for every bit length. - CopyDecodePos[_CurBitLength]++; - } - } - - // Define the number of bits to process in quick mode. We use more bits - // for larger alphabets. More bits means that more codes will be processed - // in quick mode, but also that more time will be spent to preparation - // of tables for quick decode. - switch (Size) - { - case NC: - case NC20: - case NC30: - Dec.QuickBits = MAX_QUICK_DECODE_BITS; - break; - default: - Dec.QuickBits = MAX_QUICK_DECODE_BITS - 3; - break; - } - - // Size of tables for quick mode. - uint QuickDataSize = 1U << (int)Dec.QuickBits; - - // Bit length for current code, start from 1 bit codes. It is important - // to use 1 bit instead of 0 for minimum code length, so we are moving - // forward even when processing a corrupt archive. - //uint CurBitLength=1; - byte CurBitLength = 1; - - // For every right aligned bit string which supports the quick decoding. - for (uint Code = 0; Code < QuickDataSize; Code++) - { - // Left align the current code, so it will be in usual bit field format. - uint BitField = Code << (int)(16 - Dec.QuickBits); - - // Prepare the table for quick decoding of bit lengths. - - // Find the upper limit for current bit field and adjust the bit length - // accordingly if necessary. - while ( - CurBitLength < Dec.DecodeLen.Length && BitField >= Dec.DecodeLen[CurBitLength] - ) - { - CurBitLength++; - } - - // Translation of right aligned bit string to bit length. - Dec.QuickLen[Code] = CurBitLength; - - // Prepare the table for quick translation of position in code list - // to position in alphabet. - - // Calculate the distance from the start code for current bit length. - uint Dist = BitField - Dec.DecodeLen[CurBitLength - 1]; - - // Right align the distance. - Dist >>= (16 - CurBitLength); - - // Now we can calculate the position in the code list. It is the sum - // of first position for current bit length and right aligned distance - // between our bit field and start code for current bit length. - uint Pos; - if ( - CurBitLength < Dec.DecodePos.Length - && (Pos = Dec.DecodePos[CurBitLength] + Dist) < Size - ) - { - // Define the code to alphabet number translation. - Dec.QuickNum[Code] = Dec.DecodeNum[Pos]; - } - else - { - // Can be here for length table filled with zeroes only (empty). - Dec.QuickNum[Code] = 0; - } + // Can be here for length table filled with zeroes only (empty). + Dec.QuickNum[Code] = 0; } } } diff --git a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpackinline_cpp.cs b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpackinline_cpp.cs index 8c585af2..584d0b51 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpackinline_cpp.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpackinline_cpp.cs @@ -1,179 +1,173 @@ -#if !Rar2017_64bit -using nint = System.Int32; -using nuint = System.UInt32; -using size_t = System.UInt32; +#if !Rar2017_64bit #else using nint = System.Int64; using nuint = System.UInt64; using size_t = System.UInt64; #endif -using int64 = System.Int64; - using static SharpCompress.Compressors.Rar.UnpackV2017.PackDef; -namespace SharpCompress.Compressors.Rar.UnpackV2017 +namespace SharpCompress.Compressors.Rar.UnpackV2017; + +internal partial class Unpack { - internal partial class Unpack + private void InsertOldDist(uint Distance) { - private void InsertOldDist(uint Distance) + OldDist[3] = OldDist[2]; + OldDist[2] = OldDist[1]; + OldDist[1] = OldDist[0]; + OldDist[0] = Distance; + } + + //#ifdef _MSC_VER + //#define FAST_MEMCPY + //#endif + + private void CopyString(uint Length, uint Distance) + { + var SrcPtr = UnpPtr - Distance; + + if (SrcPtr < MaxWinSize - MAX_LZ_MATCH && UnpPtr < MaxWinSize - MAX_LZ_MATCH) { - OldDist[3] = OldDist[2]; - OldDist[2] = OldDist[1]; - OldDist[1] = OldDist[0]; - OldDist[0] = Distance; + // If we are not close to end of window, we do not need to waste time + // to "& MaxWinMask" pointer protection. + + // TODO: sharpcompress: non-optimized loop, we may be able to unroll and speed up + var Window = this.Window; + while (Length-- > 0) + { + Window[UnpPtr++] = Window[SrcPtr++]; + } + + // byte *Src=Window+SrcPtr; + // byte *Dest=Window+UnpPtr; + // UnpPtr+=Length; + // + //#if FAST_MEMCPY + // if (Distance=8) + // { + // Dest[0]=Src[0]; + // Dest[1]=Src[1]; + // Dest[2]=Src[2]; + // Dest[3]=Src[3]; + // Dest[4]=Src[4]; + // Dest[5]=Src[5]; + // Dest[6]=Src[6]; + // Dest[7]=Src[7]; + // + // Src+=8; + // Dest+=8; + // Length-=8; + // } + //#if FAST_MEMCPY + // else + // while (Length>=8) + // { + // // In theory we still could overlap here. + // // Supposing Distance == MaxWinSize - 1 we have memcpy(Src, Src + 1, 8). + // // But for real RAR archives Distance <= MaxWinSize - MAX_LZ_MATCH + // // always, so overlap here is impossible. + // + // // This memcpy expanded inline by MSVC. We could also use uint64 + // // assignment, which seems to provide about the same speed. + // memcpy(Dest,Src,8); + // + // Src+=8; + // Dest+=8; + // Length-=8; + // } + //#endif + // + // // Unroll the loop for 0 - 7 bytes left. Note that we use nested "if"s. + // if (Length>0) { Dest[0]=Src[0]; + // if (Length>1) { Dest[1]=Src[1]; + // if (Length>2) { Dest[2]=Src[2]; + // if (Length>3) { Dest[3]=Src[3]; + // if (Length>4) { Dest[4]=Src[4]; + // if (Length>5) { Dest[5]=Src[5]; + // if (Length>6) { Dest[6]=Src[6]; } } } } } } } // Close all nested "if"s. } - - //#ifdef _MSC_VER - //#define FAST_MEMCPY - //#endif - - private void CopyString(uint Length, uint Distance) + else { - size_t SrcPtr = UnpPtr - Distance; - - if (SrcPtr < MaxWinSize - MAX_LZ_MATCH && UnpPtr < MaxWinSize - MAX_LZ_MATCH) + while (Length-- > 0) // Slow copying with all possible precautions. { - // If we are not close to end of window, we do not need to waste time - // to "& MaxWinMask" pointer protection. - - // TODO: sharpcompress: non-optimized loop, we may be able to unroll and speed up - var Window = this.Window; - while (Length-- > 0) - { - Window[UnpPtr++] = Window[SrcPtr++]; - } - - // byte *Src=Window+SrcPtr; - // byte *Dest=Window+UnpPtr; - // UnpPtr+=Length; - // - //#if FAST_MEMCPY - // if (Distance=8) - // { - // Dest[0]=Src[0]; - // Dest[1]=Src[1]; - // Dest[2]=Src[2]; - // Dest[3]=Src[3]; - // Dest[4]=Src[4]; - // Dest[5]=Src[5]; - // Dest[6]=Src[6]; - // Dest[7]=Src[7]; - // - // Src+=8; - // Dest+=8; - // Length-=8; - // } - //#if FAST_MEMCPY - // else - // while (Length>=8) - // { - // // In theory we still could overlap here. - // // Supposing Distance == MaxWinSize - 1 we have memcpy(Src, Src + 1, 8). - // // But for real RAR archives Distance <= MaxWinSize - MAX_LZ_MATCH - // // always, so overlap here is impossible. - // - // // This memcpy expanded inline by MSVC. We could also use uint64 - // // assignment, which seems to provide about the same speed. - // memcpy(Dest,Src,8); - // - // Src+=8; - // Dest+=8; - // Length-=8; - // } - //#endif - // - // // Unroll the loop for 0 - 7 bytes left. Note that we use nested "if"s. - // if (Length>0) { Dest[0]=Src[0]; - // if (Length>1) { Dest[1]=Src[1]; - // if (Length>2) { Dest[2]=Src[2]; - // if (Length>3) { Dest[3]=Src[3]; - // if (Length>4) { Dest[4]=Src[4]; - // if (Length>5) { Dest[5]=Src[5]; - // if (Length>6) { Dest[6]=Src[6]; } } } } } } } // Close all nested "if"s. + Window[UnpPtr] = Window[SrcPtr++ & MaxWinMask]; + // We need to have masked UnpPtr after quit from loop, so it must not + // be replaced with 'Window[UnpPtr++ & MaxWinMask]' + UnpPtr = (UnpPtr + 1) & MaxWinMask; } - else - { - while (Length-- > 0) // Slow copying with all possible precautions. - { - Window[UnpPtr] = Window[SrcPtr++ & MaxWinMask]; - // We need to have masked UnpPtr after quit from loop, so it must not - // be replaced with 'Window[UnpPtr++ & MaxWinMask]' - UnpPtr = (UnpPtr + 1) & MaxWinMask; - } - } - } - - private uint DecodeNumber(BitInput Inp, DecodeTable Dec) - { - // Left aligned 15 bit length raw bit field. - uint BitField = Inp.getbits() & 0xfffe; - - if (BitField < Dec.DecodeLen[Dec.QuickBits]) - { - uint Code = BitField >> (int)(16 - Dec.QuickBits); - Inp.addbits(Dec.QuickLen[Code]); - return Dec.QuickNum[Code]; - } - - // Detect the real bit length for current code. - uint Bits = 15; - for (uint I = Dec.QuickBits + 1; I < 15; I++) - { - if (BitField < Dec.DecodeLen[I]) - { - Bits = I; - break; - } - } - - Inp.addbits(Bits); - - // Calculate the distance from the start code for current bit length. - uint Dist = BitField - Dec.DecodeLen[Bits - 1]; - - // Start codes are left aligned, but we need the normal right aligned - // number. So we shift the distance to the right. - Dist >>= (int)(16 - Bits); - - // Now we can calculate the position in the code list. It is the sum - // of first position for current bit length and right aligned distance - // between our bit field and start code for current bit length. - uint Pos = Dec.DecodePos[Bits] + Dist; - - // Out of bounds safety check required for damaged archives. - if (Pos >= Dec.MaxNum) - { - Pos = 0; - } - - // Convert the position in the code list to position in alphabet - // and return it. - return Dec.DecodeNum[Pos]; - } - - private uint SlotToLength(BitInput Inp, uint Slot) - { - uint LBits, - Length = 2; - if (Slot < 8) - { - LBits = 0; - Length += Slot; - } - else - { - LBits = Slot / 4 - 1; - Length += (4 | (Slot & 3)) << (int)LBits; - } - - if (LBits > 0) - { - Length += Inp.getbits() >> (int)(16 - LBits); - Inp.addbits(LBits); - } - return Length; } } + + private uint DecodeNumber(BitInput Inp, DecodeTable Dec) + { + // Left aligned 15 bit length raw bit field. + var BitField = Inp.getbits() & 0xfffe; + + if (BitField < Dec.DecodeLen[Dec.QuickBits]) + { + var Code = BitField >> (int)(16 - Dec.QuickBits); + Inp.addbits(Dec.QuickLen[Code]); + return Dec.QuickNum[Code]; + } + + // Detect the real bit length for current code. + uint Bits = 15; + for (var I = Dec.QuickBits + 1; I < 15; I++) + { + if (BitField < Dec.DecodeLen[I]) + { + Bits = I; + break; + } + } + + Inp.addbits(Bits); + + // Calculate the distance from the start code for current bit length. + var Dist = BitField - Dec.DecodeLen[Bits - 1]; + + // Start codes are left aligned, but we need the normal right aligned + // number. So we shift the distance to the right. + Dist >>= (int)(16 - Bits); + + // Now we can calculate the position in the code list. It is the sum + // of first position for current bit length and right aligned distance + // between our bit field and start code for current bit length. + var Pos = Dec.DecodePos[Bits] + Dist; + + // Out of bounds safety check required for damaged archives. + if (Pos >= Dec.MaxNum) + { + Pos = 0; + } + + // Convert the position in the code list to position in alphabet + // and return it. + return Dec.DecodeNum[Pos]; + } + + private uint SlotToLength(BitInput Inp, uint Slot) + { + uint LBits, + Length = 2; + if (Slot < 8) + { + LBits = 0; + Length += Slot; + } + else + { + LBits = (Slot / 4) - 1; + Length += (4 | (Slot & 3)) << (int)LBits; + } + + if (LBits > 0) + { + Length += Inp.getbits() >> (int)(16 - LBits); + Inp.addbits(LBits); + } + return Length; + } } diff --git a/src/SharpCompress/Compressors/Rar/UnpackV2017/unpack_hpp.cs b/src/SharpCompress/Compressors/Rar/UnpackV2017/unpack_hpp.cs index a0905ff4..ddeefa86 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV2017/unpack_hpp.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV2017/unpack_hpp.cs @@ -1,6 +1,4 @@ -#if !Rar2017_64bit -using nint = System.Int32; -using nuint = System.UInt32; +#if !Rar2017_64bit using size_t = System.UInt32; #else using nint = System.Int64; @@ -18,429 +16,383 @@ using System; #pragma warning disable 169 #pragma warning disable 414 -namespace SharpCompress.Compressors.Rar.UnpackV2017 +namespace SharpCompress.Compressors.Rar.UnpackV2017; + +internal static class UnpackGlobal { - internal static class UnpackGlobal + + + // Maximum allowed number of compressed bits processed in quick mode. + public const int MAX_QUICK_DECODE_BITS = 10; + + // Maximum number of filters per entire data block. Must be at least + // twice more than MAX_PACK_FILTERS to store filters from two data blocks. + public const int MAX_UNPACK_FILTERS = 8192; + + // Maximum number of filters per entire data block for RAR3 unpack. + // Must be at least twice more than v3_MAX_PACK_FILTERS to store filters + // from two data blocks. + public const int MAX3_UNPACK_FILTERS = 8192; + + // Maximum size of single filter block. We restrict it to limit memory + // allocation. Must be equal or larger than MAX_ANALYZE_SIZE. + public const int MAX_FILTER_BLOCK_SIZE = 0x400000; + + // Write data in 4 MB or smaller blocks. Must not exceed PACK_MAX_WRITE, + // so we keep number of buffered filter in unpacker reasonable. + public const int UNPACK_MAX_WRITE = 0x400000; +} + +// Decode compressed bit fields to alphabet numbers. +internal sealed class DecodeTable +{ + // Real size of DecodeNum table. + public uint MaxNum; + + // Left aligned start and upper limit codes defining code space + // ranges for bit lengths. DecodeLen[BitLength-1] defines the start of + // range for bit length and DecodeLen[BitLength] defines next code + // after the end of range or in other words the upper limit code + // for specified bit length. + public readonly uint[] DecodeLen = new uint[16]; + + // Every item of this array contains the sum of all preceding items. + // So it contains the start position in code list for every bit length. + public readonly uint[] DecodePos = new uint[16]; + + // Number of compressed bits processed in quick mode. + // Must not exceed MAX_QUICK_DECODE_BITS. + public uint QuickBits; + + // Translates compressed bits (up to QuickBits length) + // to bit length in quick mode. + public readonly byte[] QuickLen = new byte[1 << MAX_QUICK_DECODE_BITS]; + + // Translates compressed bits (up to QuickBits length) + // to position in alphabet in quick mode. + // 'ushort' saves some memory and even provides a little speed gain + // comparting to 'uint' here. + public readonly ushort[] QuickNum = new ushort[1 << MAX_QUICK_DECODE_BITS]; + + // Translate the position in code list to position in alphabet. + // We do not allocate it dynamically to avoid performance overhead + // introduced by pointer, so we use the largest possible table size + // as array dimension. Real size of this array is defined in MaxNum. + // We use this array if compressed bit field is too lengthy + // for QuickLen based translation. + // 'ushort' saves some memory and even provides a little speed gain + // comparting to 'uint' here. + public readonly ushort[] DecodeNum = new ushort[LARGEST_TABLE_SIZE]; +}; + +internal struct UnpackBlockHeader +{ + public int BlockSize; + public int BlockBitSize; + public int BlockStart; + public int HeaderSize; + public bool LastBlockInFile; + public bool TablePresent; +}; + +internal struct UnpackBlockTables +{ + public DecodeTable LD; // Decode literals. + public DecodeTable DD; // Decode distances. + public DecodeTable LDD; // Decode lower bits of distances. + public DecodeTable RD; // Decode repeating distances. + public DecodeTable BD; // Decode bit lengths in Huffman table. + + public void Init() { - - - // Maximum allowed number of compressed bits processed in quick mode. - public const int MAX_QUICK_DECODE_BITS = 10; - - // Maximum number of filters per entire data block. Must be at least - // twice more than MAX_PACK_FILTERS to store filters from two data blocks. - public const int MAX_UNPACK_FILTERS = 8192; - - // Maximum number of filters per entire data block for RAR3 unpack. - // Must be at least twice more than v3_MAX_PACK_FILTERS to store filters - // from two data blocks. - public const int MAX3_UNPACK_FILTERS = 8192; - - // Limit maximum number of channels in RAR3 delta filter to some reasonable - // value to prevent too slow processing of corrupt archives with invalid - // channels number. Must be equal or larger than v3_MAX_FILTER_CHANNELS. - // No need to provide it for RAR5, which uses only 5 bits to store channels. - private const int MAX3_UNPACK_CHANNELS = 1024; - - // Maximum size of single filter block. We restrict it to limit memory - // allocation. Must be equal or larger than MAX_ANALYZE_SIZE. - public const int MAX_FILTER_BLOCK_SIZE = 0x400000; - - // Write data in 4 MB or smaller blocks. Must not exceed PACK_MAX_WRITE, - // so we keep number of buffered filter in unpacker reasonable. - public const int UNPACK_MAX_WRITE = 0x400000; + LD = new DecodeTable(); + DD = new DecodeTable(); + LDD = new DecodeTable(); + RD = new DecodeTable(); + BD = new DecodeTable(); } - - // Decode compressed bit fields to alphabet numbers. - internal sealed class DecodeTable - { - // Real size of DecodeNum table. - public uint MaxNum; - - // Left aligned start and upper limit codes defining code space - // ranges for bit lengths. DecodeLen[BitLength-1] defines the start of - // range for bit length and DecodeLen[BitLength] defines next code - // after the end of range or in other words the upper limit code - // for specified bit length. - public readonly uint[] DecodeLen = new uint[16]; - - // Every item of this array contains the sum of all preceding items. - // So it contains the start position in code list for every bit length. - public readonly uint[] DecodePos = new uint[16]; - - // Number of compressed bits processed in quick mode. - // Must not exceed MAX_QUICK_DECODE_BITS. - public uint QuickBits; - - // Translates compressed bits (up to QuickBits length) - // to bit length in quick mode. - public readonly byte[] QuickLen = new byte[1 << MAX_QUICK_DECODE_BITS]; - - // Translates compressed bits (up to QuickBits length) - // to position in alphabet in quick mode. - // 'ushort' saves some memory and even provides a little speed gain - // comparting to 'uint' here. - public readonly ushort[] QuickNum = new ushort[1 << MAX_QUICK_DECODE_BITS]; - - // Translate the position in code list to position in alphabet. - // We do not allocate it dynamically to avoid performance overhead - // introduced by pointer, so we use the largest possible table size - // as array dimension. Real size of this array is defined in MaxNum. - // We use this array if compressed bit field is too lengthy - // for QuickLen based translation. - // 'ushort' saves some memory and even provides a little speed gain - // comparting to 'uint' here. - public readonly ushort[] DecodeNum = new ushort[LARGEST_TABLE_SIZE]; - }; - - internal struct UnpackBlockHeader - { - public int BlockSize; - public int BlockBitSize; - public int BlockStart; - public int HeaderSize; - public bool LastBlockInFile; - public bool TablePresent; - }; - - internal struct UnpackBlockTables - { - public DecodeTable LD; // Decode literals. - public DecodeTable DD; // Decode distances. - public DecodeTable LDD; // Decode lower bits of distances. - public DecodeTable RD; // Decode repeating distances. - public DecodeTable BD; // Decode bit lengths in Huffman table. - - public void Init() - { - LD = new DecodeTable(); - DD = new DecodeTable(); - LDD = new DecodeTable(); - RD = new DecodeTable(); - BD = new DecodeTable(); - } - }; +}; #if RarV2017_RAR_SMP enum UNP_DEC_TYPE { - UNPDT_LITERAL,UNPDT_MATCH,UNPDT_FULLREP,UNPDT_REP,UNPDT_FILTER +UNPDT_LITERAL,UNPDT_MATCH,UNPDT_FULLREP,UNPDT_REP,UNPDT_FILTER }; struct UnpackDecodedItem { - UNP_DEC_TYPE Type; - ushort Length; - union - { - uint Distance; - byte Literal[4]; - }; +UNP_DEC_TYPE Type; +ushort Length; +union +{ +uint Distance; +byte Literal[4]; +}; }; struct UnpackThreadData { - Unpack *UnpackPtr; - BitInput Inp; - bool HeaderRead; - UnpackBlockHeader BlockHeader; - bool TableRead; - UnpackBlockTables BlockTables; - int DataSize; // Data left in buffer. Can be less than block size. - bool DamagedData; - bool LargeBlock; - bool NoDataLeft; // 'true' if file is read completely. - bool Incomplete; // Not entire block was processed, need to read more data. +Unpack *UnpackPtr; +BitInput Inp; +bool HeaderRead; +UnpackBlockHeader BlockHeader; +bool TableRead; +UnpackBlockTables BlockTables; +int DataSize; // Data left in buffer. Can be less than block size. +bool DamagedData; +bool LargeBlock; +bool NoDataLeft; // 'true' if file is read completely. +bool Incomplete; // Not entire block was processed, need to read more data. - UnpackDecodedItem *Decoded; - uint DecodedSize; - uint DecodedAllocated; - uint ThreadNumber; // For debugging. +UnpackDecodedItem *Decoded; +uint DecodedSize; +uint DecodedAllocated; +uint ThreadNumber; // For debugging. - UnpackThreadData() - :Inp(false) - { - Decoded=NULL; - } - ~UnpackThreadData() - { - if (Decoded!=NULL) - free(Decoded); - } +UnpackThreadData() +:Inp(false) +{ +Decoded=NULL; +} +~UnpackThreadData() +{ +if (Decoded!=NULL) + free(Decoded); +} }; #endif - //struct UnpackFilter - internal class UnpackFilter - { - public byte Type; - public uint BlockStart; - public uint BlockLength; - public byte Channels; - // uint Width; - // byte PosR; - public bool NextWindow; - }; +//struct UnpackFilter +internal class UnpackFilter +{ + public byte Type; + public uint BlockStart; + public uint BlockLength; + public byte Channels; + // uint Width; + // byte PosR; + public bool NextWindow; +}; - //struct UnpackFilter30 - internal class UnpackFilter30 - { - public uint BlockStart; - public uint BlockLength; - public bool NextWindow; +//struct UnpackFilter30 +internal class UnpackFilter30 +{ + public uint BlockStart; + public uint BlockLength; + public bool NextWindow; - // Position of parent filter in Filters array used as prototype for filter - // in PrgStack array. Not defined for filters in Filters array. - public uint ParentFilter; + // Position of parent filter in Filters array used as prototype for filter + // in PrgStack array. Not defined for filters in Filters array. + public uint ParentFilter; - /*#if !RarV2017_RAR5ONLY - public VM_PreparedProgram Prg; - #endif*/ - }; + /*#if !RarV2017_RAR5ONLY + public VM_PreparedProgram Prg; + #endif*/ +}; - internal class AudioVariables // For RAR 2.0 archives only. - { - public int K1, K2, K3, K4, K5; - public int D1, D2, D3, D4; - public int LastDelta; - public readonly uint[] Dif = new uint[11]; - public uint ByteCount; - public int LastChar; - }; +internal class AudioVariables // For RAR 2.0 archives only. +{ + public int K1, K2, K3, K4, K5; + public int D1, D2, D3, D4; + public int LastDelta; + public readonly uint[] Dif = new uint[11]; + public uint ByteCount; + public int LastChar; +}; - // We can use the fragmented dictionary in case heap does not have the single - // large enough memory block. It is slower than normal dictionary. - internal partial class FragmentedWindow - { - private const int MAX_MEM_BLOCKS = 32; +// We can use the fragmented dictionary in case heap does not have the single +// large enough memory block. It is slower than normal dictionary. +internal partial class FragmentedWindow +{ + private const int MAX_MEM_BLOCKS = 32; - //void Reset(); - private readonly byte[][] Mem = new byte[MAX_MEM_BLOCKS][]; - private readonly size_t[] MemSize = new size_t[MAX_MEM_BLOCKS]; + //void Reset(); + private readonly byte[][] Mem = new byte[MAX_MEM_BLOCKS][]; + private readonly size_t[] MemSize = new size_t[MAX_MEM_BLOCKS]; - //FragmentedWindow(); - //~FragmentedWindow(); - //void Init(size_t WinSize); - //byte& operator [](size_t Item); - //void CopyString(uint Length,uint Distance,size_t &UnpPtr,size_t MaxWinMask); - //void CopyData(byte *Dest,size_t WinPos,size_t Size); - //size_t GetBlockSize(size_t StartPos,size_t RequiredSize); - }; + //FragmentedWindow(); + //~FragmentedWindow(); + //void Init(size_t WinSize); + //byte& operator [](size_t Item); + //void CopyString(uint Length,uint Distance,size_t &UnpPtr,size_t MaxWinMask); + //void CopyData(byte *Dest,size_t WinPos,size_t Size); + //size_t GetBlockSize(size_t StartPos,size_t RequiredSize); +}; - internal partial class Unpack - { +internal partial class Unpack +{ - //void Unpack5(bool Solid); - //void Unpack5MT(bool Solid); - //bool UnpReadBuf(); - //void UnpWriteBuf(); - //byte* ApplyFilter(byte *Data,uint DataSize,UnpackFilter *Flt); - //void UnpWriteArea(size_t StartPtr,size_t EndPtr); - //void UnpWriteData(byte *Data,size_t Size); - //_forceinline uint SlotToLength(BitInput &Inp,uint Slot); - //void UnpInitData50(bool Solid); - //bool ReadBlockHeader(BitInput &Inp,UnpackBlockHeader &Header); - //bool ReadTables(BitInput &Inp,UnpackBlockHeader &Header,UnpackBlockTables &Tables); - //void MakeDecodeTables(byte *LengthTable,DecodeTable *Dec,uint Size); - //_forceinline uint DecodeNumber(BitInput &Inp,DecodeTable *Dec); - //void CopyString(); - //inline void InsertOldDist(uint Distance); - //void UnpInitData(bool Solid); - //_forceinline void CopyString(uint Length,uint Distance); - //uint ReadFilterData(BitInput &Inp); - //bool ReadFilter(BitInput &Inp,UnpackFilter &Filter); - //bool AddFilter(UnpackFilter &Filter); - //bool AddFilter(); - //void InitFilters(); + //void Unpack5(bool Solid); + //void Unpack5MT(bool Solid); + //bool UnpReadBuf(); + //void UnpWriteBuf(); + //byte* ApplyFilter(byte *Data,uint DataSize,UnpackFilter *Flt); + //void UnpWriteArea(size_t StartPtr,size_t EndPtr); + //void UnpWriteData(byte *Data,size_t Size); + //_forceinline uint SlotToLength(BitInput &Inp,uint Slot); + //void UnpInitData50(bool Solid); + //bool ReadBlockHeader(BitInput &Inp,UnpackBlockHeader &Header); + //bool ReadTables(BitInput &Inp,UnpackBlockHeader &Header,UnpackBlockTables &Tables); + //void MakeDecodeTables(byte *LengthTable,DecodeTable *Dec,uint Size); + //_forceinline uint DecodeNumber(BitInput &Inp,DecodeTable *Dec); + //void CopyString(); + //inline void InsertOldDist(uint Distance); + //void UnpInitData(bool Solid); + //_forceinline void CopyString(uint Length,uint Distance); + //uint ReadFilterData(BitInput &Inp); + //bool ReadFilter(BitInput &Inp,UnpackFilter &Filter); + //bool AddFilter(UnpackFilter &Filter); + //bool AddFilter(); + //void InitFilters(); - //ComprDataIO *UnpIO; - //BitInput Inp; - private BitInput Inp { get { return this; } } // hopefully this gets inlined + //ComprDataIO *UnpIO; + //BitInput Inp; + private BitInput Inp { get { return this; } } // hopefully this gets inlined #if RarV2017_RAR_SMP - void InitMT(); - bool UnpackLargeBlock(UnpackThreadData &D); - bool ProcessDecoded(UnpackThreadData &D); +void InitMT(); +bool UnpackLargeBlock(UnpackThreadData &D); +bool ProcessDecoded(UnpackThreadData &D); - ThreadPool *UnpThreadPool; - UnpackThreadData *UnpThreadData; - uint MaxUserThreads; - byte *ReadBufMT; +ThreadPool *UnpThreadPool; +UnpackThreadData *UnpThreadData; +uint MaxUserThreads; +byte *ReadBufMT; #endif - private byte[] FilterSrcMemory = Array.Empty(); - private byte[] FilterDstMemory = Array.Empty(); + private byte[] FilterSrcMemory = Array.Empty(); + private byte[] FilterDstMemory = Array.Empty(); - // Filters code, one entry per filter. - private readonly List Filters = new List(); + // Filters code, one entry per filter. + private readonly List Filters = new List(); - private readonly uint[] OldDist = new uint[4]; - private uint OldDistPtr; - private uint LastLength; + private readonly uint[] OldDist = new uint[4]; + private uint OldDistPtr; + private uint LastLength; - // LastDist is necessary only for RAR2 and older with circular OldDist - // array. In RAR3 last distance is always stored in OldDist[0]. - private uint LastDist; + // LastDist is necessary only for RAR2 and older with circular OldDist + // array. In RAR3 last distance is always stored in OldDist[0]. + private uint LastDist; - private size_t UnpPtr, WrPtr; + private size_t UnpPtr, WrPtr; - // Top border of read packed data. - private int ReadTop; + // Top border of read packed data. + private int ReadTop; - // Border to call UnpReadBuf. We use it instead of (ReadTop-C) - // for optimization reasons. Ensures that we have C bytes in buffer - // unless we are at the end of file. - private int ReadBorder; + // Border to call UnpReadBuf. We use it instead of (ReadTop-C) + // for optimization reasons. Ensures that we have C bytes in buffer + // unless we are at the end of file. + private int ReadBorder; - private UnpackBlockHeader BlockHeader; - private UnpackBlockTables BlockTables; + private UnpackBlockHeader BlockHeader; + private UnpackBlockTables BlockTables; - private size_t WriteBorder; + private size_t WriteBorder; - private byte[] Window; + private byte[] Window; - private readonly FragmentedWindow FragWindow = new FragmentedWindow(); - private bool Fragmented; + private readonly FragmentedWindow FragWindow = new FragmentedWindow(); + private bool Fragmented; - private int64 DestUnpSize; + private int64 DestUnpSize; - //bool Suspended; - private bool UnpAllBuf; - private bool UnpSomeRead; - private int64 WrittenFileSize; - private bool FileExtracted; + //bool Suspended; + private bool UnpAllBuf; + private bool UnpSomeRead; + private int64 WrittenFileSize; + private bool FileExtracted; - /***************************** Unpack v 1.5 *********************************/ - //void Unpack15(bool Solid); - //void ShortLZ(); - //void LongLZ(); - //void HuffDecode(); - //void GetFlagsBuf(); - //void UnpInitData15(int Solid); - //void InitHuff(); - //void CorrHuff(ushort *CharSet,byte *NumToPlace); - //void CopyString15(uint Distance,uint Length); - //uint DecodeNum(uint Num,uint StartPos,uint *DecTab,uint *PosTab); + /***************************** Unpack v 1.5 *********************************/ + //void Unpack15(bool Solid); + //void ShortLZ(); + //void LongLZ(); + //void HuffDecode(); + //void GetFlagsBuf(); + //void UnpInitData15(int Solid); + //void InitHuff(); + //void CorrHuff(ushort *CharSet,byte *NumToPlace); + //void CopyString15(uint Distance,uint Length); + //uint DecodeNum(uint Num,uint StartPos,uint *DecTab,uint *PosTab); - private readonly ushort[] ChSet = new ushort[256], ChSetA = new ushort[256], ChSetB = new ushort[256], ChSetC = new ushort[256]; - private readonly byte[] NToPl = new byte[256], NToPlB = new byte[256], NToPlC = new byte[256]; - private uint FlagBuf, AvrPlc, AvrPlcB, AvrLn1, AvrLn2, AvrLn3; - private int Buf60, NumHuf, StMode, LCount, FlagsCnt; + private readonly ushort[] ChSet = new ushort[256], ChSetA = new ushort[256], ChSetB = new ushort[256], ChSetC = new ushort[256]; + private readonly byte[] NToPl = new byte[256], NToPlB = new byte[256], NToPlC = new byte[256]; + private uint FlagBuf, AvrPlc, AvrPlcB, AvrLn1, AvrLn2, AvrLn3; + private int Buf60, NumHuf, StMode, LCount, FlagsCnt; - private uint Nhfb, Nlzb, MaxDist3; - /***************************** Unpack v 1.5 *********************************/ + private uint Nhfb, Nlzb, MaxDist3; + /***************************** Unpack v 1.5 *********************************/ - /***************************** Unpack v 2.0 *********************************/ - //void Unpack20(bool Solid); + /***************************** Unpack v 2.0 *********************************/ + //void Unpack20(bool Solid); - private DecodeTable[] MD = new DecodeTable[4]; // Decode multimedia data, up to 4 channels. + private DecodeTable[] MD = new DecodeTable[4]; // Decode multimedia data, up to 4 channels. - private readonly byte[] UnpOldTable20 = new byte[MC20 * 4]; - private bool UnpAudioBlock; - private uint UnpChannels, UnpCurChannel; + private readonly byte[] UnpOldTable20 = new byte[MC20 * 4]; + private bool UnpAudioBlock; + private uint UnpChannels, UnpCurChannel; - private int UnpChannelDelta; - //void CopyString20(uint Length,uint Distance); - //bool ReadTables20(); - //void UnpWriteBuf20(); - //void UnpInitData20(int Solid); - //void ReadLastTables(); - //byte DecodeAudio(int Delta); - private AudioVariables[] AudV = new AudioVariables[4]; - /***************************** Unpack v 2.0 *********************************/ + private int UnpChannelDelta; + //void CopyString20(uint Length,uint Distance); + //bool ReadTables20(); + //void UnpWriteBuf20(); + //void UnpInitData20(int Solid); + //void ReadLastTables(); + //byte DecodeAudio(int Delta); + private AudioVariables[] AudV = new AudioVariables[4]; + /***************************** Unpack v 2.0 *********************************/ - /***************************** Unpack v 3.0 *********************************/ - public const int BLOCK_LZ = 0; - public const int BLOCK_PPM = 1; + /***************************** Unpack v 3.0 *********************************/ + public const int BLOCK_LZ = 0; + public const int BLOCK_PPM = 1; - //void UnpInitData30(bool Solid); - //void Unpack29(bool Solid); - //void InitFilters30(bool Solid); - //bool ReadEndOfBlock(); - //bool ReadVMCode(); - //bool ReadVMCodePPM(); - //bool AddVMCode(uint FirstByte,byte *Code,int CodeSize); - //int SafePPMDecodeChar(); - //bool ReadTables30(); - //bool UnpReadBuf30(); - //void UnpWriteBuf30(); - //void ExecuteCode(VM_PreparedProgram *Prg); + /*#if !RarV2017_RAR5ONLY + ModelPPM PPM; + #endif*/ + private int PPMEscChar; - private int PrevLowDist, LowDistRepCount; + private readonly byte[] UnpOldTable = new byte[HUFF_TABLE_SIZE30]; - /*#if !RarV2017_RAR5ONLY - ModelPPM PPM; - #endif*/ - private int PPMEscChar; + // If we already read decoding tables for Unpack v2,v3,v5. + // We should not use a single variable for all algorithm versions, + // because we can have a corrupt archive with one algorithm file + // followed by another algorithm file with "solid" flag and we do not + // want to reuse tables from one algorithm in another. + private bool TablesRead2, TablesRead5; - private readonly byte[] UnpOldTable = new byte[HUFF_TABLE_SIZE30]; - private int UnpBlockType; + // Virtual machine to execute filters code. + /*#if !RarV2017_RAR5ONLY + RarVM VM; + #endif*/ - // If we already read decoding tables for Unpack v2,v3,v5. - // We should not use a single variable for all algorithm versions, - // because we can have a corrupt archive with one algorithm file - // followed by another algorithm file with "solid" flag and we do not - // want to reuse tables from one algorithm in another. - private bool TablesRead2, TablesRead3, TablesRead5; + // Buffer to read VM filters code. We moved it here from AddVMCode + // function to reduce time spent in BitInput constructor. + private readonly BitInput VMCodeInp = new BitInput(true); - // Virtual machine to execute filters code. - /*#if !RarV2017_RAR5ONLY - RarVM VM; - #endif*/ + // Filters code, one entry per filter. + private readonly List Filters30 = new List(); - // Buffer to read VM filters code. We moved it here from AddVMCode - // function to reduce time spent in BitInput constructor. - private readonly BitInput VMCodeInp = new BitInput(true); + // Filters stack, several entrances of same filter are possible. + private readonly List PrgStack = new List(); - // Filters code, one entry per filter. - private readonly List Filters30 = new List(); - - // Filters stack, several entrances of same filter are possible. - private readonly List PrgStack = new List(); - - // Lengths of preceding data blocks, one length of one last block - // for every filter. Used to reduce the size required to write - // the data block length if lengths are repeating. - private readonly List OldFilterLengths = new List(); - - private int LastFilter; - /***************************** Unpack v 3.0 *********************************/ - - //Unpack(ComprDataIO *DataIO); - //~Unpack(); - //void Init(size_t WinSize,bool Solid); - //void DoUnpack(uint Method,bool Solid); - private bool IsFileExtracted() { return (FileExtracted); } - private void SetDestSize(int64 DestSize) { DestUnpSize = DestSize; FileExtracted = false; } - private void SetSuspended(bool Suspended) { this.Suspended = Suspended; } + // Lengths of preceding data blocks, one length of one last block + // for every filter. Used to reduce the size required to write + // the data block length if lengths are repeating. + private readonly List OldFilterLengths = new List(); #if RarV2017_RAR_SMP - // More than 8 threads are unlikely to provide a noticeable gain - // for unpacking, but would use the additional memory. - void SetThreads(uint Threads) {MaxUserThreads=Min(Threads,8);} +// More than 8 threads are unlikely to provide a noticeable gain +// for unpacking, but would use the additional memory. +void SetThreads(uint Threads) {MaxUserThreads=Min(Threads,8);} - void UnpackDecode(UnpackThreadData &D); +void UnpackDecode(UnpackThreadData &D); #endif - private size_t MaxWinSize; - private size_t MaxWinMask; - - private uint GetChar() - { - if (Inp.InAddr > MAX_SIZE - 30) - { - UnpReadBuf(); - } - - return (Inp.InBuf[Inp.InAddr++]); - } - - - } + private size_t MaxWinSize; + private size_t MaxWinMask; } diff --git a/src/SharpCompress/Compressors/Rar/VM/BitInput.cs b/src/SharpCompress/Compressors/Rar/VM/BitInput.cs index b90d40d8..39bbcc3f 100644 --- a/src/SharpCompress/Compressors/Rar/VM/BitInput.cs +++ b/src/SharpCompress/Compressors/Rar/VM/BitInput.cs @@ -1,105 +1,104 @@ -namespace SharpCompress.Compressors.Rar.VM +namespace SharpCompress.Compressors.Rar.VM; + +internal class BitInput { - internal class BitInput + /// the max size of the input + internal const int MAX_SIZE = 0x8000; + + public int inAddr; + public int inBit; + + // TODO: rename var + public int InAddr { - /// the max size of the input - internal const int MAX_SIZE = 0x8000; + get { return inAddr; } + set { inAddr = value; } + } + public int InBit + { + get { return inBit; } + set { inBit = value; } + } + public bool ExternalBuffer; - public int inAddr; - public int inBit; + /// + internal BitInput() + { + InBuf = new byte[MAX_SIZE]; + } - // TODO: rename var - public int InAddr - { - get { return inAddr; } - set { inAddr = value; } - } - public int InBit - { - get { return inBit; } - set { inBit = value; } - } - public bool ExternalBuffer; + internal byte[] InBuf { get; } - /// - internal BitInput() - { - InBuf = new byte[MAX_SIZE]; - } + internal void InitBitInput() + { + inAddr = 0; + inBit = 0; + } - internal byte[] InBuf { get; } + internal void faddbits(uint bits) + { + // TODO uint + AddBits((int)bits); + } - internal void InitBitInput() - { - inAddr = 0; - inBit = 0; - } + /// + /// also named faddbits + /// + /// + internal void AddBits(int bits) + { + bits += inBit; + inAddr += (bits >> 3); + inBit = bits & 7; + } - internal void faddbits(uint bits) - { - // TODO uint - AddBits((int)bits); - } + internal uint fgetbits() + { + // TODO uint + return (uint)GetBits(); + } - /// - /// also named faddbits - /// - /// - internal void AddBits(int bits) - { - bits += inBit; - inAddr += (bits >> 3); - inBit = bits & 7; - } + internal uint getbits() + { + // TODO uint + return (uint)GetBits(); + } - internal uint fgetbits() - { - // TODO uint - return (uint)GetBits(); - } + /// + /// (also named fgetbits) + /// + /// + /// the bits (unsigned short) + /// + internal int GetBits() + { + // int BitField=0; + // BitField|=(int)(inBuf[inAddr] << 16)&0xFF0000; + // BitField|=(int)(inBuf[inAddr+1] << 8)&0xff00; + // BitField|=(int)(inBuf[inAddr+2])&0xFF; + // BitField >>>= (8-inBit); + // return (BitField & 0xffff); + return ( + ( + Utility.URShift( + ( + ((InBuf[inAddr] & 0xff) << 16) + + ((InBuf[inAddr + 1] & 0xff) << 8) + + ((InBuf[inAddr + 2] & 0xff)) + ), + (8 - inBit) + ) + ) & 0xffff + ); + } - internal uint getbits() - { - // TODO uint - return (uint)GetBits(); - } - - /// - /// (also named fgetbits) - /// - /// - /// the bits (unsigned short) - /// - internal int GetBits() - { - // int BitField=0; - // BitField|=(int)(inBuf[inAddr] << 16)&0xFF0000; - // BitField|=(int)(inBuf[inAddr+1] << 8)&0xff00; - // BitField|=(int)(inBuf[inAddr+2])&0xFF; - // BitField >>>= (8-inBit); - // return (BitField & 0xffff); - return ( - ( - Utility.URShift( - ( - ((InBuf[inAddr] & 0xff) << 16) - + ((InBuf[inAddr + 1] & 0xff) << 8) - + ((InBuf[inAddr + 2] & 0xff)) - ), - (8 - inBit) - ) - ) & 0xffff - ); - } - - /// Indicates an Overfow - /// how many bytes to inc - /// - /// true if an Oververflow would occur - /// - internal bool Overflow(int IncPtr) - { - return (inAddr + IncPtr >= MAX_SIZE); - } + /// Indicates an Overfow + /// how many bytes to inc + /// + /// true if an Oververflow would occur + /// + internal bool Overflow(int IncPtr) + { + return (inAddr + IncPtr >= MAX_SIZE); } } diff --git a/src/SharpCompress/Compressors/Rar/VM/RarVM.cs b/src/SharpCompress/Compressors/Rar/VM/RarVM.cs index 3ab8e2ca..612f56ff 100644 --- a/src/SharpCompress/Compressors/Rar/VM/RarVM.cs +++ b/src/SharpCompress/Compressors/Rar/VM/RarVM.cs @@ -4,1612 +4,1608 @@ using System; using System.Buffers.Binary; using System.Collections.Generic; -namespace SharpCompress.Compressors.Rar.VM +namespace SharpCompress.Compressors.Rar.VM; + +internal sealed class RarVM : BitInput { - internal sealed class RarVM : BitInput + //private void InitBlock() + //{ + // Mem.set_Renamed(offset + 0, Byte.valueOf((sbyte) (value_Renamed & 0xff))); + // Mem.set_Renamed(offset + 1, Byte.valueOf((sbyte) ((Utility.URShift(value_Renamed, 8)) & 0xff))); + // Mem.set_Renamed(offset + 2, Byte.valueOf((sbyte) ((Utility.URShift(value_Renamed, 16)) & 0xff))); + // Mem.set_Renamed(offset + 3, Byte.valueOf((sbyte) ((Utility.URShift(value_Renamed, 24)) & 0xff))); + + //} + internal byte[] Mem { get; private set; } + + public const int VM_MEMSIZE = 0x40000; + + //UPGRADE_NOTE: Final was removed from the declaration of 'VM_MEMMASK '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + public static readonly int VM_MEMMASK = (VM_MEMSIZE - 1); + + public const int VM_GLOBALMEMADDR = 0x3C000; + + public const int VM_GLOBALMEMSIZE = 0x2000; + + public const int VM_FIXEDGLOBALSIZE = 64; + + private const int regCount = 8; + private readonly int[] R = new int[regCount]; + + private VMFlags flags; + + private int maxOpCount = 25000000; + + private int codeSize; + + private int IP; + + internal RarVM() { - //private void InitBlock() - //{ - // Mem.set_Renamed(offset + 0, Byte.valueOf((sbyte) (value_Renamed & 0xff))); - // Mem.set_Renamed(offset + 1, Byte.valueOf((sbyte) ((Utility.URShift(value_Renamed, 8)) & 0xff))); - // Mem.set_Renamed(offset + 2, Byte.valueOf((sbyte) ((Utility.URShift(value_Renamed, 16)) & 0xff))); - // Mem.set_Renamed(offset + 3, Byte.valueOf((sbyte) ((Utility.URShift(value_Renamed, 24)) & 0xff))); + //InitBlock(); + Mem = null; + } - //} - internal byte[] Mem { get; private set; } + internal void init() + { + Mem ??= new byte[VM_MEMSIZE + 4]; + } - public const int VM_MEMSIZE = 0x40000; + private bool IsVMMem(byte[] mem) + { + return Mem == mem; + } - //UPGRADE_NOTE: Final was removed from the declaration of 'VM_MEMMASK '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly int VM_MEMMASK = (VM_MEMSIZE - 1); - - public const int VM_GLOBALMEMADDR = 0x3C000; - - public const int VM_GLOBALMEMSIZE = 0x2000; - - public const int VM_FIXEDGLOBALSIZE = 64; - - private const int regCount = 8; - - private const long UINT_MASK = 0xffffFFFF; //((long)2*(long)Integer.MAX_VALUE); - - private readonly int[] R = new int[regCount]; - - private VMFlags flags; - - private int maxOpCount = 25000000; - - private int codeSize; - - private int IP; - - internal RarVM() + private int GetValue(bool byteMode, byte[] mem, int offset) + { + if (byteMode) { - //InitBlock(); - Mem = null; - } - - internal void init() - { - Mem ??= new byte[VM_MEMSIZE + 4]; - } - - private bool IsVMMem(byte[] mem) - { - return Mem == mem; - } - - private int GetValue(bool byteMode, byte[] mem, int offset) - { - if (byteMode) - { - if (IsVMMem(mem)) - { - return (mem[offset]); - } - return (mem[offset] & 0xff); - } if (IsVMMem(mem)) { - return BinaryPrimitives.ReadInt32LittleEndian(mem.AsSpan(offset)); + return (mem[offset]); } - return BinaryPrimitives.ReadInt32BigEndian(mem.AsSpan(offset)); + return (mem[offset] & 0xff); } - - private void SetValue(bool byteMode, byte[] mem, int offset, int value) + if (IsVMMem(mem)) { - if (byteMode) + return BinaryPrimitives.ReadInt32LittleEndian(mem.AsSpan(offset)); + } + return BinaryPrimitives.ReadInt32BigEndian(mem.AsSpan(offset)); + } + + private void SetValue(bool byteMode, byte[] mem, int offset, int value) + { + if (byteMode) + { + if (IsVMMem(mem)) { - if (IsVMMem(mem)) - { - mem[offset] = (byte)value; - } - else - { - mem[offset] = (byte)((mem[offset] & 0x00) | (byte)(value & 0xff)); - } + mem[offset] = (byte)value; } else { - if (IsVMMem(mem)) - { - BinaryPrimitives.WriteInt32LittleEndian(mem.AsSpan(offset), value); - } - else - { - BinaryPrimitives.WriteInt32BigEndian(mem.AsSpan(offset), value); - } + mem[offset] = (byte)((mem[offset] & 0x00) | (byte)(value & 0xff)); } - - // #define SET_VALUE(ByteMode,Addr,Value) SetValue(ByteMode,(uint - // *)Addr,Value) } - - internal void SetLowEndianValue(List mem, int offset, int value) + else { - mem[offset + 0] = (byte)(value & 0xff); - mem[offset + 1] = (byte)(Utility.URShift(value, 8) & 0xff); - mem[offset + 2] = (byte)(Utility.URShift(value, 16) & 0xff); - mem[offset + 3] = (byte)(Utility.URShift(value, 24) & 0xff); - } - - private int GetOperand(VMPreparedOperand cmdOp) - { - int ret = 0; - if (cmdOp.Type == VMOpType.VM_OPREGMEM) + if (IsVMMem(mem)) { - int pos = (cmdOp.Offset + cmdOp.Base) & VM_MEMMASK; - ret = BinaryPrimitives.ReadInt32LittleEndian(Mem.AsSpan(pos)); + BinaryPrimitives.WriteInt32LittleEndian(mem.AsSpan(offset), value); } else { - int pos = cmdOp.Offset; - ret = BinaryPrimitives.ReadInt32LittleEndian(Mem.AsSpan(pos)); - } - return ret; - } - - public void execute(VMPreparedProgram prg) - { - for (int i = 0; i < prg.InitR.Length; i++) - // memcpy(R,Prg->InitR,sizeof(Prg->InitR)); - { - R[i] = prg.InitR[i]; - } - - long globalSize = Math.Min(prg.GlobalData.Count, VM_GLOBALMEMSIZE) & 0xffFFffFF; - if (globalSize != 0) - { - for (int i = 0; i < globalSize; i++) - // memcpy(Mem+VM_GLOBALMEMADDR,&Prg->GlobalData[0],GlobalSize); - { - Mem[VM_GLOBALMEMADDR + i] = prg.GlobalData[i]; - } - } - long staticSize = - Math.Min(prg.StaticData.Count, VM_GLOBALMEMSIZE - globalSize) & 0xffFFffFF; - if (staticSize != 0) - { - for (int i = 0; i < staticSize; i++) - // memcpy(Mem+VM_GLOBALMEMADDR+GlobalSize,&Prg->StaticData[0],StaticSize); - { - Mem[VM_GLOBALMEMADDR + (int)globalSize + i] = prg.StaticData[i]; - } - } - R[7] = VM_MEMSIZE; - flags = 0; - - //UPGRADE_NOTE: There is an untranslated Statement. Please refer to original code. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1153'" - List preparedCode = - prg.AltCommands.Count != 0 ? prg.AltCommands : prg.Commands; - - if (!ExecuteCode(preparedCode, prg.CommandCount)) - { - preparedCode[0].OpCode = VMCommands.VM_RET; - } - int newBlockPos = GetValue(false, Mem, VM_GLOBALMEMADDR + 0x20) & VM_MEMMASK; - int newBlockSize = GetValue(false, Mem, VM_GLOBALMEMADDR + 0x1c) & VM_MEMMASK; - if ((newBlockPos + newBlockSize) >= VM_MEMSIZE) - { - newBlockPos = 0; - newBlockSize = 0; - } - - prg.FilteredDataOffset = newBlockPos; - prg.FilteredDataSize = newBlockSize; - - prg.GlobalData.Clear(); - - int dataSize = Math.Min( - GetValue(false, Mem, VM_GLOBALMEMADDR + 0x30), - VM_GLOBALMEMSIZE - VM_FIXEDGLOBALSIZE - ); - if (dataSize != 0) - { - //prg.GlobalData.Clear(); - // ->GlobalData.Add(dataSize+VM_FIXEDGLOBALSIZE); - prg.GlobalData.Capacity = dataSize + VM_FIXEDGLOBALSIZE; - for (int i = 0; i < dataSize + VM_FIXEDGLOBALSIZE; i++) - // memcpy(&Prg->GlobalData[0],&Mem[VM_GLOBALMEMADDR],DataSize+VM_FIXEDGLOBALSIZE); - { - prg.GlobalData.Add(Mem[VM_GLOBALMEMADDR + i]); - } + BinaryPrimitives.WriteInt32BigEndian(mem.AsSpan(offset), value); } } - private bool setIP(int ip) + // #define SET_VALUE(ByteMode,Addr,Value) SetValue(ByteMode,(uint + // *)Addr,Value) + } + + internal void SetLowEndianValue(List mem, int offset, int value) + { + mem[offset + 0] = (byte)(value & 0xff); + mem[offset + 1] = (byte)(Utility.URShift(value, 8) & 0xff); + mem[offset + 2] = (byte)(Utility.URShift(value, 16) & 0xff); + mem[offset + 3] = (byte)(Utility.URShift(value, 24) & 0xff); + } + + private int GetOperand(VMPreparedOperand cmdOp) + { + var ret = 0; + if (cmdOp.Type == VMOpType.VM_OPREGMEM) { - if ((ip) >= codeSize) - { - return (true); - } + var pos = (cmdOp.Offset + cmdOp.Base) & VM_MEMMASK; + ret = BinaryPrimitives.ReadInt32LittleEndian(Mem.AsSpan(pos)); + } + else + { + var pos = cmdOp.Offset; + ret = BinaryPrimitives.ReadInt32LittleEndian(Mem.AsSpan(pos)); + } + return ret; + } - if (--maxOpCount <= 0) - { - return (false); - } - - IP = ip; - return true; + public void execute(VMPreparedProgram prg) + { + for (var i = 0; i < prg.InitR.Length; i++) + // memcpy(R,Prg->InitR,sizeof(Prg->InitR)); + { + R[i] = prg.InitR[i]; } - private bool ExecuteCode(List preparedCode, int cmdCount) + var globalSize = Math.Min(prg.GlobalData.Count, VM_GLOBALMEMSIZE) & 0xffFFffFF; + if (globalSize != 0) { - maxOpCount = 25000000; - codeSize = cmdCount; - IP = 0; - - while (true) + for (var i = 0; i < globalSize; i++) + // memcpy(Mem+VM_GLOBALMEMADDR,&Prg->GlobalData[0],GlobalSize); { - VMPreparedCommand cmd = preparedCode[IP]; - int op1 = GetOperand(cmd.Op1); - int op2 = GetOperand(cmd.Op2); - switch (cmd.OpCode) - { - case VMCommands.VM_MOV: - SetValue(cmd.IsByteMode, Mem, op1, GetValue(cmd.IsByteMode, Mem, op2)); - - // SET_VALUE(Cmd->ByteMode,Op1,GET_VALUE(Cmd->ByteMode,Op2)); - break; - - case VMCommands.VM_MOVB: - SetValue(true, Mem, op1, GetValue(true, Mem, op2)); - break; - - case VMCommands.VM_MOVD: - SetValue(false, Mem, op1, GetValue(false, Mem, op2)); - break; - - case VMCommands.VM_CMP: - - { - VMFlags value1 = (VMFlags)GetValue(cmd.IsByteMode, Mem, op1); - VMFlags result = value1 - GetValue(cmd.IsByteMode, Mem, op2); - - if (result == 0) - { - flags = VMFlags.VM_FZ; - } - else - { - flags = (VMFlags)( - (result > value1) ? 1 : 0 | (int)(result & VMFlags.VM_FS) - ); - } - } - break; - - case VMCommands.VM_CMPB: - - { - VMFlags value1 = (VMFlags)GetValue(true, Mem, op1); - VMFlags result = value1 - GetValue(true, Mem, op2); - if (result == 0) - { - flags = VMFlags.VM_FZ; - } - else - { - flags = (VMFlags)( - (result > value1) ? 1 : 0 | (int)(result & VMFlags.VM_FS) - ); - } - } - break; - - case VMCommands.VM_CMPD: - - { - VMFlags value1 = (VMFlags)GetValue(false, Mem, op1); - VMFlags result = value1 - GetValue(false, Mem, op2); - if (result == 0) - { - flags = VMFlags.VM_FZ; - } - else - { - flags = (VMFlags)( - (result > value1) ? 1 : 0 | (int)(result & VMFlags.VM_FS) - ); - } - } - break; - - case VMCommands.VM_ADD: - - { - int value1 = GetValue(cmd.IsByteMode, Mem, op1); - int result = (int)( - ((value1 + (long)GetValue(cmd.IsByteMode, Mem, op2))) - & unchecked((int)0xffffffff) - ); - if (cmd.IsByteMode) - { - result &= 0xff; - flags = (VMFlags)( - (result < value1) - ? 1 - : 0 - | ( - result == 0 - ? (int)VMFlags.VM_FZ - : ( - ((result & 0x80) != 0) - ? (int)VMFlags.VM_FS - : 0 - ) - ) - ); - - // Flags=(Result value1) ? 1 : 0 | (result & (int)VMFlags.VM_FS)) - ); - SetValue(cmd.IsByteMode, Mem, op1, result); // (Cmd->ByteMode,Op1,Result); - } - break; - - case VMCommands.VM_SUBB: - SetValue( - true, - Mem, - op1, - (int)( - GetValue(true, Mem, op1) - & 0xFFffFFff - GetValue(true, Mem, op2) - & unchecked((int)0xFFffFFff) - ) - ); - break; - - case VMCommands.VM_SUBD: - SetValue( - false, - Mem, - op1, - (int)( - GetValue(false, Mem, op1) - & 0xFFffFFff - GetValue(false, Mem, op2) - & unchecked((int)0xFFffFFff) - ) - ); - break; - - case VMCommands.VM_JZ: - if ((flags & VMFlags.VM_FZ) != 0) - { - setIP(GetValue(false, Mem, op1)); - continue; - } - break; - - case VMCommands.VM_JNZ: - if ((flags & VMFlags.VM_FZ) == 0) - { - setIP(GetValue(false, Mem, op1)); - continue; - } - break; - - case VMCommands.VM_INC: - - { - int result = (int)( - GetValue(cmd.IsByteMode, Mem, op1) & 0xFFffFFffL + 1L - ); - if (cmd.IsByteMode) - { - result &= 0xff; - } - - SetValue(cmd.IsByteMode, Mem, op1, result); - flags = (VMFlags)( - result == 0 ? (int)VMFlags.VM_FZ : result & (int)VMFlags.VM_FS - ); - } - break; - - case VMCommands.VM_INCB: - SetValue( - true, - Mem, - op1, - (int)(GetValue(true, Mem, op1) & 0xFFffFFffL + 1L) - ); - break; - - case VMCommands.VM_INCD: - SetValue( - false, - Mem, - op1, - (int)(GetValue(false, Mem, op1) & 0xFFffFFffL + 1L) - ); - break; - - case VMCommands.VM_DEC: - - { - int result = (int)(GetValue(cmd.IsByteMode, Mem, op1) & 0xFFffFFff - 1); - SetValue(cmd.IsByteMode, Mem, op1, result); - flags = (VMFlags)( - result == 0 ? (int)VMFlags.VM_FZ : result & (int)VMFlags.VM_FS - ); - } - break; - - case VMCommands.VM_DECB: - SetValue(true, Mem, op1, (int)(GetValue(true, Mem, op1) & 0xFFffFFff - 1)); - break; - - case VMCommands.VM_DECD: - SetValue( - false, - Mem, - op1, - (int)(GetValue(false, Mem, op1) & 0xFFffFFff - 1) - ); - break; - - case VMCommands.VM_JMP: - setIP(GetValue(false, Mem, op1)); - continue; - - case VMCommands.VM_XOR: - - { - int result = - GetValue(cmd.IsByteMode, Mem, op1) - ^ GetValue(cmd.IsByteMode, Mem, op2); - flags = (VMFlags)( - result == 0 ? (int)VMFlags.VM_FZ : result & (int)VMFlags.VM_FS - ); - SetValue(cmd.IsByteMode, Mem, op1, result); - } - break; - - case VMCommands.VM_AND: - - { - int result = - GetValue(cmd.IsByteMode, Mem, op1) - & GetValue(cmd.IsByteMode, Mem, op2); - flags = (VMFlags)( - result == 0 ? (int)VMFlags.VM_FZ : result & (int)VMFlags.VM_FS - ); - SetValue(cmd.IsByteMode, Mem, op1, result); - } - break; - - case VMCommands.VM_OR: - - { - int result = - GetValue(cmd.IsByteMode, Mem, op1) - | GetValue(cmd.IsByteMode, Mem, op2); - flags = (VMFlags)( - result == 0 ? (int)VMFlags.VM_FZ : result & (int)VMFlags.VM_FS - ); - SetValue(cmd.IsByteMode, Mem, op1, result); - } - break; - - case VMCommands.VM_TEST: - - { - int result = - GetValue(cmd.IsByteMode, Mem, op1) - & GetValue(cmd.IsByteMode, Mem, op2); - flags = (VMFlags)( - result == 0 ? (int)VMFlags.VM_FZ : result & (int)VMFlags.VM_FS - ); - } - break; - - case VMCommands.VM_JS: - if ((flags & VMFlags.VM_FS) != 0) - { - setIP(GetValue(false, Mem, op1)); - continue; - } - break; - - case VMCommands.VM_JNS: - if ((flags & VMFlags.VM_FS) == 0) - { - setIP(GetValue(false, Mem, op1)); - continue; - } - break; - - case VMCommands.VM_JB: - if ((flags & VMFlags.VM_FC) != 0) - { - setIP(GetValue(false, Mem, op1)); - continue; - } - break; - - case VMCommands.VM_JBE: - if ((flags & (VMFlags.VM_FC | VMFlags.VM_FZ)) != 0) - { - setIP(GetValue(false, Mem, op1)); - continue; - } - break; - - case VMCommands.VM_JA: - if ((flags & (VMFlags.VM_FC | VMFlags.VM_FZ)) == 0) - { - setIP(GetValue(false, Mem, op1)); - continue; - } - break; - - case VMCommands.VM_JAE: - if ((flags & VMFlags.VM_FC) == 0) - { - setIP(GetValue(false, Mem, op1)); - continue; - } - break; - - case VMCommands.VM_PUSH: - R[7] -= 4; - SetValue(false, Mem, R[7] & VM_MEMMASK, GetValue(false, Mem, op1)); - break; - - case VMCommands.VM_POP: - SetValue(false, Mem, op1, GetValue(false, Mem, R[7] & VM_MEMMASK)); - R[7] += 4; - break; - - case VMCommands.VM_CALL: - R[7] -= 4; - SetValue(false, Mem, R[7] & VM_MEMMASK, IP + 1); - setIP(GetValue(false, Mem, op1)); - continue; - - case VMCommands.VM_NOT: - SetValue(cmd.IsByteMode, Mem, op1, ~GetValue(cmd.IsByteMode, Mem, op1)); - break; - - case VMCommands.VM_SHL: - - { - int value1 = GetValue(cmd.IsByteMode, Mem, op1); - int value2 = GetValue(cmd.IsByteMode, Mem, op2); - int result = value1 << value2; - flags = (VMFlags)( - (result == 0 ? (int)VMFlags.VM_FZ : (result & (int)VMFlags.VM_FS)) - | ( - ((value1 << (value2 - 1)) & unchecked((int)0x80000000)) != 0 - ? (int)VMFlags.VM_FC - : 0 - ) - ); - SetValue(cmd.IsByteMode, Mem, op1, result); - } - break; - - case VMCommands.VM_SHR: - - { - int value1 = GetValue(cmd.IsByteMode, Mem, op1); - int value2 = GetValue(cmd.IsByteMode, Mem, op2); - int result = Utility.URShift(value1, value2); - flags = (VMFlags)( - (result == 0 ? (int)VMFlags.VM_FZ : (result & (int)VMFlags.VM_FS)) - | ((Utility.URShift(value1, (value2 - 1))) & (int)VMFlags.VM_FC) - ); - SetValue(cmd.IsByteMode, Mem, op1, result); - } - break; - - case VMCommands.VM_SAR: - - { - int value1 = GetValue(cmd.IsByteMode, Mem, op1); - int value2 = GetValue(cmd.IsByteMode, Mem, op2); - int result = value1 >> value2; - flags = (VMFlags)( - (result == 0 ? (int)VMFlags.VM_FZ : (result & (int)VMFlags.VM_FS)) - | ((value1 >> (value2 - 1)) & (int)VMFlags.VM_FC) - ); - SetValue(cmd.IsByteMode, Mem, op1, result); - } - break; - - case VMCommands.VM_NEG: - - { - int result = -GetValue(cmd.IsByteMode, Mem, op1); - flags = (VMFlags)( - result == 0 - ? (int)VMFlags.VM_FZ - : (int)VMFlags.VM_FC | (result & (int)VMFlags.VM_FS) - ); - SetValue(cmd.IsByteMode, Mem, op1, result); - } - break; - - case VMCommands.VM_NEGB: - SetValue(true, Mem, op1, -GetValue(true, Mem, op1)); - break; - - case VMCommands.VM_NEGD: - SetValue(false, Mem, op1, -GetValue(false, Mem, op1)); - break; - - case VMCommands.VM_PUSHA: - - { - for (int i = 0, SP = R[7] - 4; i < regCount; i++, SP -= 4) - { - SetValue(false, Mem, SP & VM_MEMMASK, R[i]); - } - R[7] -= regCount * 4; - } - break; - - case VMCommands.VM_POPA: - - { - for (int i = 0, SP = R[7]; i < regCount; i++, SP += 4) - { - R[7 - i] = GetValue(false, Mem, SP & VM_MEMMASK); - } - } - break; - - case VMCommands.VM_PUSHF: - R[7] -= 4; - SetValue(false, Mem, R[7] & VM_MEMMASK, (int)flags); - break; - - case VMCommands.VM_POPF: - flags = (VMFlags)GetValue(false, Mem, R[7] & VM_MEMMASK); - R[7] += 4; - break; - - case VMCommands.VM_MOVZX: - SetValue(false, Mem, op1, GetValue(true, Mem, op2)); - break; - - case VMCommands.VM_MOVSX: - SetValue(false, Mem, op1, (byte)GetValue(true, Mem, op2)); - break; - - case VMCommands.VM_XCHG: - - { - int value1 = GetValue(cmd.IsByteMode, Mem, op1); - SetValue(cmd.IsByteMode, Mem, op1, GetValue(cmd.IsByteMode, Mem, op2)); - SetValue(cmd.IsByteMode, Mem, op2, value1); - } - break; - - case VMCommands.VM_MUL: - - { - int result = (int)( - ( - GetValue(cmd.IsByteMode, Mem, op1) - & 0xFFffFFff * GetValue(cmd.IsByteMode, Mem, op2) - & unchecked((int)0xFFffFFff) - ) & unchecked((int)0xFFffFFff) - ); - SetValue(cmd.IsByteMode, Mem, op1, result); - } - break; - - case VMCommands.VM_DIV: - - { - int divider = GetValue(cmd.IsByteMode, Mem, op2); - if (divider != 0) - { - int result = GetValue(cmd.IsByteMode, Mem, op1) / divider; - SetValue(cmd.IsByteMode, Mem, op1, result); - } - } - break; - - case VMCommands.VM_ADC: - - { - int value1 = GetValue(cmd.IsByteMode, Mem, op1); - int FC = (int)(flags & VMFlags.VM_FC); - int result = (int)( - value1 - & 0xFFffFFff + GetValue(cmd.IsByteMode, Mem, op2) - & 0xFFffFFff + FC - & unchecked((int)0xFFffFFff) - ); - if (cmd.IsByteMode) - { - result &= 0xff; - } - - flags = (VMFlags)( - (result < value1 || result == value1 && FC != 0) - ? 1 - : 0 - | ( - result == 0 - ? (int)VMFlags.VM_FZ - : (result & (int)VMFlags.VM_FS) - ) - ); - SetValue(cmd.IsByteMode, Mem, op1, result); - } - break; - - case VMCommands.VM_SBB: - - { - int value1 = GetValue(cmd.IsByteMode, Mem, op1); - int FC = (int)(flags & VMFlags.VM_FC); - int result = (int)( - value1 - & 0xFFffFFff - GetValue(cmd.IsByteMode, Mem, op2) - & 0xFFffFFff - FC - & unchecked((int)0xFFffFFff) - ); - if (cmd.IsByteMode) - { - result &= 0xff; - } - flags = (VMFlags)( - (result > value1 || result == value1 && FC != 0) - ? 1 - : 0 - | ( - result == 0 - ? (int)VMFlags.VM_FZ - : (result & (int)VMFlags.VM_FS) - ) - ); - SetValue(cmd.IsByteMode, Mem, op1, result); - } - break; - - case VMCommands.VM_RET: - if (R[7] >= VM_MEMSIZE) - { - return (true); - } - setIP(GetValue(false, Mem, R[7] & VM_MEMMASK)); - R[7] += 4; - continue; - - case VMCommands.VM_STANDARD: - ExecuteStandardFilter((VMStandardFilters)(cmd.Op1.Data)); - break; - - case VMCommands.VM_PRINT: - break; - } - IP++; - --maxOpCount; + Mem[VM_GLOBALMEMADDR + i] = prg.GlobalData[i]; } } - - public void prepare(byte[] code, int codeSize, VMPreparedProgram prg) + var staticSize = + Math.Min(prg.StaticData.Count, VM_GLOBALMEMSIZE - globalSize) & 0xffFFffFF; + if (staticSize != 0) { - InitBitInput(); - int cpLength = Math.Min(MAX_SIZE, codeSize); - - // memcpy(inBuf,Code,Min(CodeSize,BitInput::MAX_SIZE)); - - Buffer.BlockCopy(code, 0, InBuf, 0, cpLength); - byte xorSum = 0; - for (int i = 1; i < codeSize; i++) + for (var i = 0; i < staticSize; i++) + // memcpy(Mem+VM_GLOBALMEMADDR+GlobalSize,&Prg->StaticData[0],StaticSize); { - xorSum ^= code[i]; + Mem[VM_GLOBALMEMADDR + (int)globalSize + i] = prg.StaticData[i]; } + } + R[7] = VM_MEMSIZE; + flags = 0; - AddBits(8); + //UPGRADE_NOTE: There is an untranslated Statement. Please refer to original code. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1153'" + var preparedCode = + prg.AltCommands.Count != 0 ? prg.AltCommands : prg.Commands; - prg.CommandCount = 0; - if (xorSum == code[0]) + if (!ExecuteCode(preparedCode, prg.CommandCount)) + { + preparedCode[0].OpCode = VMCommands.VM_RET; + } + var newBlockPos = GetValue(false, Mem, VM_GLOBALMEMADDR + 0x20) & VM_MEMMASK; + var newBlockSize = GetValue(false, Mem, VM_GLOBALMEMADDR + 0x1c) & VM_MEMMASK; + if ((newBlockPos + newBlockSize) >= VM_MEMSIZE) + { + newBlockPos = 0; + newBlockSize = 0; + } + + prg.FilteredDataOffset = newBlockPos; + prg.FilteredDataSize = newBlockSize; + + prg.GlobalData.Clear(); + + var dataSize = Math.Min( + GetValue(false, Mem, VM_GLOBALMEMADDR + 0x30), + VM_GLOBALMEMSIZE - VM_FIXEDGLOBALSIZE + ); + if (dataSize != 0) + { + //prg.GlobalData.Clear(); + // ->GlobalData.Add(dataSize+VM_FIXEDGLOBALSIZE); + prg.GlobalData.Capacity = dataSize + VM_FIXEDGLOBALSIZE; + for (var i = 0; i < dataSize + VM_FIXEDGLOBALSIZE; i++) + // memcpy(&Prg->GlobalData[0],&Mem[VM_GLOBALMEMADDR],DataSize+VM_FIXEDGLOBALSIZE); { - VMStandardFilters filterType = IsStandardFilter(code, codeSize); - if (filterType != VMStandardFilters.VMSF_NONE) + prg.GlobalData.Add(Mem[VM_GLOBALMEMADDR + i]); + } + } + } + + private bool setIP(int ip) + { + if ((ip) >= codeSize) + { + return (true); + } + + if (--maxOpCount <= 0) + { + return (false); + } + + IP = ip; + return true; + } + + private bool ExecuteCode(List preparedCode, int cmdCount) + { + maxOpCount = 25000000; + codeSize = cmdCount; + IP = 0; + + while (true) + { + var cmd = preparedCode[IP]; + var op1 = GetOperand(cmd.Op1); + var op2 = GetOperand(cmd.Op2); + switch (cmd.OpCode) + { + case VMCommands.VM_MOV: + SetValue(cmd.IsByteMode, Mem, op1, GetValue(cmd.IsByteMode, Mem, op2)); + + // SET_VALUE(Cmd->ByteMode,Op1,GET_VALUE(Cmd->ByteMode,Op2)); + break; + + case VMCommands.VM_MOVB: + SetValue(true, Mem, op1, GetValue(true, Mem, op2)); + break; + + case VMCommands.VM_MOVD: + SetValue(false, Mem, op1, GetValue(false, Mem, op2)); + break; + + case VMCommands.VM_CMP: + { - VMPreparedCommand curCmd = new VMPreparedCommand(); - curCmd.OpCode = VMCommands.VM_STANDARD; - curCmd.Op1.Data = (int)filterType; - curCmd.Op1.Type = VMOpType.VM_OPNONE; - curCmd.Op2.Type = VMOpType.VM_OPNONE; - codeSize = 0; - prg.Commands.Add(curCmd); - prg.CommandCount = prg.CommandCount + 1; + var value1 = (VMFlags)GetValue(cmd.IsByteMode, Mem, op1); + var result = value1 - GetValue(cmd.IsByteMode, Mem, op2); - // TODO - // curCmd->Op1.Data=FilterType; - // >>>>>> CurCmd->Op1.Addr=&CurCmd->Op1.Data; <<<<<<<<<< not set - // do i need to ? - // >>>>>> CurCmd->Op2.Addr=&CurCmd->Op2.Data; <<<<<<<<<< " - // CurCmd->Op1.Type=CurCmd->Op2.Type=VM_OPNONE; - // CodeSize=0; - } - int dataFlag = GetBits(); - AddBits(1); - - // Read static data contained in DB operators. This data cannot be - // changed, - // it is a part of VM code, not a filter parameter. - - if ((dataFlag & 0x8000) != 0) - { - long dataSize = ReadData(this) & 0xffFFffFFL + 1L; - for (int i = 0; inAddr < codeSize && i < dataSize; i++) + if (result == 0) { - prg.StaticData.Add((byte)(GetBits() >> 8)); - AddBits(8); + flags = VMFlags.VM_FZ; + } + else + { + flags = (VMFlags)( + (result > value1) ? 1 : 0 | (int)(result & VMFlags.VM_FS) + ); } } + break; + + case VMCommands.VM_CMPB: - while (inAddr < codeSize) { - VMPreparedCommand curCmd = new VMPreparedCommand(); - int data = GetBits(); - if ((data & 0x8000) == 0) + var value1 = (VMFlags)GetValue(true, Mem, op1); + var result = value1 - GetValue(true, Mem, op2); + if (result == 0) { - curCmd.OpCode = (VMCommands)((data >> 12)); + flags = VMFlags.VM_FZ; + } + else + { + flags = (VMFlags)( + (result > value1) ? 1 : 0 | (int)(result & VMFlags.VM_FS) + ); + } + } + break; + + case VMCommands.VM_CMPD: + + { + var value1 = (VMFlags)GetValue(false, Mem, op1); + var result = value1 - GetValue(false, Mem, op2); + if (result == 0) + { + flags = VMFlags.VM_FZ; + } + else + { + flags = (VMFlags)( + (result > value1) ? 1 : 0 | (int)(result & VMFlags.VM_FS) + ); + } + } + break; + + case VMCommands.VM_ADD: + + { + var value1 = GetValue(cmd.IsByteMode, Mem, op1); + var result = (int)( + ((value1 + (long)GetValue(cmd.IsByteMode, Mem, op2))) + & unchecked((int)0xffffffff) + ); + if (cmd.IsByteMode) + { + result &= 0xff; + flags = (VMFlags)( + (result < value1) + ? 1 + : 0 + | ( + result == 0 + ? (int)VMFlags.VM_FZ + : ( + ((result & 0x80) != 0) + ? (int)VMFlags.VM_FS + : 0 + ) + ) + ); + + // Flags=(Result value1) ? 1 : 0 | (result & (int)VMFlags.VM_FS)) + ); + SetValue(cmd.IsByteMode, Mem, op1, result); // (Cmd->ByteMode,Op1,Result); + } + break; + + case VMCommands.VM_SUBB: + SetValue( + true, + Mem, + op1, + (int)( + GetValue(true, Mem, op1) + & (0xFFffFFff - GetValue(true, Mem, op2)) + & unchecked((int)0xFFffFFff) + ) + ); + break; + + case VMCommands.VM_SUBD: + SetValue( + false, + Mem, + op1, + (int)( + GetValue(false, Mem, op1) + & (0xFFffFFff - GetValue(false, Mem, op2)) + & unchecked((int)0xFFffFFff) + ) + ); + break; + + case VMCommands.VM_JZ: + if ((flags & VMFlags.VM_FZ) != 0) + { + setIP(GetValue(false, Mem, op1)); + continue; + } + break; + + case VMCommands.VM_JNZ: + if ((flags & VMFlags.VM_FZ) == 0) + { + setIP(GetValue(false, Mem, op1)); + continue; + } + break; + + case VMCommands.VM_INC: + + { + var result = (int)( + GetValue(cmd.IsByteMode, Mem, op1) & (0xFFffFFffL + 1L) + ); + if (cmd.IsByteMode) + { + result &= 0xff; + } + + SetValue(cmd.IsByteMode, Mem, op1, result); + flags = (VMFlags)( + result == 0 ? (int)VMFlags.VM_FZ : result & (int)VMFlags.VM_FS + ); + } + break; + + case VMCommands.VM_INCB: + SetValue( + true, + Mem, + op1, + (int)(GetValue(true, Mem, op1) & (0xFFffFFffL + 1L)) + ); + break; + + case VMCommands.VM_INCD: + SetValue( + false, + Mem, + op1, + (int)(GetValue(false, Mem, op1) & (0xFFffFFffL + 1L)) + ); + break; + + case VMCommands.VM_DEC: + + { + var result = (int)(GetValue(cmd.IsByteMode, Mem, op1) & (0xFFffFFff - 1)); + SetValue(cmd.IsByteMode, Mem, op1, result); + flags = (VMFlags)( + result == 0 ? (int)VMFlags.VM_FZ : result & (int)VMFlags.VM_FS + ); + } + break; + + case VMCommands.VM_DECB: + SetValue(true, Mem, op1, (int)(GetValue(true, Mem, op1) & (0xFFffFFff - 1))); + break; + + case VMCommands.VM_DECD: + SetValue( + false, + Mem, + op1, + (int)(GetValue(false, Mem, op1) & (0xFFffFFff - 1)) + ); + break; + + case VMCommands.VM_JMP: + setIP(GetValue(false, Mem, op1)); + continue; + + case VMCommands.VM_XOR: + + { + var result = + GetValue(cmd.IsByteMode, Mem, op1) + ^ GetValue(cmd.IsByteMode, Mem, op2); + flags = (VMFlags)( + result == 0 ? (int)VMFlags.VM_FZ : result & (int)VMFlags.VM_FS + ); + SetValue(cmd.IsByteMode, Mem, op1, result); + } + break; + + case VMCommands.VM_AND: + + { + var result = + GetValue(cmd.IsByteMode, Mem, op1) + & GetValue(cmd.IsByteMode, Mem, op2); + flags = (VMFlags)( + result == 0 ? (int)VMFlags.VM_FZ : result & (int)VMFlags.VM_FS + ); + SetValue(cmd.IsByteMode, Mem, op1, result); + } + break; + + case VMCommands.VM_OR: + + { + var result = + GetValue(cmd.IsByteMode, Mem, op1) + | GetValue(cmd.IsByteMode, Mem, op2); + flags = (VMFlags)( + result == 0 ? (int)VMFlags.VM_FZ : result & (int)VMFlags.VM_FS + ); + SetValue(cmd.IsByteMode, Mem, op1, result); + } + break; + + case VMCommands.VM_TEST: + + { + var result = + GetValue(cmd.IsByteMode, Mem, op1) + & GetValue(cmd.IsByteMode, Mem, op2); + flags = (VMFlags)( + result == 0 ? (int)VMFlags.VM_FZ : result & (int)VMFlags.VM_FS + ); + } + break; + + case VMCommands.VM_JS: + if ((flags & VMFlags.VM_FS) != 0) + { + setIP(GetValue(false, Mem, op1)); + continue; + } + break; + + case VMCommands.VM_JNS: + if ((flags & VMFlags.VM_FS) == 0) + { + setIP(GetValue(false, Mem, op1)); + continue; + } + break; + + case VMCommands.VM_JB: + if ((flags & VMFlags.VM_FC) != 0) + { + setIP(GetValue(false, Mem, op1)); + continue; + } + break; + + case VMCommands.VM_JBE: + if ((flags & (VMFlags.VM_FC | VMFlags.VM_FZ)) != 0) + { + setIP(GetValue(false, Mem, op1)); + continue; + } + break; + + case VMCommands.VM_JA: + if ((flags & (VMFlags.VM_FC | VMFlags.VM_FZ)) == 0) + { + setIP(GetValue(false, Mem, op1)); + continue; + } + break; + + case VMCommands.VM_JAE: + if ((flags & VMFlags.VM_FC) == 0) + { + setIP(GetValue(false, Mem, op1)); + continue; + } + break; + + case VMCommands.VM_PUSH: + R[7] -= 4; + SetValue(false, Mem, R[7] & VM_MEMMASK, GetValue(false, Mem, op1)); + break; + + case VMCommands.VM_POP: + SetValue(false, Mem, op1, GetValue(false, Mem, R[7] & VM_MEMMASK)); + R[7] += 4; + break; + + case VMCommands.VM_CALL: + R[7] -= 4; + SetValue(false, Mem, R[7] & VM_MEMMASK, IP + 1); + setIP(GetValue(false, Mem, op1)); + continue; + + case VMCommands.VM_NOT: + SetValue(cmd.IsByteMode, Mem, op1, ~GetValue(cmd.IsByteMode, Mem, op1)); + break; + + case VMCommands.VM_SHL: + + { + var value1 = GetValue(cmd.IsByteMode, Mem, op1); + var value2 = GetValue(cmd.IsByteMode, Mem, op2); + var result = value1 << value2; + flags = (VMFlags)( + (result == 0 ? (int)VMFlags.VM_FZ : (result & (int)VMFlags.VM_FS)) + | ( + ((value1 << (value2 - 1)) & unchecked((int)0x80000000)) != 0 + ? (int)VMFlags.VM_FC + : 0 + ) + ); + SetValue(cmd.IsByteMode, Mem, op1, result); + } + break; + + case VMCommands.VM_SHR: + + { + var value1 = GetValue(cmd.IsByteMode, Mem, op1); + var value2 = GetValue(cmd.IsByteMode, Mem, op2); + var result = Utility.URShift(value1, value2); + flags = (VMFlags)( + (result == 0 ? (int)VMFlags.VM_FZ : (result & (int)VMFlags.VM_FS)) + | ((Utility.URShift(value1, (value2 - 1))) & (int)VMFlags.VM_FC) + ); + SetValue(cmd.IsByteMode, Mem, op1, result); + } + break; + + case VMCommands.VM_SAR: + + { + var value1 = GetValue(cmd.IsByteMode, Mem, op1); + var value2 = GetValue(cmd.IsByteMode, Mem, op2); + var result = value1 >> value2; + flags = (VMFlags)( + (result == 0 ? (int)VMFlags.VM_FZ : (result & (int)VMFlags.VM_FS)) + | ((value1 >> (value2 - 1)) & (int)VMFlags.VM_FC) + ); + SetValue(cmd.IsByteMode, Mem, op1, result); + } + break; + + case VMCommands.VM_NEG: + + { + var result = -GetValue(cmd.IsByteMode, Mem, op1); + flags = (VMFlags)( + result == 0 + ? (int)VMFlags.VM_FZ + : (int)VMFlags.VM_FC | (result & (int)VMFlags.VM_FS) + ); + SetValue(cmd.IsByteMode, Mem, op1, result); + } + break; + + case VMCommands.VM_NEGB: + SetValue(true, Mem, op1, -GetValue(true, Mem, op1)); + break; + + case VMCommands.VM_NEGD: + SetValue(false, Mem, op1, -GetValue(false, Mem, op1)); + break; + + case VMCommands.VM_PUSHA: + + { + for (int i = 0, SP = R[7] - 4; i < regCount; i++, SP -= 4) + { + SetValue(false, Mem, SP & VM_MEMMASK, R[i]); + } + R[7] -= regCount * 4; + } + break; + + case VMCommands.VM_POPA: + + { + for (int i = 0, SP = R[7]; i < regCount; i++, SP += 4) + { + R[7 - i] = GetValue(false, Mem, SP & VM_MEMMASK); + } + } + break; + + case VMCommands.VM_PUSHF: + R[7] -= 4; + SetValue(false, Mem, R[7] & VM_MEMMASK, (int)flags); + break; + + case VMCommands.VM_POPF: + flags = (VMFlags)GetValue(false, Mem, R[7] & VM_MEMMASK); + R[7] += 4; + break; + + case VMCommands.VM_MOVZX: + SetValue(false, Mem, op1, GetValue(true, Mem, op2)); + break; + + case VMCommands.VM_MOVSX: + SetValue(false, Mem, op1, (byte)GetValue(true, Mem, op2)); + break; + + case VMCommands.VM_XCHG: + + { + var value1 = GetValue(cmd.IsByteMode, Mem, op1); + SetValue(cmd.IsByteMode, Mem, op1, GetValue(cmd.IsByteMode, Mem, op2)); + SetValue(cmd.IsByteMode, Mem, op2, value1); + } + break; + + case VMCommands.VM_MUL: + + { + var result = (int)( + ( + GetValue(cmd.IsByteMode, Mem, op1) + & (0xFFffFFff * GetValue(cmd.IsByteMode, Mem, op2)) + & unchecked((int)0xFFffFFff) + ) & unchecked((int)0xFFffFFff) + ); + SetValue(cmd.IsByteMode, Mem, op1, result); + } + break; + + case VMCommands.VM_DIV: + + { + var divider = GetValue(cmd.IsByteMode, Mem, op2); + if (divider != 0) + { + var result = GetValue(cmd.IsByteMode, Mem, op1) / divider; + SetValue(cmd.IsByteMode, Mem, op1, result); + } + } + break; + + case VMCommands.VM_ADC: + + { + var value1 = GetValue(cmd.IsByteMode, Mem, op1); + var FC = (int)(flags & VMFlags.VM_FC); + var result = (int)( + value1 + & (0xFFffFFff + GetValue(cmd.IsByteMode, Mem, op2)) + & (0xFFffFFff + FC) + & unchecked((int)0xFFffFFff) + ); + if (cmd.IsByteMode) + { + result &= 0xff; + } + + flags = (VMFlags)( + (result < value1 || result == value1 && FC != 0) + ? 1 + : 0 + | ( + result == 0 + ? (int)VMFlags.VM_FZ + : (result & (int)VMFlags.VM_FS) + ) + ); + SetValue(cmd.IsByteMode, Mem, op1, result); + } + break; + + case VMCommands.VM_SBB: + + { + var value1 = GetValue(cmd.IsByteMode, Mem, op1); + var FC = (int)(flags & VMFlags.VM_FC); + var result = (int)( + value1 + & (0xFFffFFff - GetValue(cmd.IsByteMode, Mem, op2)) + & (0xFFffFFff - FC) + & unchecked((int)0xFFffFFff) + ); + if (cmd.IsByteMode) + { + result &= 0xff; + } + flags = (VMFlags)( + (result > value1 || result == value1 && FC != 0) + ? 1 + : 0 + | ( + result == 0 + ? (int)VMFlags.VM_FZ + : (result & (int)VMFlags.VM_FS) + ) + ); + SetValue(cmd.IsByteMode, Mem, op1, result); + } + break; + + case VMCommands.VM_RET: + if (R[7] >= VM_MEMSIZE) + { + return (true); + } + setIP(GetValue(false, Mem, R[7] & VM_MEMMASK)); + R[7] += 4; + continue; + + case VMCommands.VM_STANDARD: + ExecuteStandardFilter((VMStandardFilters)(cmd.Op1.Data)); + break; + + case VMCommands.VM_PRINT: + break; + } + IP++; + --maxOpCount; + } + } + + public void prepare(byte[] code, int codeSize, VMPreparedProgram prg) + { + InitBitInput(); + var cpLength = Math.Min(MAX_SIZE, codeSize); + + // memcpy(inBuf,Code,Min(CodeSize,BitInput::MAX_SIZE)); + + Buffer.BlockCopy(code, 0, InBuf, 0, cpLength); + byte xorSum = 0; + for (var i = 1; i < codeSize; i++) + { + xorSum ^= code[i]; + } + + AddBits(8); + + prg.CommandCount = 0; + if (xorSum == code[0]) + { + var filterType = IsStandardFilter(code, codeSize); + if (filterType != VMStandardFilters.VMSF_NONE) + { + var curCmd = new VMPreparedCommand(); + curCmd.OpCode = VMCommands.VM_STANDARD; + curCmd.Op1.Data = (int)filterType; + curCmd.Op1.Type = VMOpType.VM_OPNONE; + curCmd.Op2.Type = VMOpType.VM_OPNONE; + codeSize = 0; + prg.Commands.Add(curCmd); + prg.CommandCount++; + + // TODO + // curCmd->Op1.Data=FilterType; + // >>>>>> CurCmd->Op1.Addr=&CurCmd->Op1.Data; <<<<<<<<<< not set + // do i need to ? + // >>>>>> CurCmd->Op2.Addr=&CurCmd->Op2.Data; <<<<<<<<<< " + // CurCmd->Op1.Type=CurCmd->Op2.Type=VM_OPNONE; + // CodeSize=0; + } + var dataFlag = GetBits(); + AddBits(1); + + // Read static data contained in DB operators. This data cannot be + // changed, + // it is a part of VM code, not a filter parameter. + + if ((dataFlag & 0x8000) != 0) + { + var dataSize = ReadData(this) & (0xffFFffFFL + 1L); + for (var i = 0; inAddr < codeSize && i < dataSize; i++) + { + prg.StaticData.Add((byte)(GetBits() >> 8)); + AddBits(8); + } + } + + while (inAddr < codeSize) + { + var curCmd = new VMPreparedCommand(); + var data = GetBits(); + if ((data & 0x8000) == 0) + { + curCmd.OpCode = (VMCommands)((data >> 12)); + AddBits(4); + } + else + { + curCmd.OpCode = (VMCommands)((data >> 10) - 24); + AddBits(6); + } + if ( + (VMCmdFlags.VM_CmdFlags[(int)curCmd.OpCode] & VMCmdFlags.VMCF_BYTEMODE) != 0 + ) + { + curCmd.IsByteMode = (GetBits() >> 15) == 1; + AddBits(1); + } + else + { + curCmd.IsByteMode = false; + } + curCmd.Op1.Type = VMOpType.VM_OPNONE; + curCmd.Op2.Type = VMOpType.VM_OPNONE; + + var opNum = ( + VMCmdFlags.VM_CmdFlags[(int)curCmd.OpCode] & VMCmdFlags.VMCF_OPMASK + ); + + // TODO >>> CurCmd->Op1.Addr=CurCmd->Op2.Addr=NULL; << 0) + { + decodeArg(curCmd.Op1, curCmd.IsByteMode); + if (opNum == 2) + { + decodeArg(curCmd.Op2, curCmd.IsByteMode); + } + else + { + if ( + curCmd.Op1.Type == VMOpType.VM_OPINT + && ( + VMCmdFlags.VM_CmdFlags[(int)curCmd.OpCode] + & (VMCmdFlags.VMCF_JUMP | VMCmdFlags.VMCF_PROC) + ) != 0 + ) + { + var distance = curCmd.Op1.Data; + if (distance >= 256) + { + distance -= 256; + } + else + { + if (distance >= 136) + { + distance -= 264; + } + else + { + if (distance >= 16) + { + distance -= 8; + } + else + { + if (distance >= 8) + { + distance -= 16; + } + } + } + distance += prg.CommandCount; + } + curCmd.Op1.Data = distance; + } + } + } + prg.CommandCount++; + prg.Commands.Add(curCmd); + } + } + var curCmd2 = new VMPreparedCommand(); + curCmd2.OpCode = VMCommands.VM_RET; + + // TODO CurCmd->Op1.Addr=&CurCmd->Op1.Data; + // CurCmd->Op2.Addr=&CurCmd->Op2.Data; + curCmd2.Op1.Type = VMOpType.VM_OPNONE; + curCmd2.Op2.Type = VMOpType.VM_OPNONE; + + // for (int i=0;iCmd[I]; + // if (Cmd->Op1.Addr==NULL) + // Cmd->Op1.Addr=&Cmd->Op1.Data; + // if (Cmd->Op2.Addr==NULL) + // Cmd->Op2.Addr=&Cmd->Op2.Data; + // } + + prg.Commands.Add(curCmd2); + prg.CommandCount++; + + // #ifdef VM_OPTIMIZE + if (codeSize != 0) + { + optimize(prg); + } + } + + private void decodeArg(VMPreparedOperand op, bool byteMode) + { + var data = GetBits(); + if ((data & 0x8000) != 0) + { + op.Type = VMOpType.VM_OPREG; + op.Data = (data >> 12) & 7; + op.Offset = op.Data; + AddBits(4); + } + else + { + if ((data & 0xc000) == 0) + { + op.Type = VMOpType.VM_OPINT; + if (byteMode) + { + op.Data = (data >> 6) & 0xff; + AddBits(10); + } + else + { + AddBits(2); + op.Data = ReadData(this); + } + } + else + { + op.Type = VMOpType.VM_OPREGMEM; + if ((data & 0x2000) == 0) + { + op.Data = (data >> 10) & 7; + op.Offset = op.Data; + op.Base = 0; + AddBits(6); + } + else + { + if ((data & 0x1000) == 0) + { + op.Data = (data >> 9) & 7; + op.Offset = op.Data; + AddBits(7); + } + else + { + op.Data = 0; AddBits(4); } - else - { - curCmd.OpCode = (VMCommands)((data >> 10) - 24); - AddBits(6); - } - if ( - (VMCmdFlags.VM_CmdFlags[(int)curCmd.OpCode] & VMCmdFlags.VMCF_BYTEMODE) != 0 - ) - { - curCmd.IsByteMode = (GetBits() >> 15) == 1 ? true : false; - AddBits(1); - } - else - { - curCmd.IsByteMode = false; - } - curCmd.Op1.Type = VMOpType.VM_OPNONE; - curCmd.Op2.Type = VMOpType.VM_OPNONE; - - int opNum = ( - VMCmdFlags.VM_CmdFlags[(int)curCmd.OpCode] & VMCmdFlags.VMCF_OPMASK - ); - - // TODO >>> CurCmd->Op1.Addr=CurCmd->Op2.Addr=NULL; << 0) - { - decodeArg(curCmd.Op1, curCmd.IsByteMode); - if (opNum == 2) - { - decodeArg(curCmd.Op2, curCmd.IsByteMode); - } - else - { - if ( - curCmd.Op1.Type == VMOpType.VM_OPINT - && ( - VMCmdFlags.VM_CmdFlags[(int)curCmd.OpCode] - & (VMCmdFlags.VMCF_JUMP | VMCmdFlags.VMCF_PROC) - ) != 0 - ) - { - int distance = curCmd.Op1.Data; - if (distance >= 256) - { - distance -= 256; - } - else - { - if (distance >= 136) - { - distance -= 264; - } - else - { - if (distance >= 16) - { - distance -= 8; - } - else - { - if (distance >= 8) - { - distance -= 16; - } - } - } - distance += prg.CommandCount; - } - curCmd.Op1.Data = distance; - } - } - } - prg.CommandCount = (prg.CommandCount + 1); - prg.Commands.Add(curCmd); - } - } - VMPreparedCommand curCmd2 = new VMPreparedCommand(); - curCmd2.OpCode = VMCommands.VM_RET; - - // TODO CurCmd->Op1.Addr=&CurCmd->Op1.Data; - // CurCmd->Op2.Addr=&CurCmd->Op2.Data; - curCmd2.Op1.Type = VMOpType.VM_OPNONE; - curCmd2.Op2.Type = VMOpType.VM_OPNONE; - - // for (int i=0;iCmd[I]; - // if (Cmd->Op1.Addr==NULL) - // Cmd->Op1.Addr=&Cmd->Op1.Data; - // if (Cmd->Op2.Addr==NULL) - // Cmd->Op2.Addr=&Cmd->Op2.Data; - // } - - prg.Commands.Add(curCmd2); - prg.CommandCount = prg.CommandCount + 1; - - // #ifdef VM_OPTIMIZE - if (codeSize != 0) - { - optimize(prg); - } - } - - private void decodeArg(VMPreparedOperand op, bool byteMode) - { - int data = GetBits(); - if ((data & 0x8000) != 0) - { - op.Type = VMOpType.VM_OPREG; - op.Data = (data >> 12) & 7; - op.Offset = op.Data; - AddBits(4); - } - else - { - if ((data & 0xc000) == 0) - { - op.Type = VMOpType.VM_OPINT; - if (byteMode) - { - op.Data = (data >> 6) & 0xff; - AddBits(10); - } - else - { - AddBits(2); - op.Data = ReadData(this); - } - } - else - { - op.Type = VMOpType.VM_OPREGMEM; - if ((data & 0x2000) == 0) - { - op.Data = (data >> 10) & 7; - op.Offset = op.Data; - op.Base = 0; - AddBits(6); - } - else - { - if ((data & 0x1000) == 0) - { - op.Data = (data >> 9) & 7; - op.Offset = op.Data; - AddBits(7); - } - else - { - op.Data = 0; - AddBits(4); - } - op.Base = ReadData(this); - } - } - } - } - - private void optimize(VMPreparedProgram prg) - { - //UPGRADE_NOTE: There is an untranslated Statement. Please refer to original code. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1153'" - - List commands = prg.Commands; - - //UPGRADE_ISSUE: The following fragment of code could not be parsed and was not converted. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1156'" - foreach (VMPreparedCommand cmd in commands) - { - switch (cmd.OpCode) - { - case VMCommands.VM_MOV: - cmd.OpCode = cmd.IsByteMode ? VMCommands.VM_MOVB : VMCommands.VM_MOVD; - continue; - - case VMCommands.VM_CMP: - cmd.OpCode = cmd.IsByteMode ? VMCommands.VM_CMPB : VMCommands.VM_CMPD; - continue; - } - if ((VMCmdFlags.VM_CmdFlags[(int)cmd.OpCode] & VMCmdFlags.VMCF_CHFLAGS) == 0) - { - continue; - } - bool flagsRequired = false; - - for (int i = commands.IndexOf(cmd) + 1; i < commands.Count; i++) - { - int flags = VMCmdFlags.VM_CmdFlags[(int)commands[i].OpCode]; - if ( - ( - flags - & ( - VMCmdFlags.VMCF_JUMP - | VMCmdFlags.VMCF_PROC - | VMCmdFlags.VMCF_USEFLAGS - ) - ) != 0 - ) - { - flagsRequired = true; - break; - } - if ((flags & VMCmdFlags.VMCF_CHFLAGS) != 0) - { - break; - } - } - if (flagsRequired) - { - continue; - } - switch (cmd.OpCode) - { - case VMCommands.VM_ADD: - cmd.OpCode = cmd.IsByteMode ? VMCommands.VM_ADDB : VMCommands.VM_ADDD; - continue; - - case VMCommands.VM_SUB: - cmd.OpCode = cmd.IsByteMode ? VMCommands.VM_SUBB : VMCommands.VM_SUBD; - continue; - - case VMCommands.VM_INC: - cmd.OpCode = cmd.IsByteMode ? VMCommands.VM_INCB : VMCommands.VM_INCD; - continue; - - case VMCommands.VM_DEC: - cmd.OpCode = cmd.IsByteMode ? VMCommands.VM_DECB : VMCommands.VM_DECD; - continue; - - case VMCommands.VM_NEG: - cmd.OpCode = cmd.IsByteMode ? VMCommands.VM_NEGB : VMCommands.VM_NEGD; - continue; - } - } - } - - internal static int ReadData(BitInput rarVM) - { - int data = rarVM.GetBits(); - switch (data & 0xc000) - { - case 0: - rarVM.AddBits(6); - return ((data >> 10) & 0xf); - - case 0x4000: - if ((data & 0x3c00) == 0) - { - data = unchecked((int)0xffffff00) | ((data >> 2) & 0xff); - rarVM.AddBits(14); - } - else - { - data = (data >> 6) & 0xff; - rarVM.AddBits(10); - } - return (data); - - case 0x8000: - rarVM.AddBits(2); - data = rarVM.GetBits(); - rarVM.AddBits(16); - return (data); - - default: - rarVM.AddBits(2); - data = (rarVM.GetBits() << 16); - rarVM.AddBits(16); - data |= rarVM.GetBits(); - rarVM.AddBits(16); - return (data); - } - } - - private VMStandardFilters IsStandardFilter(byte[] code, int codeSize) - { - VMStandardFilterSignature[] stdList = - { - new VMStandardFilterSignature(53, 0xad576887, VMStandardFilters.VMSF_E8), - new VMStandardFilterSignature(57, 0x3cd7e57e, VMStandardFilters.VMSF_E8E9), - new VMStandardFilterSignature(120, 0x3769893f, VMStandardFilters.VMSF_ITANIUM), - new VMStandardFilterSignature(29, 0x0e06077d, VMStandardFilters.VMSF_DELTA), - new VMStandardFilterSignature(149, 0x1c2c5dc8, VMStandardFilters.VMSF_RGB), - new VMStandardFilterSignature(216, 0xbc85e701, VMStandardFilters.VMSF_AUDIO), - new VMStandardFilterSignature(40, 0x46b9c560, VMStandardFilters.VMSF_UPCASE) - }; - uint CodeCRC = RarCRC.CheckCrc(0xffffffff, code, 0, code.Length) ^ 0xffffffff; - for (int i = 0; i < stdList.Length; i++) - { - if (stdList[i].CRC == CodeCRC && stdList[i].Length == code.Length) - { - return (stdList[i].Type); - } - } - return (VMStandardFilters.VMSF_NONE); - } - - private void ExecuteStandardFilter(VMStandardFilters filterType) - { - switch (filterType) - { - case VMStandardFilters.VMSF_E8: - case VMStandardFilters.VMSF_E8E9: - - { - int dataSize = R[4]; - long fileOffset = R[6] & unchecked((int)0xFFffFFff); - - if (dataSize >= VM_GLOBALMEMADDR) - { - break; - } - int fileSize = 0x1000000; - byte cmpByte2 = (byte)( - (filterType == VMStandardFilters.VMSF_E8E9) ? 0xe9 : 0xe8 - ); - for (int curPos = 0; curPos < dataSize - 4; ) - { - byte curByte = Mem[curPos++]; - if (curByte == 0xe8 || curByte == cmpByte2) - { - // #ifdef PRESENT_INT32 - // sint32 Offset=CurPos+FileOffset; - // sint32 Addr=GET_VALUE(false,Data); - // if (Addr<0) - // { - // if (Addr+Offset>=0) - // SET_VALUE(false,Data,Addr+FileSize); - // } - // else - // if (Addr= VM_GLOBALMEMADDR) - { - break; - } - int curPos = 0; - - //UPGRADE_NOTE: Final was removed from the declaration of 'Masks '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - byte[] Masks = { 4, 4, 6, 6, 0, 0, 7, 7, 4, 4, 0, 0, 4, 4, 0, 0 }; - fileOffset = Utility.URShift(fileOffset, 4); - - while (curPos < dataSize - 21) - { - int Byte = (Mem[curPos] & 0x1f) - 0x10; - if (Byte >= 0) - { - byte cmdMask = Masks[Byte]; - if (cmdMask != 0) - { - for (int i = 0; i <= 2; i++) - { - if ((cmdMask & (1 << i)) != 0) - { - int startPos = i * 41 + 5; - int opType = filterItanium_GetBits( - curPos, - startPos + 37, - 4 - ); - if (opType == 5) - { - int offset = filterItanium_GetBits( - curPos, - startPos + 13, - 20 - ); - filterItanium_SetBits( - curPos, - (int)(offset - fileOffset) & 0xfffff, - startPos + 13, - 20 - ); - } - } - } - } - } - curPos += 16; - fileOffset++; - } - } - break; - - case VMStandardFilters.VMSF_DELTA: - - { - int dataSize = R[4] & unchecked((int)0xFFffFFff); - int channels = R[0] & unchecked((int)0xFFffFFff); - int srcPos = 0; - int border = (dataSize * 2) & unchecked((int)0xFFffFFff); - SetValue(false, Mem, VM_GLOBALMEMADDR + 0x20, dataSize); - if (dataSize >= VM_GLOBALMEMADDR / 2) - { - break; - } - - // bytes from same channels are grouped to continual data blocks, - // so we need to place them back to their interleaving positions - - for (int curChannel = 0; curChannel < channels; curChannel++) - { - byte PrevByte = 0; - for ( - int destPos = dataSize + curChannel; - destPos < border; - destPos += channels - ) - { - Mem[destPos] = (PrevByte = (byte)(PrevByte - Mem[srcPos++])); - } - } - } - break; - - case VMStandardFilters.VMSF_RGB: - - { - // byte *SrcData=Mem,*DestData=SrcData+DataSize; - int dataSize = R[4], - width = R[0] - 3, - posR = R[1]; - int channels = 3; - int srcPos = 0; - int destDataPos = dataSize; - SetValue(false, Mem, VM_GLOBALMEMADDR + 0x20, dataSize); - if (dataSize >= VM_GLOBALMEMADDR / 2 || posR < 0) - { - break; - } - for (int curChannel = 0; curChannel < channels; curChannel++) - { - long prevByte = 0; - - for (int i = curChannel; i < dataSize; i += channels) - { - long predicted; - int upperPos = i - width; - if (upperPos >= 3) - { - int upperDataPos = destDataPos + upperPos; - int upperByte = Mem[upperDataPos] & 0xff; - int upperLeftByte = Mem[upperDataPos - 3] & 0xff; - predicted = prevByte + upperByte - upperLeftByte; - int pa = Math.Abs((int)(predicted - prevByte)); - int pb = Math.Abs((int)(predicted - upperByte)); - int pc = Math.Abs((int)(predicted - upperLeftByte)); - if (pa <= pb && pa <= pc) - { - predicted = prevByte; - } - else - { - if (pb <= pc) - { - predicted = upperByte; - } - else - { - predicted = upperLeftByte; - } - } - } - else - { - predicted = prevByte; - } - - prevByte = (predicted - Mem[srcPos++] & 0xff) & 0xff; - Mem[destDataPos + i] = (byte)(prevByte & 0xff); - } - } - for (int i = posR, border = dataSize - 2; i < border; i += 3) - { - byte G = Mem[destDataPos + i + 1]; - Mem[destDataPos + i] = (byte)(Mem[destDataPos + i] + G); - Mem[destDataPos + i + 2] = (byte)(Mem[destDataPos + i + 2] + G); - } - } - break; - - case VMStandardFilters.VMSF_AUDIO: - - { - int dataSize = R[4], - channels = R[0]; - int srcPos = 0; - int destDataPos = dataSize; - - //byte *SrcData=Mem,*DestData=SrcData+DataSize; - SetValue(false, Mem, VM_GLOBALMEMADDR + 0x20, dataSize); - if (dataSize >= VM_GLOBALMEMADDR / 2) - { - break; - } - for (int curChannel = 0; curChannel < channels; curChannel++) - { - long prevByte = 0; - long prevDelta = 0; - long[] Dif = new long[7]; - int D1 = 0, - D2 = 0, - D3; - int K1 = 0, - K2 = 0, - K3 = 0; - - for ( - int i = curChannel, byteCount = 0; - i < dataSize; - i += channels, byteCount++ - ) - { - D3 = D2; - D2 = (int)(prevDelta - D1); - D1 = (int)prevDelta; - - long predicted = 8 * prevByte + K1 * D1 + K2 * D2 + K3 * D3; - predicted = Utility.URShift(predicted, 3) & 0xff; - - long curByte = Mem[srcPos++]; - - predicted -= curByte; - Mem[destDataPos + i] = (byte)predicted; - prevDelta = (byte)(predicted - prevByte); - - //fix java byte - if (prevDelta >= 128) - { - prevDelta = 0 - (256 - prevDelta); - } - prevByte = predicted; - - //fix java byte - if (curByte >= 128) - { - curByte = 0 - (256 - curByte); - } - int D = ((int)curByte) << 3; - - Dif[0] += Math.Abs(D); - Dif[1] += Math.Abs(D - D1); - Dif[2] += Math.Abs(D + D1); - Dif[3] += Math.Abs(D - D2); - Dif[4] += Math.Abs(D + D2); - Dif[5] += Math.Abs(D - D3); - Dif[6] += Math.Abs(D + D3); - - if ((byteCount & 0x1f) == 0) - { - long minDif = Dif[0], - numMinDif = 0; - Dif[0] = 0; - for (int j = 1; j < Dif.Length; j++) - { - if (Dif[j] < minDif) - { - minDif = Dif[j]; - numMinDif = j; - } - Dif[j] = 0; - } - switch ((int)numMinDif) - { - case 1: - if (K1 >= -16) - { - K1--; - } - break; - - case 2: - if (K1 < 16) - { - K1++; - } - break; - - case 3: - if (K2 >= -16) - { - K2--; - } - break; - - case 4: - if (K2 < 16) - { - K2++; - } - break; - - case 5: - if (K3 >= -16) - { - K3--; - } - break; - - case 6: - if (K3 < 16) - { - K3++; - } - break; - } - } - } - } - } - break; - - case VMStandardFilters.VMSF_UPCASE: - - { - int dataSize = R[4], - srcPos = 0, - destPos = dataSize; - if (dataSize >= VM_GLOBALMEMADDR / 2) - { - break; - } - while (srcPos < dataSize) - { - byte curByte = Mem[srcPos++]; - if (curByte == 2 && (curByte = Mem[srcPos++]) != 2) - { - curByte = (byte)(curByte - 32); - } - Mem[destPos++] = curByte; - } - SetValue(false, Mem, VM_GLOBALMEMADDR + 0x1c, destPos - dataSize); - SetValue(false, Mem, VM_GLOBALMEMADDR + 0x20, dataSize); - } - break; - } - } - - private void filterItanium_SetBits(int curPos, int bitField, int bitPos, int bitCount) - { - int inAddr = bitPos / 8; - int inBit = bitPos & 7; - int andMask = Utility.URShift(unchecked((int)0xffffffff), (32 - bitCount)); - andMask = ~(andMask << inBit); - - bitField <<= inBit; - - for (int i = 0; i < 4; i++) - { - Mem[curPos + inAddr + i] &= (byte)(andMask); - Mem[curPos + inAddr + i] |= (byte)(bitField); - andMask = (Utility.URShift(andMask, 8)) | unchecked((int)0xff000000); - bitField = Utility.URShift(bitField, 8); - } - } - - private int filterItanium_GetBits(int curPos, int bitPos, int bitCount) - { - int inAddr = bitPos / 8; - int inBit = bitPos & 7; - int bitField = Mem[curPos + inAddr++] & 0xff; - bitField |= (Mem[curPos + inAddr++] & 0xff) << 8; - bitField |= (Mem[curPos + inAddr++] & 0xff) << 16; - bitField |= (Mem[curPos + inAddr] & 0xff) << 24; - bitField = Utility.URShift(bitField, inBit); - return (bitField & (Utility.URShift(unchecked((int)0xffffffff), (32 - bitCount)))); - } - - public void setMemory(int pos, byte[] data, int offset, int dataSize) - { - if (pos < VM_MEMSIZE) - { - //&& data!=Mem+Pos) - //memmove(Mem+Pos,Data,Min(DataSize,VM_MEMSIZE-Pos)); - for (int i = 0; i < Math.Min(data.Length - offset, dataSize); i++) - { - if ((VM_MEMSIZE - pos) < i) - { - break; - } - Mem[pos + i] = data[offset + i]; + op.Base = ReadData(this); } } } } - // + private void optimize(VMPreparedProgram prg) + { + //UPGRADE_NOTE: There is an untranslated Statement. Please refer to original code. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1153'" + + var commands = prg.Commands; + + //UPGRADE_ISSUE: The following fragment of code could not be parsed and was not converted. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1156'" + foreach (var cmd in commands) + { + switch (cmd.OpCode) + { + case VMCommands.VM_MOV: + cmd.OpCode = cmd.IsByteMode ? VMCommands.VM_MOVB : VMCommands.VM_MOVD; + continue; + + case VMCommands.VM_CMP: + cmd.OpCode = cmd.IsByteMode ? VMCommands.VM_CMPB : VMCommands.VM_CMPD; + continue; + } + if ((VMCmdFlags.VM_CmdFlags[(int)cmd.OpCode] & VMCmdFlags.VMCF_CHFLAGS) == 0) + { + continue; + } + var flagsRequired = false; + + for (var i = commands.IndexOf(cmd) + 1; i < commands.Count; i++) + { + int flags = VMCmdFlags.VM_CmdFlags[(int)commands[i].OpCode]; + if ( + ( + flags + & ( + VMCmdFlags.VMCF_JUMP + | VMCmdFlags.VMCF_PROC + | VMCmdFlags.VMCF_USEFLAGS + ) + ) != 0 + ) + { + flagsRequired = true; + break; + } + if ((flags & VMCmdFlags.VMCF_CHFLAGS) != 0) + { + break; + } + } + if (flagsRequired) + { + continue; + } + switch (cmd.OpCode) + { + case VMCommands.VM_ADD: + cmd.OpCode = cmd.IsByteMode ? VMCommands.VM_ADDB : VMCommands.VM_ADDD; + continue; + + case VMCommands.VM_SUB: + cmd.OpCode = cmd.IsByteMode ? VMCommands.VM_SUBB : VMCommands.VM_SUBD; + continue; + + case VMCommands.VM_INC: + cmd.OpCode = cmd.IsByteMode ? VMCommands.VM_INCB : VMCommands.VM_INCD; + continue; + + case VMCommands.VM_DEC: + cmd.OpCode = cmd.IsByteMode ? VMCommands.VM_DECB : VMCommands.VM_DECD; + continue; + + case VMCommands.VM_NEG: + cmd.OpCode = cmd.IsByteMode ? VMCommands.VM_NEGB : VMCommands.VM_NEGD; + continue; + } + } + } + + internal static int ReadData(BitInput rarVM) + { + var data = rarVM.GetBits(); + switch (data & 0xc000) + { + case 0: + rarVM.AddBits(6); + return ((data >> 10) & 0xf); + + case 0x4000: + if ((data & 0x3c00) == 0) + { + data = unchecked((int)0xffffff00) | ((data >> 2) & 0xff); + rarVM.AddBits(14); + } + else + { + data = (data >> 6) & 0xff; + rarVM.AddBits(10); + } + return (data); + + case 0x8000: + rarVM.AddBits(2); + data = rarVM.GetBits(); + rarVM.AddBits(16); + return (data); + + default: + rarVM.AddBits(2); + data = (rarVM.GetBits() << 16); + rarVM.AddBits(16); + data |= rarVM.GetBits(); + rarVM.AddBits(16); + return (data); + } + } + + private VMStandardFilters IsStandardFilter(byte[] code, int codeSize) + { + VMStandardFilterSignature[] stdList = + { + new VMStandardFilterSignature(53, 0xad576887, VMStandardFilters.VMSF_E8), + new VMStandardFilterSignature(57, 0x3cd7e57e, VMStandardFilters.VMSF_E8E9), + new VMStandardFilterSignature(120, 0x3769893f, VMStandardFilters.VMSF_ITANIUM), + new VMStandardFilterSignature(29, 0x0e06077d, VMStandardFilters.VMSF_DELTA), + new VMStandardFilterSignature(149, 0x1c2c5dc8, VMStandardFilters.VMSF_RGB), + new VMStandardFilterSignature(216, 0xbc85e701, VMStandardFilters.VMSF_AUDIO), + new VMStandardFilterSignature(40, 0x46b9c560, VMStandardFilters.VMSF_UPCASE) + }; + var CodeCRC = RarCRC.CheckCrc(0xffffffff, code, 0, code.Length) ^ 0xffffffff; + for (var i = 0; i < stdList.Length; i++) + { + if (stdList[i].CRC == CodeCRC && stdList[i].Length == code.Length) + { + return (stdList[i].Type); + } + } + return (VMStandardFilters.VMSF_NONE); + } + + private void ExecuteStandardFilter(VMStandardFilters filterType) + { + switch (filterType) + { + case VMStandardFilters.VMSF_E8: + case VMStandardFilters.VMSF_E8E9: + + { + var dataSize = R[4]; + long fileOffset = R[6] & unchecked((int)0xFFffFFff); + + if (dataSize >= VM_GLOBALMEMADDR) + { + break; + } + var fileSize = 0x1000000; + var cmpByte2 = (byte)( + (filterType == VMStandardFilters.VMSF_E8E9) ? 0xe9 : 0xe8 + ); + for (var curPos = 0; curPos < dataSize - 4;) + { + var curByte = Mem[curPos++]; + if (curByte == 0xe8 || curByte == cmpByte2) + { + // #ifdef PRESENT_INT32 + // sint32 Offset=CurPos+FileOffset; + // sint32 Addr=GET_VALUE(false,Data); + // if (Addr<0) + // { + // if (Addr+Offset>=0) + // SET_VALUE(false,Data,Addr+FileSize); + // } + // else + // if (Addr= VM_GLOBALMEMADDR) + { + break; + } + var curPos = 0; + + //UPGRADE_NOTE: Final was removed from the declaration of 'Masks '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + byte[] Masks = { 4, 4, 6, 6, 0, 0, 7, 7, 4, 4, 0, 0, 4, 4, 0, 0 }; + fileOffset = Utility.URShift(fileOffset, 4); + + while (curPos < dataSize - 21) + { + var Byte = (Mem[curPos] & 0x1f) - 0x10; + if (Byte >= 0) + { + var cmdMask = Masks[Byte]; + if (cmdMask != 0) + { + for (var i = 0; i <= 2; i++) + { + if ((cmdMask & (1 << i)) != 0) + { + var startPos = (i * 41) + 5; + var opType = filterItanium_GetBits( + curPos, + startPos + 37, + 4 + ); + if (opType == 5) + { + var offset = filterItanium_GetBits( + curPos, + startPos + 13, + 20 + ); + filterItanium_SetBits( + curPos, + (int)(offset - fileOffset) & 0xfffff, + startPos + 13, + 20 + ); + } + } + } + } + } + curPos += 16; + fileOffset++; + } + } + break; + + case VMStandardFilters.VMSF_DELTA: + + { + var dataSize = R[4] & unchecked((int)0xFFffFFff); + var channels = R[0] & unchecked((int)0xFFffFFff); + var srcPos = 0; + var border = (dataSize * 2) & unchecked((int)0xFFffFFff); + SetValue(false, Mem, VM_GLOBALMEMADDR + 0x20, dataSize); + if (dataSize >= VM_GLOBALMEMADDR / 2) + { + break; + } + + // bytes from same channels are grouped to continual data blocks, + // so we need to place them back to their interleaving positions + + for (var curChannel = 0; curChannel < channels; curChannel++) + { + byte PrevByte = 0; + for ( + var destPos = dataSize + curChannel; + destPos < border; + destPos += channels + ) + { + Mem[destPos] = (PrevByte = (byte)(PrevByte - Mem[srcPos++])); + } + } + } + break; + + case VMStandardFilters.VMSF_RGB: + + { + // byte *SrcData=Mem,*DestData=SrcData+DataSize; + int dataSize = R[4], + width = R[0] - 3, + posR = R[1]; + var channels = 3; + var srcPos = 0; + var destDataPos = dataSize; + SetValue(false, Mem, VM_GLOBALMEMADDR + 0x20, dataSize); + if (dataSize >= VM_GLOBALMEMADDR / 2 || posR < 0) + { + break; + } + for (var curChannel = 0; curChannel < channels; curChannel++) + { + long prevByte = 0; + + for (var i = curChannel; i < dataSize; i += channels) + { + long predicted; + var upperPos = i - width; + if (upperPos >= 3) + { + var upperDataPos = destDataPos + upperPos; + var upperByte = Mem[upperDataPos] & 0xff; + var upperLeftByte = Mem[upperDataPos - 3] & 0xff; + predicted = prevByte + upperByte - upperLeftByte; + var pa = Math.Abs((int)(predicted - prevByte)); + var pb = Math.Abs((int)(predicted - upperByte)); + var pc = Math.Abs((int)(predicted - upperLeftByte)); + if (pa <= pb && pa <= pc) + { + predicted = prevByte; + } + else + { + if (pb <= pc) + { + predicted = upperByte; + } + else + { + predicted = upperLeftByte; + } + } + } + else + { + predicted = prevByte; + } + + prevByte = ((predicted - Mem[srcPos++]) & 0xff) & 0xff; + Mem[destDataPos + i] = (byte)(prevByte & 0xff); + } + } + for (int i = posR, border = dataSize - 2; i < border; i += 3) + { + var G = Mem[destDataPos + i + 1]; + Mem[destDataPos + i] = (byte)(Mem[destDataPos + i] + G); + Mem[destDataPos + i + 2] = (byte)(Mem[destDataPos + i + 2] + G); + } + } + break; + + case VMStandardFilters.VMSF_AUDIO: + + { + int dataSize = R[4], + channels = R[0]; + var srcPos = 0; + var destDataPos = dataSize; + + //byte *SrcData=Mem,*DestData=SrcData+DataSize; + SetValue(false, Mem, VM_GLOBALMEMADDR + 0x20, dataSize); + if (dataSize >= VM_GLOBALMEMADDR / 2) + { + break; + } + for (var curChannel = 0; curChannel < channels; curChannel++) + { + long prevByte = 0; + long prevDelta = 0; + var Dif = new long[7]; + int D1 = 0, + D2 = 0, + D3; + int K1 = 0, + K2 = 0, + K3 = 0; + + for ( + int i = curChannel, byteCount = 0; + i < dataSize; + i += channels, byteCount++ + ) + { + D3 = D2; + D2 = (int)(prevDelta - D1); + D1 = (int)prevDelta; + + var predicted = (8 * prevByte) + (K1 * D1) + (K2 * D2) + (K3 * D3); + predicted = Utility.URShift(predicted, 3) & 0xff; + + long curByte = Mem[srcPos++]; + + predicted -= curByte; + Mem[destDataPos + i] = (byte)predicted; + prevDelta = (byte)(predicted - prevByte); + + //fix java byte + if (prevDelta >= 128) + { + prevDelta = 0 - (256 - prevDelta); + } + prevByte = predicted; + + //fix java byte + if (curByte >= 128) + { + curByte = 0 - (256 - curByte); + } + var D = ((int)curByte) << 3; + + Dif[0] += Math.Abs(D); + Dif[1] += Math.Abs(D - D1); + Dif[2] += Math.Abs(D + D1); + Dif[3] += Math.Abs(D - D2); + Dif[4] += Math.Abs(D + D2); + Dif[5] += Math.Abs(D - D3); + Dif[6] += Math.Abs(D + D3); + + if ((byteCount & 0x1f) == 0) + { + long minDif = Dif[0], + numMinDif = 0; + Dif[0] = 0; + for (var j = 1; j < Dif.Length; j++) + { + if (Dif[j] < minDif) + { + minDif = Dif[j]; + numMinDif = j; + } + Dif[j] = 0; + } + switch ((int)numMinDif) + { + case 1: + if (K1 >= -16) + { + K1--; + } + break; + + case 2: + if (K1 < 16) + { + K1++; + } + break; + + case 3: + if (K2 >= -16) + { + K2--; + } + break; + + case 4: + if (K2 < 16) + { + K2++; + } + break; + + case 5: + if (K3 >= -16) + { + K3--; + } + break; + + case 6: + if (K3 < 16) + { + K3++; + } + break; + } + } + } + } + } + break; + + case VMStandardFilters.VMSF_UPCASE: + + { + int dataSize = R[4], + srcPos = 0, + destPos = dataSize; + if (dataSize >= VM_GLOBALMEMADDR / 2) + { + break; + } + while (srcPos < dataSize) + { + var curByte = Mem[srcPos++]; + if (curByte == 2 && (curByte = Mem[srcPos++]) != 2) + { + curByte = (byte)(curByte - 32); + } + Mem[destPos++] = curByte; + } + SetValue(false, Mem, VM_GLOBALMEMADDR + 0x1c, destPos - dataSize); + SetValue(false, Mem, VM_GLOBALMEMADDR + 0x20, dataSize); + } + break; + } + } + + private void filterItanium_SetBits(int curPos, int bitField, int bitPos, int bitCount) + { + var inAddr = bitPos / 8; + var inBit = bitPos & 7; + var andMask = Utility.URShift(unchecked((int)0xffffffff), (32 - bitCount)); + andMask = ~(andMask << inBit); + + bitField <<= inBit; + + for (var i = 0; i < 4; i++) + { + Mem[curPos + inAddr + i] &= (byte)(andMask); + Mem[curPos + inAddr + i] |= (byte)(bitField); + andMask = (Utility.URShift(andMask, 8)) | unchecked((int)0xff000000); + bitField = Utility.URShift(bitField, 8); + } + } + + private int filterItanium_GetBits(int curPos, int bitPos, int bitCount) + { + var inAddr = bitPos / 8; + var inBit = bitPos & 7; + var bitField = Mem[curPos + inAddr++] & 0xff; + bitField |= (Mem[curPos + inAddr++] & 0xff) << 8; + bitField |= (Mem[curPos + inAddr++] & 0xff) << 16; + bitField |= (Mem[curPos + inAddr] & 0xff) << 24; + bitField = Utility.URShift(bitField, inBit); + return (bitField & (Utility.URShift(unchecked((int)0xffffffff), (32 - bitCount)))); + } + + public void setMemory(int pos, byte[] data, int offset, int dataSize) + { + if (pos < VM_MEMSIZE) + { + //&& data!=Mem+Pos) + //memmove(Mem+Pos,Data,Min(DataSize,VM_MEMSIZE-Pos)); + for (var i = 0; i < Math.Min(data.Length - offset, dataSize); i++) + { + if ((VM_MEMSIZE - pos) < i) + { + break; + } + Mem[pos + i] = data[offset + i]; + } + } + } } + +// diff --git a/src/SharpCompress/Compressors/Rar/VM/VMCmdFlags.cs b/src/SharpCompress/Compressors/Rar/VM/VMCmdFlags.cs index d599a558..00de0b6a 100644 --- a/src/SharpCompress/Compressors/Rar/VM/VMCmdFlags.cs +++ b/src/SharpCompress/Compressors/Rar/VM/VMCmdFlags.cs @@ -1,59 +1,58 @@ -namespace SharpCompress.Compressors.Rar.VM -{ - internal class VMCmdFlags - { - public const byte VMCF_OP0 = 0; - public const byte VMCF_OP1 = 1; - public const byte VMCF_OP2 = 2; - public const byte VMCF_OPMASK = 3; - public const byte VMCF_BYTEMODE = 4; - public const byte VMCF_JUMP = 8; - public const byte VMCF_PROC = 16; - public const byte VMCF_USEFLAGS = 32; - public const byte VMCF_CHFLAGS = 64; +namespace SharpCompress.Compressors.Rar.VM; - public static byte[] VM_CmdFlags = - { - VMCF_OP2 | VMCF_BYTEMODE, - VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, - VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, - VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, - VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS, - VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS, - VMCF_OP1 | VMCF_BYTEMODE | VMCF_CHFLAGS, - VMCF_OP1 | VMCF_BYTEMODE | VMCF_CHFLAGS, - VMCF_OP1 | VMCF_JUMP, - VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, - VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, - VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, - VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, - VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS, - VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS, - VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS, - VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS, - VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS, - VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS, - VMCF_OP1, - VMCF_OP1, - VMCF_OP1 | VMCF_PROC, - VMCF_OP0 | VMCF_PROC, - VMCF_OP1 | VMCF_BYTEMODE, - VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, - VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, - VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, - VMCF_OP1 | VMCF_BYTEMODE | VMCF_CHFLAGS, - VMCF_OP0, - VMCF_OP0, - VMCF_OP0 | VMCF_USEFLAGS, - VMCF_OP0 | VMCF_CHFLAGS, - VMCF_OP2, - VMCF_OP2, - VMCF_OP2 | VMCF_BYTEMODE, - VMCF_OP2 | VMCF_BYTEMODE, - VMCF_OP2 | VMCF_BYTEMODE, - VMCF_OP2 | VMCF_BYTEMODE | VMCF_USEFLAGS | VMCF_CHFLAGS, - VMCF_OP2 | VMCF_BYTEMODE | VMCF_USEFLAGS | VMCF_CHFLAGS, - VMCF_OP0 - }; - } +internal class VMCmdFlags +{ + public const byte VMCF_OP0 = 0; + public const byte VMCF_OP1 = 1; + public const byte VMCF_OP2 = 2; + public const byte VMCF_OPMASK = 3; + public const byte VMCF_BYTEMODE = 4; + public const byte VMCF_JUMP = 8; + public const byte VMCF_PROC = 16; + public const byte VMCF_USEFLAGS = 32; + public const byte VMCF_CHFLAGS = 64; + + public static byte[] VM_CmdFlags = + { + VMCF_OP2 | VMCF_BYTEMODE, + VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, + VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, + VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, + VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS, + VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS, + VMCF_OP1 | VMCF_BYTEMODE | VMCF_CHFLAGS, + VMCF_OP1 | VMCF_BYTEMODE | VMCF_CHFLAGS, + VMCF_OP1 | VMCF_JUMP, + VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, + VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, + VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, + VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, + VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS, + VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS, + VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS, + VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS, + VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS, + VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS, + VMCF_OP1, + VMCF_OP1, + VMCF_OP1 | VMCF_PROC, + VMCF_OP0 | VMCF_PROC, + VMCF_OP1 | VMCF_BYTEMODE, + VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, + VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, + VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS, + VMCF_OP1 | VMCF_BYTEMODE | VMCF_CHFLAGS, + VMCF_OP0, + VMCF_OP0, + VMCF_OP0 | VMCF_USEFLAGS, + VMCF_OP0 | VMCF_CHFLAGS, + VMCF_OP2, + VMCF_OP2, + VMCF_OP2 | VMCF_BYTEMODE, + VMCF_OP2 | VMCF_BYTEMODE, + VMCF_OP2 | VMCF_BYTEMODE, + VMCF_OP2 | VMCF_BYTEMODE | VMCF_USEFLAGS | VMCF_CHFLAGS, + VMCF_OP2 | VMCF_BYTEMODE | VMCF_USEFLAGS | VMCF_CHFLAGS, + VMCF_OP0 + }; } diff --git a/src/SharpCompress/Compressors/Rar/VM/VMCommands.cs b/src/SharpCompress/Compressors/Rar/VM/VMCommands.cs index 46fde3f7..7bb1a396 100644 --- a/src/SharpCompress/Compressors/Rar/VM/VMCommands.cs +++ b/src/SharpCompress/Compressors/Rar/VM/VMCommands.cs @@ -1,71 +1,70 @@ -namespace SharpCompress.Compressors.Rar.VM +namespace SharpCompress.Compressors.Rar.VM; + +internal enum VMCommands { - internal enum VMCommands - { - VM_MOV = 0, - VM_CMP = 1, - VM_ADD = 2, - VM_SUB = 3, - VM_JZ = 4, - VM_JNZ = 5, - VM_INC = 6, + VM_MOV = 0, + VM_CMP = 1, + VM_ADD = 2, + VM_SUB = 3, + VM_JZ = 4, + VM_JNZ = 5, + VM_INC = 6, - VM_DEC = 7, - VM_JMP = 8, - VM_XOR = 9, - VM_AND = 10, - VM_OR = 11, - VM_TEST = 12, + VM_DEC = 7, + VM_JMP = 8, + VM_XOR = 9, + VM_AND = 10, + VM_OR = 11, + VM_TEST = 12, - VM_JS = 13, - VM_JNS = 14, - VM_JB = 15, - VM_JBE = 16, - VM_JA = 17, - VM_JAE = 18, + VM_JS = 13, + VM_JNS = 14, + VM_JB = 15, + VM_JBE = 16, + VM_JA = 17, + VM_JAE = 18, - VM_PUSH = 19, - VM_POP = 20, - VM_CALL = 21, - VM_RET = 22, - VM_NOT = 23, - VM_SHL = 24, + VM_PUSH = 19, + VM_POP = 20, + VM_CALL = 21, + VM_RET = 22, + VM_NOT = 23, + VM_SHL = 24, - VM_SHR = 25, - VM_SAR = 26, - VM_NEG = 27, - VM_PUSHA = 28, - VM_POPA = 29, - VM_PUSHF = 30, + VM_SHR = 25, + VM_SAR = 26, + VM_NEG = 27, + VM_PUSHA = 28, + VM_POPA = 29, + VM_PUSHF = 30, - VM_POPF = 31, - VM_MOVZX = 32, - VM_MOVSX = 33, - VM_XCHG = 34, - VM_MUL = 35, - VM_DIV = 36, + VM_POPF = 31, + VM_MOVZX = 32, + VM_MOVSX = 33, + VM_XCHG = 34, + VM_MUL = 35, + VM_DIV = 36, - VM_ADC = 37, - VM_SBB = 38, - VM_PRINT = 39, + VM_ADC = 37, + VM_SBB = 38, + VM_PRINT = 39, - VM_MOVB = 40, - VM_MOVD = 41, - VM_CMPB = 42, - VM_CMPD = 43, + VM_MOVB = 40, + VM_MOVD = 41, + VM_CMPB = 42, + VM_CMPD = 43, - VM_ADDB = 44, - VM_ADDD = 45, - VM_SUBB = 46, - VM_SUBD = 47, - VM_INCB = 48, - VM_INCD = 49, + VM_ADDB = 44, + VM_ADDD = 45, + VM_SUBB = 46, + VM_SUBD = 47, + VM_INCB = 48, + VM_INCD = 49, - VM_DECB = 50, - VM_DECD = 51, - VM_NEGB = 52, - VM_NEGD = 53, + VM_DECB = 50, + VM_DECD = 51, + VM_NEGB = 52, + VM_NEGD = 53, - VM_STANDARD = 54 - } + VM_STANDARD = 54 } diff --git a/src/SharpCompress/Compressors/Rar/VM/VMFlags.cs b/src/SharpCompress/Compressors/Rar/VM/VMFlags.cs index d8b23ba8..fa9a72e7 100644 --- a/src/SharpCompress/Compressors/Rar/VM/VMFlags.cs +++ b/src/SharpCompress/Compressors/Rar/VM/VMFlags.cs @@ -1,10 +1,9 @@ -namespace SharpCompress.Compressors.Rar.VM +namespace SharpCompress.Compressors.Rar.VM; + +internal enum VMFlags { - internal enum VMFlags - { - None = 0, - VM_FC = 1, - VM_FZ = 2, - VM_FS = 80000000 - } + None = 0, + VM_FC = 1, + VM_FZ = 2, + VM_FS = 80000000 } diff --git a/src/SharpCompress/Compressors/Rar/VM/VMOpType.cs b/src/SharpCompress/Compressors/Rar/VM/VMOpType.cs index 8c72eb74..bcc4214e 100644 --- a/src/SharpCompress/Compressors/Rar/VM/VMOpType.cs +++ b/src/SharpCompress/Compressors/Rar/VM/VMOpType.cs @@ -1,10 +1,9 @@ -namespace SharpCompress.Compressors.Rar.VM +namespace SharpCompress.Compressors.Rar.VM; + +internal enum VMOpType { - internal enum VMOpType - { - VM_OPREG = 0, - VM_OPINT = 1, - VM_OPREGMEM = 2, - VM_OPNONE = 3 - } + VM_OPREG = 0, + VM_OPINT = 1, + VM_OPREGMEM = 2, + VM_OPNONE = 3 } diff --git a/src/SharpCompress/Compressors/Rar/VM/VMPreparedCommand.cs b/src/SharpCompress/Compressors/Rar/VM/VMPreparedCommand.cs index 69a459ca..e6fed0b1 100644 --- a/src/SharpCompress/Compressors/Rar/VM/VMPreparedCommand.cs +++ b/src/SharpCompress/Compressors/Rar/VM/VMPreparedCommand.cs @@ -1,17 +1,16 @@ -namespace SharpCompress.Compressors.Rar.VM +namespace SharpCompress.Compressors.Rar.VM; + +internal class VMPreparedCommand { - internal class VMPreparedCommand + internal VMPreparedCommand() { - internal VMPreparedCommand() - { - Op1 = new VMPreparedOperand(); - Op2 = new VMPreparedOperand(); - } - - internal VMCommands OpCode { get; set; } - internal bool IsByteMode { get; set; } - internal VMPreparedOperand Op1 { get; } - - internal VMPreparedOperand Op2 { get; } + Op1 = new VMPreparedOperand(); + Op2 = new VMPreparedOperand(); } + + internal VMCommands OpCode { get; set; } + internal bool IsByteMode { get; set; } + internal VMPreparedOperand Op1 { get; } + + internal VMPreparedOperand Op2 { get; } } diff --git a/src/SharpCompress/Compressors/Rar/VM/VMPreparedOperand.cs b/src/SharpCompress/Compressors/Rar/VM/VMPreparedOperand.cs index 2f20f306..af1be450 100644 --- a/src/SharpCompress/Compressors/Rar/VM/VMPreparedOperand.cs +++ b/src/SharpCompress/Compressors/Rar/VM/VMPreparedOperand.cs @@ -1,10 +1,9 @@ -namespace SharpCompress.Compressors.Rar.VM +namespace SharpCompress.Compressors.Rar.VM; + +internal class VMPreparedOperand { - internal class VMPreparedOperand - { - internal VMOpType Type { get; set; } - internal int Data { get; set; } - internal int Base { get; set; } - internal int Offset { get; set; } - } + internal VMOpType Type { get; set; } + internal int Data { get; set; } + internal int Base { get; set; } + internal int Offset { get; set; } } diff --git a/src/SharpCompress/Compressors/Rar/VM/VMPreparedProgram.cs b/src/SharpCompress/Compressors/Rar/VM/VMPreparedProgram.cs index de9e7054..c0006e09 100644 --- a/src/SharpCompress/Compressors/Rar/VM/VMPreparedProgram.cs +++ b/src/SharpCompress/Compressors/Rar/VM/VMPreparedProgram.cs @@ -1,21 +1,20 @@ using System.Collections.Generic; -namespace SharpCompress.Compressors.Rar.VM +namespace SharpCompress.Compressors.Rar.VM; + +internal class VMPreparedProgram { - internal class VMPreparedProgram - { - internal List Commands = new List(); - internal List AltCommands = new List(); + internal List Commands = new List(); + internal List AltCommands = new List(); - public int CommandCount { get; set; } + public int CommandCount { get; set; } - internal List GlobalData = new List(); - internal List StaticData = new List(); + internal List GlobalData = new List(); + internal List StaticData = new List(); - // static data contained in DB operators - internal int[] InitR = new int[7]; + // static data contained in DB operators + internal int[] InitR = new int[7]; - internal int FilteredDataOffset { get; set; } - internal int FilteredDataSize { get; set; } - } + internal int FilteredDataOffset { get; set; } + internal int FilteredDataSize { get; set; } } diff --git a/src/SharpCompress/Compressors/Rar/VM/VMStandardFilterSignature.cs b/src/SharpCompress/Compressors/Rar/VM/VMStandardFilterSignature.cs index cc55f167..a9096041 100644 --- a/src/SharpCompress/Compressors/Rar/VM/VMStandardFilterSignature.cs +++ b/src/SharpCompress/Compressors/Rar/VM/VMStandardFilterSignature.cs @@ -1,18 +1,17 @@ -namespace SharpCompress.Compressors.Rar.VM +namespace SharpCompress.Compressors.Rar.VM; + +internal class VMStandardFilterSignature { - internal class VMStandardFilterSignature + internal VMStandardFilterSignature(int length, uint crc, VMStandardFilters type) { - internal VMStandardFilterSignature(int length, uint crc, VMStandardFilters type) - { - Length = length; - CRC = crc; - Type = type; - } - - internal int Length { get; } - - internal uint CRC { get; } - - internal VMStandardFilters Type { get; } + Length = length; + CRC = crc; + Type = type; } + + internal int Length { get; } + + internal uint CRC { get; } + + internal VMStandardFilters Type { get; } } diff --git a/src/SharpCompress/Compressors/Rar/VM/VMStandardFilters.cs b/src/SharpCompress/Compressors/Rar/VM/VMStandardFilters.cs index 5f7c18ea..4b90b019 100644 --- a/src/SharpCompress/Compressors/Rar/VM/VMStandardFilters.cs +++ b/src/SharpCompress/Compressors/Rar/VM/VMStandardFilters.cs @@ -1,14 +1,13 @@ -namespace SharpCompress.Compressors.Rar.VM +namespace SharpCompress.Compressors.Rar.VM; + +internal enum VMStandardFilters { - internal enum VMStandardFilters - { - VMSF_NONE = 0, - VMSF_E8 = 1, - VMSF_E8E9 = 2, - VMSF_ITANIUM = 3, - VMSF_RGB = 4, - VMSF_AUDIO = 5, - VMSF_DELTA = 6, - VMSF_UPCASE = 7 - } + VMSF_NONE = 0, + VMSF_E8 = 1, + VMSF_E8E9 = 2, + VMSF_ITANIUM = 3, + VMSF_RGB = 4, + VMSF_AUDIO = 5, + VMSF_DELTA = 6, + VMSF_UPCASE = 7 } diff --git a/src/SharpCompress/Compressors/Xz/BinaryUtils.cs b/src/SharpCompress/Compressors/Xz/BinaryUtils.cs index a0a92171..b05c3bb1 100644 --- a/src/SharpCompress/Compressors/Xz/BinaryUtils.cs +++ b/src/SharpCompress/Compressors/Xz/BinaryUtils.cs @@ -1,61 +1,60 @@ -using System; +using System; using System.Buffers.Binary; using System.IO; -namespace SharpCompress.Compressors.Xz +namespace SharpCompress.Compressors.Xz; + +[CLSCompliant(false)] +public static class BinaryUtils { - [CLSCompliant(false)] - public static class BinaryUtils + public static int ReadLittleEndianInt32(this BinaryReader reader) { - public static int ReadLittleEndianInt32(this BinaryReader reader) + var bytes = reader.ReadBytes(4); + return BinaryPrimitives.ReadInt32LittleEndian(bytes); + } + + internal static uint ReadLittleEndianUInt32(this BinaryReader reader) + { + return unchecked((uint)ReadLittleEndianInt32(reader)); + } + + public static int ReadLittleEndianInt32(this Stream stream) + { + Span bytes = stackalloc byte[4]; + var read = stream.ReadFully(bytes); + if (!read) { - byte[] bytes = reader.ReadBytes(4); - return BinaryPrimitives.ReadInt32LittleEndian(bytes); + throw new EndOfStreamException(); + } + return BinaryPrimitives.ReadInt32LittleEndian(bytes); + } + + internal static uint ReadLittleEndianUInt32(this Stream stream) + { + return unchecked((uint)ReadLittleEndianInt32(stream)); + } + + internal static byte[] ToBigEndianBytes(this uint uint32) + { + var result = BitConverter.GetBytes(uint32); + + if (BitConverter.IsLittleEndian) + { + Array.Reverse(result); } - internal static uint ReadLittleEndianUInt32(this BinaryReader reader) + return result; + } + + public static byte[] ToLittleEndianBytes(this uint uint32) + { + var result = BitConverter.GetBytes(uint32); + + if (!BitConverter.IsLittleEndian) { - return unchecked((uint)ReadLittleEndianInt32(reader)); + Array.Reverse(result); } - public static int ReadLittleEndianInt32(this Stream stream) - { - Span bytes = stackalloc byte[4]; - var read = stream.ReadFully(bytes); - if (!read) - { - throw new EndOfStreamException(); - } - return BinaryPrimitives.ReadInt32LittleEndian(bytes); - } - - internal static uint ReadLittleEndianUInt32(this Stream stream) - { - return unchecked((uint)ReadLittleEndianInt32(stream)); - } - - internal static byte[] ToBigEndianBytes(this uint uint32) - { - var result = BitConverter.GetBytes(uint32); - - if (BitConverter.IsLittleEndian) - { - Array.Reverse(result); - } - - return result; - } - - public static byte[] ToLittleEndianBytes(this uint uint32) - { - var result = BitConverter.GetBytes(uint32); - - if (!BitConverter.IsLittleEndian) - { - Array.Reverse(result); - } - - return result; - } + return result; } } diff --git a/src/SharpCompress/Compressors/Xz/CheckType.cs b/src/SharpCompress/Compressors/Xz/CheckType.cs index 4176ac4b..a94f8261 100644 --- a/src/SharpCompress/Compressors/Xz/CheckType.cs +++ b/src/SharpCompress/Compressors/Xz/CheckType.cs @@ -1,10 +1,9 @@ -namespace SharpCompress.Compressors.Xz +namespace SharpCompress.Compressors.Xz; + +public enum CheckType : byte { - public enum CheckType : byte - { - NONE = 0x00, - CRC32 = 0x01, - CRC64 = 0x04, - SHA256 = 0x0A - } + NONE = 0x00, + CRC32 = 0x01, + CRC64 = 0x04, + SHA256 = 0x0A } diff --git a/src/SharpCompress/Compressors/Xz/Crc32.cs b/src/SharpCompress/Compressors/Xz/Crc32.cs index 51b4c7bf..5df276ae 100644 --- a/src/SharpCompress/Compressors/Xz/Crc32.cs +++ b/src/SharpCompress/Compressors/Xz/Crc32.cs @@ -1,76 +1,75 @@ -#nullable disable +#nullable disable using System; -namespace SharpCompress.Compressors.Xz +namespace SharpCompress.Compressors.Xz; + +[CLSCompliant(false)] +public static class Crc32 { - [CLSCompliant(false)] - public static class Crc32 + public const uint DefaultPolynomial = 0xedb88320u; + public const uint DefaultSeed = 0xffffffffu; + + private static uint[] defaultTable; + + public static uint Compute(byte[] buffer) { - public const UInt32 DefaultPolynomial = 0xedb88320u; - public const UInt32 DefaultSeed = 0xffffffffu; + return Compute(DefaultSeed, buffer); + } - private static UInt32[] defaultTable; + public static uint Compute(uint seed, byte[] buffer) + { + return Compute(DefaultPolynomial, seed, buffer); + } - public static UInt32 Compute(byte[] buffer) + public static uint Compute(uint polynomial, uint seed, byte[] buffer) + { + return ~CalculateHash(InitializeTable(polynomial), seed, buffer); + } + + private static uint[] InitializeTable(uint polynomial) + { + if (polynomial == DefaultPolynomial && defaultTable != null) { - return Compute(DefaultSeed, buffer); + return defaultTable; } - public static UInt32 Compute(UInt32 seed, byte[] buffer) + var createTable = new uint[256]; + for (var i = 0; i < 256; i++) { - return Compute(DefaultPolynomial, seed, buffer); - } - - public static UInt32 Compute(UInt32 polynomial, UInt32 seed, byte[] buffer) - { - return ~CalculateHash(InitializeTable(polynomial), seed, buffer); - } - - private static UInt32[] InitializeTable(UInt32 polynomial) - { - if (polynomial == DefaultPolynomial && defaultTable != null) + var entry = (uint)i; + for (var j = 0; j < 8; j++) { - return defaultTable; - } - - var createTable = new UInt32[256]; - for (var i = 0; i < 256; i++) - { - var entry = (UInt32)i; - for (var j = 0; j < 8; j++) + if ((entry & 1) == 1) { - if ((entry & 1) == 1) - { - entry = (entry >> 1) ^ polynomial; - } - else - { - entry = entry >> 1; - } + entry = (entry >> 1) ^ polynomial; + } + else + { + entry >>= 1; } - - createTable[i] = entry; } - if (polynomial == DefaultPolynomial) - { - defaultTable = createTable; - } - - return createTable; + createTable[i] = entry; } - private static UInt32 CalculateHash(UInt32[] table, UInt32 seed, ReadOnlySpan buffer) + if (polynomial == DefaultPolynomial) { - var crc = seed; - int len = buffer.Length; - for (var i = 0; i < len; i++) - { - crc = (crc >> 8) ^ table[(buffer[i] ^ crc) & 0xff]; - } - - return crc; + defaultTable = createTable; } + + return createTable; + } + + private static uint CalculateHash(uint[] table, uint seed, ReadOnlySpan buffer) + { + var crc = seed; + var len = buffer.Length; + for (var i = 0; i < len; i++) + { + crc = (crc >> 8) ^ table[(buffer[i] ^ crc) & 0xff]; + } + + return crc; } } diff --git a/src/SharpCompress/Compressors/Xz/Crc64.cs b/src/SharpCompress/Compressors/Xz/Crc64.cs index 6ea99940..6e578329 100644 --- a/src/SharpCompress/Compressors/Xz/Crc64.cs +++ b/src/SharpCompress/Compressors/Xz/Crc64.cs @@ -1,67 +1,65 @@ -#nullable disable +#nullable disable using System; -using System.Collections.Generic; -namespace SharpCompress.Compressors.Xz +namespace SharpCompress.Compressors.Xz; + +[CLSCompliant(false)] +public static class Crc64 { - [CLSCompliant(false)] - public static class Crc64 + public const ulong DefaultSeed = 0x0; + + internal static ulong[] Table; + + public const ulong Iso3309Polynomial = 0xD800000000000000; + + public static ulong Compute(byte[] buffer) { - public const UInt64 DefaultSeed = 0x0; + return Compute(DefaultSeed, buffer); + } - internal static UInt64[] Table; + public static ulong Compute(ulong seed, byte[] buffer) + { + Table ??= CreateTable(Iso3309Polynomial); - public const UInt64 Iso3309Polynomial = 0xD800000000000000; + return CalculateHash(seed, Table, buffer); + } - public static UInt64 Compute(byte[] buffer) + public static ulong CalculateHash(ulong seed, ulong[] table, ReadOnlySpan buffer) + { + var crc = seed; + var len = buffer.Length; + for (var i = 0; i < len; i++) { - return Compute(DefaultSeed, buffer); - } - - public static UInt64 Compute(UInt64 seed, byte[] buffer) - { - Table ??= CreateTable(Iso3309Polynomial); - - return CalculateHash(seed, Table, buffer); - } - - public static UInt64 CalculateHash(UInt64 seed, UInt64[] table, ReadOnlySpan buffer) - { - var crc = seed; - int len = buffer.Length; - for (var i = 0; i < len; i++) + unchecked { - unchecked + crc = (crc >> 8) ^ table[(buffer[i] ^ crc) & 0xff]; + } + } + + return crc; + } + + public static ulong[] CreateTable(ulong polynomial) + { + var createTable = new ulong[256]; + for (var i = 0; i < 256; ++i) + { + var entry = (ulong)i; + for (var j = 0; j < 8; ++j) + { + if ((entry & 1) == 1) { - crc = (crc >> 8) ^ table[(buffer[i] ^ crc) & 0xff]; + entry = (entry >> 1) ^ polynomial; + } + else + { + entry >>= 1; } } - return crc; - } - - public static ulong[] CreateTable(ulong polynomial) - { - var createTable = new UInt64[256]; - for (var i = 0; i < 256; ++i) - { - var entry = (UInt64)i; - for (var j = 0; j < 8; ++j) - { - if ((entry & 1) == 1) - { - entry = (entry >> 1) ^ polynomial; - } - else - { - entry = entry >> 1; - } - } - - createTable[i] = entry; - } - return createTable; + createTable[i] = entry; } + return createTable; } } diff --git a/src/SharpCompress/Compressors/Xz/Filters/ArmFilter.cs b/src/SharpCompress/Compressors/Xz/Filters/ArmFilter.cs index cefc1137..e30109f1 100644 --- a/src/SharpCompress/Compressors/Xz/Filters/ArmFilter.cs +++ b/src/SharpCompress/Compressors/Xz/Filters/ArmFilter.cs @@ -4,62 +4,56 @@ * @TODO Properties offset */ -using System; -using System.Collections.Generic; using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using SharpCompress.Compressors.Filters; -namespace SharpCompress.Compressors.Xz.Filters +namespace SharpCompress.Compressors.Xz.Filters; + +public class ArmFilter : BlockFilter { - public class ArmFilter : BlockFilter + public override bool AllowAsLast => false; + + public override bool AllowAsNonLast => true; + + public override bool ChangesDataSize => false; + + private uint _ip = 0; + + //private UInt32 _offset = 0; + + public override void Init(byte[] properties) { - public override bool AllowAsLast => false; - - public override bool AllowAsNonLast => true; - - public override bool ChangesDataSize => false; - - private UInt32 _ip = 0; - - //private UInt32 _offset = 0; - - public override void Init(byte[] properties) + if (properties.Length != 0 && properties.Length != 4) { - if (properties.Length != 0 && properties.Length != 4) - { - throw new InvalidDataException("ARM properties unexpected length"); - } - - if (properties.Length == 4) - { - // Even XZ doesn't support it. - throw new InvalidDataException("ARM properties offset is not supported"); - - //_offset = BitConverter.ToUInt32(properties, 0); - // - //if (_offset % (UInt32)BranchExec.Alignment.ARCH_ARM_ALIGNMENT != 0) - //{ - // throw new InvalidDataException("Filter offset does not match alignment"); - //} - } + throw new InvalidDataException("ARM properties unexpected length"); } - public override void ValidateFilter() { } - - public override int Read(byte[] buffer, int offset, int count) + if (properties.Length == 4) { - int bytesRead = BaseStream.Read(buffer, offset, count); - BranchExecFilter.ARMConverter(buffer, _ip); - _ip += (UInt32)bytesRead; - return bytesRead; - } + // Even XZ doesn't support it. + throw new InvalidDataException("ARM properties offset is not supported"); - public override void SetBaseStream(Stream stream) - { - BaseStream = stream; + //_offset = BitConverter.ToUInt32(properties, 0); + // + //if (_offset % (UInt32)BranchExec.Alignment.ARCH_ARM_ALIGNMENT != 0) + //{ + // throw new InvalidDataException("Filter offset does not match alignment"); + //} } } + + public override void ValidateFilter() { } + + public override int Read(byte[] buffer, int offset, int count) + { + var bytesRead = BaseStream.Read(buffer, offset, count); + BranchExecFilter.ARMConverter(buffer, _ip); + _ip += (uint)bytesRead; + return bytesRead; + } + + public override void SetBaseStream(Stream stream) + { + BaseStream = stream; + } } diff --git a/src/SharpCompress/Compressors/Xz/Filters/ArmThumbFilter.cs b/src/SharpCompress/Compressors/Xz/Filters/ArmThumbFilter.cs index 3a70f6f7..586e3779 100644 --- a/src/SharpCompress/Compressors/Xz/Filters/ArmThumbFilter.cs +++ b/src/SharpCompress/Compressors/Xz/Filters/ArmThumbFilter.cs @@ -4,62 +4,56 @@ * @TODO Properties offset */ -using System; -using System.Collections.Generic; using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using SharpCompress.Compressors.Filters; -namespace SharpCompress.Compressors.Xz.Filters +namespace SharpCompress.Compressors.Xz.Filters; + +public class ArmThumbFilter : BlockFilter { - public class ArmThumbFilter : BlockFilter + public override bool AllowAsLast => false; + + public override bool AllowAsNonLast => true; + + public override bool ChangesDataSize => false; + + private uint _ip = 0; + + //private UInt32 _offset = 0; + + public override void Init(byte[] properties) { - public override bool AllowAsLast => false; - - public override bool AllowAsNonLast => true; - - public override bool ChangesDataSize => false; - - private UInt32 _ip = 0; - - //private UInt32 _offset = 0; - - public override void Init(byte[] properties) + if (properties.Length != 0 && properties.Length != 4) { - if (properties.Length != 0 && properties.Length != 4) - { - throw new InvalidDataException("ARM Thumb properties unexpected length"); - } - - if (properties.Length == 4) - { - // Even XZ doesn't support it. - throw new InvalidDataException("ARM Thumb properties offset is not supported"); - - //_offset = BitConverter.ToUInt32(properties, 0); - // - //if (_offset % (UInt32)BranchExec.Alignment.ARCH_ARMTHUMB_ALIGNMENT != 0) - //{ - // throw new InvalidDataException("Filter offset does not match alignment"); - //} - } + throw new InvalidDataException("ARM Thumb properties unexpected length"); } - public override void ValidateFilter() { } - - public override int Read(byte[] buffer, int offset, int count) + if (properties.Length == 4) { - int bytesRead = BaseStream.Read(buffer, offset, count); - BranchExecFilter.ARMTConverter(buffer, _ip); - _ip += (UInt32)bytesRead; - return bytesRead; - } + // Even XZ doesn't support it. + throw new InvalidDataException("ARM Thumb properties offset is not supported"); - public override void SetBaseStream(Stream stream) - { - BaseStream = stream; + //_offset = BitConverter.ToUInt32(properties, 0); + // + //if (_offset % (UInt32)BranchExec.Alignment.ARCH_ARMTHUMB_ALIGNMENT != 0) + //{ + // throw new InvalidDataException("Filter offset does not match alignment"); + //} } } + + public override void ValidateFilter() { } + + public override int Read(byte[] buffer, int offset, int count) + { + var bytesRead = BaseStream.Read(buffer, offset, count); + BranchExecFilter.ARMTConverter(buffer, _ip); + _ip += (uint)bytesRead; + return bytesRead; + } + + public override void SetBaseStream(Stream stream) + { + BaseStream = stream; + } } diff --git a/src/SharpCompress/Compressors/Xz/Filters/BlockFilter.cs b/src/SharpCompress/Compressors/Xz/Filters/BlockFilter.cs index 79eddaaa..f141f4f2 100644 --- a/src/SharpCompress/Compressors/Xz/Filters/BlockFilter.cs +++ b/src/SharpCompress/Compressors/Xz/Filters/BlockFilter.cs @@ -2,67 +2,66 @@ using System; using System.Collections.Generic; using System.IO; -namespace SharpCompress.Compressors.Xz.Filters +namespace SharpCompress.Compressors.Xz.Filters; + +public abstract class BlockFilter : ReadOnlyStream { - public abstract class BlockFilter : ReadOnlyStream + [CLSCompliant(false)] + public enum FilterTypes : ulong { - [CLSCompliant(false)] - public enum FilterTypes : ulong - { - DELTA = 0x03, - ARCH_x86_FILTER = 0x04, - ARCH_PowerPC_FILTER = 0x05, - ARCH_IA64_FILTER = 0x06, - ARCH_ARM_FILTER = 0x07, - ARCH_ARMTHUMB_FILTER = 0x08, - ARCH_SPARC_FILTER = 0x09, - LZMA2 = 0x21 - } - - private static readonly Dictionary FilterMap = new Dictionary< - FilterTypes, - Type - > - { - { FilterTypes.ARCH_x86_FILTER, typeof(X86Filter) }, - { FilterTypes.ARCH_PowerPC_FILTER, typeof(PowerPCFilter) }, - { FilterTypes.ARCH_IA64_FILTER, typeof(IA64Filter) }, - { FilterTypes.ARCH_ARM_FILTER, typeof(ArmFilter) }, - { FilterTypes.ARCH_ARMTHUMB_FILTER, typeof(ArmThumbFilter) }, - { FilterTypes.ARCH_SPARC_FILTER, typeof(SparcFilter) }, - { FilterTypes.LZMA2, typeof(Lzma2Filter) } - }; - - public abstract bool AllowAsLast { get; } - public abstract bool AllowAsNonLast { get; } - public abstract bool ChangesDataSize { get; } - - public abstract void Init(byte[] properties); - public abstract void ValidateFilter(); - - public static BlockFilter Read(BinaryReader reader) - { - var filterType = (FilterTypes)reader.ReadXZInteger(); - if (!FilterMap.ContainsKey(filterType)) - { - throw new NotImplementedException( - $"Filter {filterType} has not yet been implemented" - ); - } - - var filter = (BlockFilter)Activator.CreateInstance(FilterMap[filterType])!; - - var sizeOfProperties = reader.ReadXZInteger(); - if (sizeOfProperties > int.MaxValue) - { - throw new InvalidDataException("Block filter information too large"); - } - - byte[] properties = reader.ReadBytes((int)sizeOfProperties); - filter.Init(properties); - return filter; - } - - public abstract void SetBaseStream(Stream stream); + DELTA = 0x03, + ARCH_x86_FILTER = 0x04, + ARCH_PowerPC_FILTER = 0x05, + ARCH_IA64_FILTER = 0x06, + ARCH_ARM_FILTER = 0x07, + ARCH_ARMTHUMB_FILTER = 0x08, + ARCH_SPARC_FILTER = 0x09, + LZMA2 = 0x21 } + + private static readonly Dictionary FilterMap = new Dictionary< + FilterTypes, + Type + > + { + { FilterTypes.ARCH_x86_FILTER, typeof(X86Filter) }, + { FilterTypes.ARCH_PowerPC_FILTER, typeof(PowerPCFilter) }, + { FilterTypes.ARCH_IA64_FILTER, typeof(IA64Filter) }, + { FilterTypes.ARCH_ARM_FILTER, typeof(ArmFilter) }, + { FilterTypes.ARCH_ARMTHUMB_FILTER, typeof(ArmThumbFilter) }, + { FilterTypes.ARCH_SPARC_FILTER, typeof(SparcFilter) }, + { FilterTypes.LZMA2, typeof(Lzma2Filter) } + }; + + public abstract bool AllowAsLast { get; } + public abstract bool AllowAsNonLast { get; } + public abstract bool ChangesDataSize { get; } + + public abstract void Init(byte[] properties); + public abstract void ValidateFilter(); + + public static BlockFilter Read(BinaryReader reader) + { + var filterType = (FilterTypes)reader.ReadXZInteger(); + if (!FilterMap.ContainsKey(filterType)) + { + throw new NotImplementedException( + $"Filter {filterType} has not yet been implemented" + ); + } + + var filter = (BlockFilter)Activator.CreateInstance(FilterMap[filterType])!; + + var sizeOfProperties = reader.ReadXZInteger(); + if (sizeOfProperties > int.MaxValue) + { + throw new InvalidDataException("Block filter information too large"); + } + + var properties = reader.ReadBytes((int)sizeOfProperties); + filter.Init(properties); + return filter; + } + + public abstract void SetBaseStream(Stream stream); } diff --git a/src/SharpCompress/Compressors/Xz/Filters/IA64Filter.cs b/src/SharpCompress/Compressors/Xz/Filters/IA64Filter.cs index 7c78ef26..b1f1b66c 100644 --- a/src/SharpCompress/Compressors/Xz/Filters/IA64Filter.cs +++ b/src/SharpCompress/Compressors/Xz/Filters/IA64Filter.cs @@ -4,62 +4,56 @@ * @TODO Properties offset */ -using System; -using System.Collections.Generic; using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using SharpCompress.Compressors.Filters; -namespace SharpCompress.Compressors.Xz.Filters +namespace SharpCompress.Compressors.Xz.Filters; + +public class IA64Filter : BlockFilter { - public class IA64Filter : BlockFilter + public override bool AllowAsLast => false; + + public override bool AllowAsNonLast => true; + + public override bool ChangesDataSize => false; + + private uint _ip = 0; + + //private UInt32 _offset = 0; + + public override void Init(byte[] properties) { - public override bool AllowAsLast => false; - - public override bool AllowAsNonLast => true; - - public override bool ChangesDataSize => false; - - private UInt32 _ip = 0; - - //private UInt32 _offset = 0; - - public override void Init(byte[] properties) + if (properties.Length != 0 && properties.Length != 4) { - if (properties.Length != 0 && properties.Length != 4) - { - throw new InvalidDataException("IA64 properties unexpected length"); - } - - if (properties.Length == 4) - { - // Even XZ doesn't support it. - throw new InvalidDataException("IA64 properties offset is not supported"); - - //_offset = BitConverter.ToUInt32(properties, 0); - // - //if (_offset % (UInt32)BranchExec.Alignment.ARCH_IA64_ALIGNMENT != 0) - //{ - // throw new InvalidDataException("Filter offset does not match alignment"); - //} - } + throw new InvalidDataException("IA64 properties unexpected length"); } - public override void ValidateFilter() { } - - public override int Read(byte[] buffer, int offset, int count) + if (properties.Length == 4) { - int bytesRead = BaseStream.Read(buffer, offset, count); - BranchExecFilter.IA64Converter(buffer, _ip); - _ip += (UInt32)bytesRead; - return bytesRead; - } + // Even XZ doesn't support it. + throw new InvalidDataException("IA64 properties offset is not supported"); - public override void SetBaseStream(Stream stream) - { - BaseStream = stream; + //_offset = BitConverter.ToUInt32(properties, 0); + // + //if (_offset % (UInt32)BranchExec.Alignment.ARCH_IA64_ALIGNMENT != 0) + //{ + // throw new InvalidDataException("Filter offset does not match alignment"); + //} } } + + public override void ValidateFilter() { } + + public override int Read(byte[] buffer, int offset, int count) + { + var bytesRead = BaseStream.Read(buffer, offset, count); + BranchExecFilter.IA64Converter(buffer, _ip); + _ip += (uint)bytesRead; + return bytesRead; + } + + public override void SetBaseStream(Stream stream) + { + BaseStream = stream; + } } diff --git a/src/SharpCompress/Compressors/Xz/Filters/Lzma2Filter.cs b/src/SharpCompress/Compressors/Xz/Filters/Lzma2Filter.cs index be1f9ff4..7b4a2a1c 100644 --- a/src/SharpCompress/Compressors/Xz/Filters/Lzma2Filter.cs +++ b/src/SharpCompress/Compressors/Xz/Filters/Lzma2Filter.cs @@ -1,66 +1,65 @@ -using System; +using System; using System.IO; using SharpCompress.Compressors.LZMA; -namespace SharpCompress.Compressors.Xz.Filters +namespace SharpCompress.Compressors.Xz.Filters; + +[CLSCompliant(false)] +public class Lzma2Filter : BlockFilter { - [CLSCompliant(false)] - public class Lzma2Filter : BlockFilter + public override bool AllowAsLast => true; + public override bool AllowAsNonLast => false; + public override bool ChangesDataSize => true; + + private byte _dictionarySize; + public uint DictionarySize { - public override bool AllowAsLast => true; - public override bool AllowAsNonLast => false; - public override bool ChangesDataSize => true; - - private byte _dictionarySize; - public uint DictionarySize + get { - get + if (_dictionarySize > 40) { - if (_dictionarySize > 40) - { - throw new OverflowException("Dictionary size greater than UInt32.Max"); - } - - if (_dictionarySize == 40) - { - return uint.MaxValue; - } - int mantissa = 2 | (_dictionarySize & 1); - int exponent = _dictionarySize / 2 + 11; - return (uint)mantissa << exponent; - } - } - - public override void Init(byte[] properties) - { - if (properties.Length != 1) - { - throw new InvalidDataException("LZMA properties unexpected length"); + throw new OverflowException("Dictionary size greater than UInt32.Max"); } - _dictionarySize = (byte)(properties[0] & 0x3F); - var reserved = properties[0] & 0xC0; - if (reserved != 0) + if (_dictionarySize == 40) { - throw new InvalidDataException("Reserved bits used in LZMA properties"); + return uint.MaxValue; } - } - - public override void ValidateFilter() { } - - public override void SetBaseStream(Stream stream) - { - BaseStream = new LzmaStream(new[] { _dictionarySize }, stream); - } - - public override int Read(byte[] buffer, int offset, int count) - { - return BaseStream.Read(buffer, offset, count); - } - - public override int ReadByte() - { - return BaseStream.ReadByte(); + var mantissa = 2 | (_dictionarySize & 1); + var exponent = (_dictionarySize / 2) + 11; + return (uint)mantissa << exponent; } } + + public override void Init(byte[] properties) + { + if (properties.Length != 1) + { + throw new InvalidDataException("LZMA properties unexpected length"); + } + + _dictionarySize = (byte)(properties[0] & 0x3F); + var reserved = properties[0] & 0xC0; + if (reserved != 0) + { + throw new InvalidDataException("Reserved bits used in LZMA properties"); + } + } + + public override void ValidateFilter() { } + + public override void SetBaseStream(Stream stream) + { + BaseStream = new LzmaStream(new[] { _dictionarySize }, stream); + } + + public override int Read(byte[] buffer, int offset, int count) + { + return BaseStream.Read(buffer, offset, count); + } + + public override int ReadByte() + { + return BaseStream.ReadByte(); + } } diff --git a/src/SharpCompress/Compressors/Xz/Filters/PowerPCFilter.cs b/src/SharpCompress/Compressors/Xz/Filters/PowerPCFilter.cs index b9566c35..dfd7caa1 100644 --- a/src/SharpCompress/Compressors/Xz/Filters/PowerPCFilter.cs +++ b/src/SharpCompress/Compressors/Xz/Filters/PowerPCFilter.cs @@ -4,62 +4,56 @@ * @TODO Properties offset */ -using System; -using System.Collections.Generic; using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using SharpCompress.Compressors.Filters; -namespace SharpCompress.Compressors.Xz.Filters +namespace SharpCompress.Compressors.Xz.Filters; + +public class PowerPCFilter : BlockFilter { - public class PowerPCFilter : BlockFilter + public override bool AllowAsLast => false; + + public override bool AllowAsNonLast => true; + + public override bool ChangesDataSize => false; + + private uint _ip = 0; + + //private UInt32 _offset = 0; + + public override void Init(byte[] properties) { - public override bool AllowAsLast => false; - - public override bool AllowAsNonLast => true; - - public override bool ChangesDataSize => false; - - private UInt32 _ip = 0; - - //private UInt32 _offset = 0; - - public override void Init(byte[] properties) + if (properties.Length != 0 && properties.Length != 4) { - if (properties.Length != 0 && properties.Length != 4) - { - throw new InvalidDataException("PPC properties unexpected length"); - } - - if (properties.Length == 4) - { - // Even XZ doesn't support it. - throw new InvalidDataException("PPC properties offset is not supported"); - - //_offset = BitConverter.ToUInt32(properties, 0); - // - //if (_offset % (UInt32)BranchExec.Alignment.ARCH_PowerPC_ALIGNMENT != 0) - //{ - // throw new InvalidDataException("Filter offset does not match alignment"); - //} - } + throw new InvalidDataException("PPC properties unexpected length"); } - public override void ValidateFilter() { } - - public override int Read(byte[] buffer, int offset, int count) + if (properties.Length == 4) { - int bytesRead = BaseStream.Read(buffer, offset, count); - BranchExecFilter.PowerPCConverter(buffer, _ip); - _ip += (UInt32)bytesRead; - return bytesRead; - } + // Even XZ doesn't support it. + throw new InvalidDataException("PPC properties offset is not supported"); - public override void SetBaseStream(Stream stream) - { - BaseStream = stream; + //_offset = BitConverter.ToUInt32(properties, 0); + // + //if (_offset % (UInt32)BranchExec.Alignment.ARCH_PowerPC_ALIGNMENT != 0) + //{ + // throw new InvalidDataException("Filter offset does not match alignment"); + //} } } + + public override void ValidateFilter() { } + + public override int Read(byte[] buffer, int offset, int count) + { + var bytesRead = BaseStream.Read(buffer, offset, count); + BranchExecFilter.PowerPCConverter(buffer, _ip); + _ip += (uint)bytesRead; + return bytesRead; + } + + public override void SetBaseStream(Stream stream) + { + BaseStream = stream; + } } diff --git a/src/SharpCompress/Compressors/Xz/Filters/SparcFilter.cs b/src/SharpCompress/Compressors/Xz/Filters/SparcFilter.cs index 1b7d4edd..141acb46 100644 --- a/src/SharpCompress/Compressors/Xz/Filters/SparcFilter.cs +++ b/src/SharpCompress/Compressors/Xz/Filters/SparcFilter.cs @@ -4,62 +4,56 @@ * @TODO Properties offset */ -using System; -using System.Collections.Generic; using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using SharpCompress.Compressors.Filters; -namespace SharpCompress.Compressors.Xz.Filters +namespace SharpCompress.Compressors.Xz.Filters; + +public class SparcFilter : BlockFilter { - public class SparcFilter : BlockFilter + public override bool AllowAsLast => false; + + public override bool AllowAsNonLast => true; + + public override bool ChangesDataSize => false; + + private uint _ip = 0; + + //private UInt32 _offset = 0; + + public override void Init(byte[] properties) { - public override bool AllowAsLast => false; - - public override bool AllowAsNonLast => true; - - public override bool ChangesDataSize => false; - - private UInt32 _ip = 0; - - //private UInt32 _offset = 0; - - public override void Init(byte[] properties) + if (properties.Length != 0 && properties.Length != 4) { - if (properties.Length != 0 && properties.Length != 4) - { - throw new InvalidDataException("SPARC properties unexpected length"); - } - - if (properties.Length == 4) - { - // Even XZ doesn't support it. - throw new InvalidDataException("SPARC properties offset is not supported"); - - //_offset = BitConverter.ToUInt32(properties, 0); - // - //if (_offset % (UInt32)BranchExec.Alignment.ARCH_SPARC_ALIGNMENT != 0) - //{ - // throw new InvalidDataException("Filter offset does not match alignment"); - //} - } + throw new InvalidDataException("SPARC properties unexpected length"); } - public override void ValidateFilter() { } - - public override int Read(byte[] buffer, int offset, int count) + if (properties.Length == 4) { - int bytesRead = BaseStream.Read(buffer, offset, count); - BranchExecFilter.SPARCConverter(buffer, _ip); - _ip += (UInt32)bytesRead; - return bytesRead; - } + // Even XZ doesn't support it. + throw new InvalidDataException("SPARC properties offset is not supported"); - public override void SetBaseStream(Stream stream) - { - BaseStream = stream; + //_offset = BitConverter.ToUInt32(properties, 0); + // + //if (_offset % (UInt32)BranchExec.Alignment.ARCH_SPARC_ALIGNMENT != 0) + //{ + // throw new InvalidDataException("Filter offset does not match alignment"); + //} } } + + public override void ValidateFilter() { } + + public override int Read(byte[] buffer, int offset, int count) + { + var bytesRead = BaseStream.Read(buffer, offset, count); + BranchExecFilter.SPARCConverter(buffer, _ip); + _ip += (uint)bytesRead; + return bytesRead; + } + + public override void SetBaseStream(Stream stream) + { + BaseStream = stream; + } } diff --git a/src/SharpCompress/Compressors/Xz/Filters/X86Filter.cs b/src/SharpCompress/Compressors/Xz/Filters/X86Filter.cs index 46d5837a..2713a344 100644 --- a/src/SharpCompress/Compressors/Xz/Filters/X86Filter.cs +++ b/src/SharpCompress/Compressors/Xz/Filters/X86Filter.cs @@ -4,64 +4,58 @@ * @TODO Properties offset */ -using System; -using System.Collections.Generic; using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using SharpCompress.Compressors.Filters; -namespace SharpCompress.Compressors.Xz.Filters +namespace SharpCompress.Compressors.Xz.Filters; + +public class X86Filter : BlockFilter { - public class X86Filter : BlockFilter + public override bool AllowAsLast => false; + + public override bool AllowAsNonLast => true; + + public override bool ChangesDataSize => false; + + private uint _ip = 0; + + private uint _state = 0; + + //private UInt32 _offset = 0; + + public override void Init(byte[] properties) { - public override bool AllowAsLast => false; - - public override bool AllowAsNonLast => true; - - public override bool ChangesDataSize => false; - - private UInt32 _ip = 0; - - private UInt32 _state = 0; - - //private UInt32 _offset = 0; - - public override void Init(byte[] properties) + if (properties.Length != 0 && properties.Length != 4) { - if (properties.Length != 0 && properties.Length != 4) - { - throw new InvalidDataException("X86 properties unexpected length"); - } - - if (properties.Length == 4) - { - // Even XZ doesn't support it. - throw new InvalidDataException("X86 properties offset is not supported"); - - //_offset = BitConverter.ToUInt32(properties, 0); - // - //if (_offset % (UInt32)BranchExec.Alignment.ARCH_x86_ALIGNMENT != 0) - //{ - // throw new InvalidDataException("Filter offset does not match alignment"); - //} - } + throw new InvalidDataException("X86 properties unexpected length"); } - public override void ValidateFilter() { } - - public override int Read(byte[] buffer, int offset, int count) + if (properties.Length == 4) { - int bytesRead = BaseStream.Read(buffer, offset, count); - BranchExecFilter.X86Converter(buffer, _ip, ref _state); - _ip += (UInt32)bytesRead; - return bytesRead; - } + // Even XZ doesn't support it. + throw new InvalidDataException("X86 properties offset is not supported"); - public override void SetBaseStream(Stream stream) - { - BaseStream = stream; + //_offset = BitConverter.ToUInt32(properties, 0); + // + //if (_offset % (UInt32)BranchExec.Alignment.ARCH_x86_ALIGNMENT != 0) + //{ + // throw new InvalidDataException("Filter offset does not match alignment"); + //} } } + + public override void ValidateFilter() { } + + public override int Read(byte[] buffer, int offset, int count) + { + var bytesRead = BaseStream.Read(buffer, offset, count); + BranchExecFilter.X86Converter(buffer, _ip, ref _state); + _ip += (uint)bytesRead; + return bytesRead; + } + + public override void SetBaseStream(Stream stream) + { + BaseStream = stream; + } } diff --git a/src/SharpCompress/Compressors/Xz/MultiByteIntegers.cs b/src/SharpCompress/Compressors/Xz/MultiByteIntegers.cs index 27f94644..a38505da 100644 --- a/src/SharpCompress/Compressors/Xz/MultiByteIntegers.cs +++ b/src/SharpCompress/Compressors/Xz/MultiByteIntegers.cs @@ -1,42 +1,41 @@ -using System; +using System; using System.IO; -namespace SharpCompress.Compressors.Xz +namespace SharpCompress.Compressors.Xz; + +internal static class MultiByteIntegers { - internal static class MultiByteIntegers + public static ulong ReadXZInteger(this BinaryReader reader, int MaxBytes = 9) { - public static ulong ReadXZInteger(this BinaryReader reader, int MaxBytes = 9) + if (MaxBytes <= 0) { - if (MaxBytes <= 0) - { - throw new ArgumentOutOfRangeException(nameof(MaxBytes)); - } - - if (MaxBytes > 9) - { - MaxBytes = 9; - } - - byte LastByte = reader.ReadByte(); - ulong Output = (ulong)LastByte & 0x7F; - - int i = 0; - while ((LastByte & 0x80) != 0) - { - if (++i >= MaxBytes) - { - throw new InvalidDataException(); - } - - LastByte = reader.ReadByte(); - if (LastByte == 0) - { - throw new InvalidDataException(); - } - - Output |= ((ulong)(LastByte & 0x7F)) << (i * 7); - } - return Output; + throw new ArgumentOutOfRangeException(nameof(MaxBytes)); } + + if (MaxBytes > 9) + { + MaxBytes = 9; + } + + var LastByte = reader.ReadByte(); + var Output = (ulong)LastByte & 0x7F; + + var i = 0; + while ((LastByte & 0x80) != 0) + { + if (++i >= MaxBytes) + { + throw new InvalidDataException(); + } + + LastByte = reader.ReadByte(); + if (LastByte == 0) + { + throw new InvalidDataException(); + } + + Output |= ((ulong)(LastByte & 0x7F)) << (i * 7); + } + return Output; } } diff --git a/src/SharpCompress/Compressors/Xz/ReadOnlyStream.cs b/src/SharpCompress/Compressors/Xz/ReadOnlyStream.cs index 0c1b53b4..c890b22d 100644 --- a/src/SharpCompress/Compressors/Xz/ReadOnlyStream.cs +++ b/src/SharpCompress/Compressors/Xz/ReadOnlyStream.cs @@ -1,46 +1,45 @@ -#nullable disable +#nullable disable using System; using System.IO; -namespace SharpCompress.Compressors.Xz +namespace SharpCompress.Compressors.Xz; + +public abstract class ReadOnlyStream : Stream { - public abstract class ReadOnlyStream : Stream + public Stream BaseStream { get; protected set; } + + public override bool CanRead => BaseStream.CanRead; + + public override bool CanSeek => false; + + public override bool CanWrite => false; + + public override long Length => throw new NotSupportedException(); + + public override long Position { - public Stream BaseStream { get; protected set; } + get => throw new NotSupportedException(); + set => throw new NotSupportedException(); + } - public override bool CanRead => BaseStream.CanRead; + public override void Flush() + { + throw new NotSupportedException(); + } - public override bool CanSeek => false; + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } - public override bool CanWrite => false; + public override void SetLength(long value) + { + throw new NotSupportedException(); + } - public override long Length => throw new NotSupportedException(); - - public override long Position - { - get => throw new NotSupportedException(); - set => throw new NotSupportedException(); - } - - public override void Flush() - { - throw new NotSupportedException(); - } - - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } - - public override void SetLength(long value) - { - throw new NotSupportedException(); - } - - public override void Write(byte[] buffer, int offset, int count) - { - throw new NotSupportedException(); - } + public override void Write(byte[] buffer, int offset, int count) + { + throw new NotSupportedException(); } } diff --git a/src/SharpCompress/Compressors/Xz/XZBlock.cs b/src/SharpCompress/Compressors/Xz/XZBlock.cs index 38409ecf..5b948500 100644 --- a/src/SharpCompress/Compressors/Xz/XZBlock.cs +++ b/src/SharpCompress/Compressors/Xz/XZBlock.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable using System; using System.Collections.Generic; @@ -6,213 +6,212 @@ using System.IO; using System.Linq; using SharpCompress.Compressors.Xz.Filters; -namespace SharpCompress.Compressors.Xz +namespace SharpCompress.Compressors.Xz; + +[CLSCompliant(false)] +public sealed class XZBlock : XZReadOnlyStream { - [CLSCompliant(false)] - public sealed class XZBlock : XZReadOnlyStream + public int BlockHeaderSize => (_blockHeaderSizeByte + 1) * 4; + public ulong? CompressedSize { get; private set; } + public ulong? UncompressedSize { get; private set; } + public Stack Filters { get; private set; } = new Stack(); + public bool HeaderIsLoaded { get; private set; } + private CheckType _checkType; + private readonly int _checkSize; + private bool _streamConnected; + private int _numFilters; + private byte _blockHeaderSizeByte; + private Stream _decomStream; + private bool _endOfStream; + private bool _paddingSkipped; + private bool _crcChecked; + private ulong _bytesRead; + + public XZBlock(Stream stream, CheckType checkType, int checkSize) : base(stream) { - public int BlockHeaderSize => (_blockHeaderSizeByte + 1) * 4; - public ulong? CompressedSize { get; private set; } - public ulong? UncompressedSize { get; private set; } - public Stack Filters { get; private set; } = new Stack(); - public bool HeaderIsLoaded { get; private set; } - private CheckType _checkType; - private readonly int _checkSize; - private bool _streamConnected; - private int _numFilters; - private byte _blockHeaderSizeByte; - private Stream _decomStream; - private bool _endOfStream; - private bool _paddingSkipped; - private bool _crcChecked; - private ulong _bytesRead; + _checkType = checkType; + _checkSize = checkSize; + } - public XZBlock(Stream stream, CheckType checkType, int checkSize) : base(stream) + public override int Read(byte[] buffer, int offset, int count) + { + var bytesRead = 0; + if (!HeaderIsLoaded) { - _checkType = checkType; - _checkSize = checkSize; + LoadHeader(); } - public override int Read(byte[] buffer, int offset, int count) + if (!_streamConnected) { - int bytesRead = 0; - if (!HeaderIsLoaded) - { - LoadHeader(); - } - - if (!_streamConnected) - { - ConnectStream(); - } - - if (!_endOfStream) - { - bytesRead = _decomStream.Read(buffer, offset, count); - } - - if (bytesRead != count) - { - _endOfStream = true; - } - - if (_endOfStream && !_paddingSkipped) - { - SkipPadding(); - } - - if (_endOfStream && !_crcChecked) - { - CheckCrc(); - } - - _bytesRead += (ulong)bytesRead; - return bytesRead; + ConnectStream(); } - private void SkipPadding() + if (!_endOfStream) { - int bytes = (int)(BaseStream.Position % 4); - if (bytes > 0) - { - byte[] paddingBytes = new byte[4 - bytes]; - BaseStream.Read(paddingBytes, 0, paddingBytes.Length); - if (paddingBytes.Any(b => b != 0)) - { - throw new InvalidDataException("Padding bytes were non-null"); - } - } - _paddingSkipped = true; + bytesRead = _decomStream.Read(buffer, offset, count); } - private void CheckCrc() + if (bytesRead != count) { - byte[] crc = new byte[_checkSize]; - BaseStream.Read(crc, 0, _checkSize); - // Actually do a check (and read in the bytes - // into the function throughout the stream read). - _crcChecked = true; + _endOfStream = true; } - private void ConnectStream() + if (_endOfStream && !_paddingSkipped) { - _decomStream = BaseStream; - while (Filters.Any()) - { - BlockFilter filter = Filters.Pop(); - filter.SetBaseStream(_decomStream); - _decomStream = filter; - } - _streamConnected = true; + SkipPadding(); } - private void LoadHeader() + if (_endOfStream && !_crcChecked) { - ReadHeaderSize(); - byte[] headerCache = CacheHeader(); - - using (var cache = new MemoryStream(headerCache)) - using (var cachedReader = new BinaryReader(cache)) - { - cachedReader.BaseStream.Position = 1; // skip the header size byte - ReadBlockFlags(cachedReader); - ReadFilters(cachedReader); - } - HeaderIsLoaded = true; + CheckCrc(); } - private void ReadHeaderSize() + _bytesRead += (ulong)bytesRead; + return bytesRead; + } + + private void SkipPadding() + { + var bytes = (int)(BaseStream.Position % 4); + if (bytes > 0) { - _blockHeaderSizeByte = (byte)BaseStream.ReadByte(); - if (_blockHeaderSizeByte == 0) + var paddingBytes = new byte[4 - bytes]; + BaseStream.Read(paddingBytes, 0, paddingBytes.Length); + if (paddingBytes.Any(b => b != 0)) { - throw new XZIndexMarkerReachedException(); + throw new InvalidDataException("Padding bytes were non-null"); } } + _paddingSkipped = true; + } - private byte[] CacheHeader() + private void CheckCrc() + { + var crc = new byte[_checkSize]; + BaseStream.Read(crc, 0, _checkSize); + // Actually do a check (and read in the bytes + // into the function throughout the stream read). + _crcChecked = true; + } + + private void ConnectStream() + { + _decomStream = BaseStream; + while (Filters.Any()) { - byte[] blockHeaderWithoutCrc = new byte[BlockHeaderSize - 4]; - blockHeaderWithoutCrc[0] = _blockHeaderSizeByte; - var read = BaseStream.Read(blockHeaderWithoutCrc, 1, BlockHeaderSize - 5); - if (read != BlockHeaderSize - 5) - { - throw new EndOfStreamException("Reached end of stream unexectedly"); - } + var filter = Filters.Pop(); + filter.SetBaseStream(_decomStream); + _decomStream = filter; + } + _streamConnected = true; + } - uint crc = BaseStream.ReadLittleEndianUInt32(); - uint calcCrc = Crc32.Compute(blockHeaderWithoutCrc); - if (crc != calcCrc) - { - throw new InvalidDataException("Block header corrupt"); - } + private void LoadHeader() + { + ReadHeaderSize(); + var headerCache = CacheHeader(); - return blockHeaderWithoutCrc; + using (var cache = new MemoryStream(headerCache)) + using (var cachedReader = new BinaryReader(cache)) + { + cachedReader.BaseStream.Position = 1; // skip the header size byte + ReadBlockFlags(cachedReader); + ReadFilters(cachedReader); + } + HeaderIsLoaded = true; + } + + private void ReadHeaderSize() + { + _blockHeaderSizeByte = (byte)BaseStream.ReadByte(); + if (_blockHeaderSizeByte == 0) + { + throw new XZIndexMarkerReachedException(); + } + } + + private byte[] CacheHeader() + { + var blockHeaderWithoutCrc = new byte[BlockHeaderSize - 4]; + blockHeaderWithoutCrc[0] = _blockHeaderSizeByte; + var read = BaseStream.Read(blockHeaderWithoutCrc, 1, BlockHeaderSize - 5); + if (read != BlockHeaderSize - 5) + { + throw new EndOfStreamException("Reached end of stream unexectedly"); } - private void ReadBlockFlags(BinaryReader reader) + var crc = BaseStream.ReadLittleEndianUInt32(); + var calcCrc = Crc32.Compute(blockHeaderWithoutCrc); + if (crc != calcCrc) { - var blockFlags = reader.ReadByte(); - _numFilters = (blockFlags & 0x03) + 1; - byte reserved = (byte)(blockFlags & 0x3C); - - if (reserved != 0) - { - throw new InvalidDataException( - "Reserved bytes used, perhaps an unknown XZ implementation" - ); - } - - bool compressedSizePresent = (blockFlags & 0x40) != 0; - bool uncompressedSizePresent = (blockFlags & 0x80) != 0; - - if (compressedSizePresent) - { - CompressedSize = reader.ReadXZInteger(); - } - - if (uncompressedSizePresent) - { - UncompressedSize = reader.ReadXZInteger(); - } + throw new InvalidDataException("Block header corrupt"); } - private void ReadFilters(BinaryReader reader, long baseStreamOffset = 0) + return blockHeaderWithoutCrc; + } + + private void ReadBlockFlags(BinaryReader reader) + { + var blockFlags = reader.ReadByte(); + _numFilters = (blockFlags & 0x03) + 1; + var reserved = (byte)(blockFlags & 0x3C); + + if (reserved != 0) { - int nonLastSizeChangers = 0; - for (int i = 0; i < _numFilters; i++) - { - var filter = BlockFilter.Read(reader); - if ( - (i + 1 == _numFilters && !filter.AllowAsLast) - || (i + 1 < _numFilters && !filter.AllowAsNonLast) - ) - { - throw new InvalidDataException("Block Filters in bad order"); - } + throw new InvalidDataException( + "Reserved bytes used, perhaps an unknown XZ implementation" + ); + } - if (filter.ChangesDataSize && i + 1 < _numFilters) - { - nonLastSizeChangers++; - } + var compressedSizePresent = (blockFlags & 0x40) != 0; + var uncompressedSizePresent = (blockFlags & 0x80) != 0; - filter.ValidateFilter(); - Filters.Push(filter); - } - if (nonLastSizeChangers > 2) + if (compressedSizePresent) + { + CompressedSize = reader.ReadXZInteger(); + } + + if (uncompressedSizePresent) + { + UncompressedSize = reader.ReadXZInteger(); + } + } + + private void ReadFilters(BinaryReader reader, long baseStreamOffset = 0) + { + var nonLastSizeChangers = 0; + for (var i = 0; i < _numFilters; i++) + { + var filter = BlockFilter.Read(reader); + if ( + (i + 1 == _numFilters && !filter.AllowAsLast) + || (i + 1 < _numFilters && !filter.AllowAsNonLast) + ) { - throw new InvalidDataException( - "More than two non-last block filters cannot change stream size" - ); + throw new InvalidDataException("Block Filters in bad order"); } - int blockHeaderPaddingSize = - BlockHeaderSize - (4 + (int)(reader.BaseStream.Position - baseStreamOffset)); - byte[] blockHeaderPadding = reader.ReadBytes(blockHeaderPaddingSize); - if (!blockHeaderPadding.All(b => b == 0)) + if (filter.ChangesDataSize && i + 1 < _numFilters) { - throw new InvalidDataException("Block header contains unknown fields"); + nonLastSizeChangers++; } + + filter.ValidateFilter(); + Filters.Push(filter); + } + if (nonLastSizeChangers > 2) + { + throw new InvalidDataException( + "More than two non-last block filters cannot change stream size" + ); + } + + var blockHeaderPaddingSize = + BlockHeaderSize - (4 + (int)(reader.BaseStream.Position - baseStreamOffset)); + var blockHeaderPadding = reader.ReadBytes(blockHeaderPaddingSize); + if (!blockHeaderPadding.All(b => b == 0)) + { + throw new InvalidDataException("Block header contains unknown fields"); } } } diff --git a/src/SharpCompress/Compressors/Xz/XZFooter.cs b/src/SharpCompress/Compressors/Xz/XZFooter.cs index 40850f31..8632ec7e 100644 --- a/src/SharpCompress/Compressors/Xz/XZFooter.cs +++ b/src/SharpCompress/Compressors/Xz/XZFooter.cs @@ -4,52 +4,51 @@ using System.Linq; using System.Text; using SharpCompress.IO; -namespace SharpCompress.Compressors.Xz +namespace SharpCompress.Compressors.Xz; + +public class XZFooter { - public class XZFooter + private readonly BinaryReader _reader; + private static ReadOnlySpan _magicBytes => "YZ"u8; + public long StreamStartPosition { get; private set; } + public long BackwardSize { get; private set; } + public byte[]? StreamFlags { get; private set; } + + public XZFooter(BinaryReader reader) { - private readonly BinaryReader _reader; - private static ReadOnlySpan _magicBytes => new byte[] { 0x59, 0x5A }; - public long StreamStartPosition { get; private set; } - public long BackwardSize { get; private set; } - public byte[]? StreamFlags { get; private set; } + _reader = reader; + StreamStartPosition = reader.BaseStream.Position; + } - public XZFooter(BinaryReader reader) + public static XZFooter FromStream(Stream stream) + { + var footer = new XZFooter( + new BinaryReader(NonDisposingStream.Create(stream), Encoding.UTF8) + ); + footer.Process(); + return footer; + } + + public void Process() + { + var crc = _reader.ReadLittleEndianUInt32(); + var footerBytes = _reader.ReadBytes(6); + var myCrc = Crc32.Compute(footerBytes); + if (crc != myCrc) { - _reader = reader; - StreamStartPosition = reader.BaseStream.Position; + throw new InvalidDataException("Footer corrupt"); } - public static XZFooter FromStream(Stream stream) + using (var stream = new MemoryStream(footerBytes)) + using (var reader = new BinaryReader(stream)) { - var footer = new XZFooter( - new BinaryReader(NonDisposingStream.Create(stream), Encoding.UTF8) - ); - footer.Process(); - return footer; + BackwardSize = (reader.ReadLittleEndianUInt32() + 1) * 4; + StreamFlags = reader.ReadBytes(2); } - - public void Process() + var magBy = _reader.ReadBytes(2); + if (!magBy.AsSpan().SequenceEqual(_magicBytes)) { - uint crc = _reader.ReadLittleEndianUInt32(); - byte[] footerBytes = _reader.ReadBytes(6); - uint myCrc = Crc32.Compute(footerBytes); - if (crc != myCrc) - { - throw new InvalidDataException("Footer corrupt"); - } - - using (var stream = new MemoryStream(footerBytes)) - using (var reader = new BinaryReader(stream)) - { - BackwardSize = (reader.ReadLittleEndianUInt32() + 1) * 4; - StreamFlags = reader.ReadBytes(2); - } - byte[] magBy = _reader.ReadBytes(2); - if (!magBy.AsSpan().SequenceEqual(_magicBytes)) - { - throw new InvalidDataException("Magic footer missing"); - } + throw new InvalidDataException("Magic footer missing"); } } } diff --git a/src/SharpCompress/Compressors/Xz/XZHeader.cs b/src/SharpCompress/Compressors/Xz/XZHeader.cs index 5968cc62..16277dc6 100644 --- a/src/SharpCompress/Compressors/Xz/XZHeader.cs +++ b/src/SharpCompress/Compressors/Xz/XZHeader.cs @@ -4,60 +4,59 @@ using System.Linq; using System.Text; using SharpCompress.IO; -namespace SharpCompress.Compressors.Xz +namespace SharpCompress.Compressors.Xz; + +public class XZHeader { - public class XZHeader + private readonly BinaryReader _reader; + private readonly byte[] MagicHeader = { 0xFD, 0x37, 0x7A, 0x58, 0x5a, 0x00 }; + + public CheckType BlockCheckType { get; private set; } + public int BlockCheckSize => ((((int)BlockCheckType) + 2) / 3) * 4; + + public XZHeader(BinaryReader reader) { - private readonly BinaryReader _reader; - private readonly byte[] MagicHeader = { 0xFD, 0x37, 0x7A, 0x58, 0x5a, 0x00 }; + _reader = reader; + } - public CheckType BlockCheckType { get; private set; } - public int BlockCheckSize => ((((int)BlockCheckType) + 2) / 3) * 4; + public static XZHeader FromStream(Stream stream) + { + var header = new XZHeader( + new BinaryReader(NonDisposingStream.Create(stream), Encoding.UTF8) + ); + header.Process(); + return header; + } - public XZHeader(BinaryReader reader) + public void Process() + { + CheckMagicBytes(_reader.ReadBytes(6)); + ProcessStreamFlags(); + } + + private void ProcessStreamFlags() + { + var streamFlags = _reader.ReadBytes(2); + var crc = _reader.ReadLittleEndianUInt32(); + var calcCrc = Crc32.Compute(streamFlags); + if (crc != calcCrc) { - _reader = reader; + throw new InvalidDataException("Stream header corrupt"); } - public static XZHeader FromStream(Stream stream) + BlockCheckType = (CheckType)(streamFlags[1] & 0x0F); + var futureUse = (byte)(streamFlags[1] & 0xF0); + if (futureUse != 0 || streamFlags[0] != 0) { - var header = new XZHeader( - new BinaryReader(NonDisposingStream.Create(stream), Encoding.UTF8) - ); - header.Process(); - return header; + throw new InvalidDataException("Unknown XZ Stream Version"); } + } - public void Process() + private void CheckMagicBytes(byte[] header) + { + if (!header.SequenceEqual(MagicHeader)) { - CheckMagicBytes(_reader.ReadBytes(6)); - ProcessStreamFlags(); - } - - private void ProcessStreamFlags() - { - byte[] streamFlags = _reader.ReadBytes(2); - UInt32 crc = _reader.ReadLittleEndianUInt32(); - UInt32 calcCrc = Crc32.Compute(streamFlags); - if (crc != calcCrc) - { - throw new InvalidDataException("Stream header corrupt"); - } - - BlockCheckType = (CheckType)(streamFlags[1] & 0x0F); - byte futureUse = (byte)(streamFlags[1] & 0xF0); - if (futureUse != 0 || streamFlags[0] != 0) - { - throw new InvalidDataException("Unknown XZ Stream Version"); - } - } - - private void CheckMagicBytes(byte[] header) - { - if (!header.SequenceEqual(MagicHeader)) - { - throw new InvalidDataException("Invalid XZ Stream"); - } + throw new InvalidDataException("Invalid XZ Stream"); } } } diff --git a/src/SharpCompress/Compressors/Xz/XZIndex.cs b/src/SharpCompress/Compressors/Xz/XZIndex.cs index 7ad364ce..631f27b2 100644 --- a/src/SharpCompress/Compressors/Xz/XZIndex.cs +++ b/src/SharpCompress/Compressors/Xz/XZIndex.cs @@ -5,81 +5,80 @@ using System.Linq; using System.Text; using SharpCompress.IO; -namespace SharpCompress.Compressors.Xz +namespace SharpCompress.Compressors.Xz; + +[CLSCompliant(false)] +public class XZIndex { - [CLSCompliant(false)] - public class XZIndex + private readonly BinaryReader _reader; + public long StreamStartPosition { get; private set; } + public ulong NumberOfRecords { get; private set; } + public List Records { get; } = new List(); + + private readonly bool _indexMarkerAlreadyVerified; + + public XZIndex(BinaryReader reader, bool indexMarkerAlreadyVerified) { - private readonly BinaryReader _reader; - public long StreamStartPosition { get; private set; } - public ulong NumberOfRecords { get; private set; } - public List Records { get; } = new List(); - - private readonly bool _indexMarkerAlreadyVerified; - - public XZIndex(BinaryReader reader, bool indexMarkerAlreadyVerified) + _reader = reader; + _indexMarkerAlreadyVerified = indexMarkerAlreadyVerified; + StreamStartPosition = reader.BaseStream.Position; + if (indexMarkerAlreadyVerified) { - _reader = reader; - _indexMarkerAlreadyVerified = indexMarkerAlreadyVerified; - StreamStartPosition = reader.BaseStream.Position; - if (indexMarkerAlreadyVerified) - { - StreamStartPosition--; - } - } - - public static XZIndex FromStream(Stream stream, bool indexMarkerAlreadyVerified) - { - var index = new XZIndex( - new BinaryReader(NonDisposingStream.Create(stream), Encoding.UTF8), - indexMarkerAlreadyVerified - ); - index.Process(); - return index; - } - - public void Process() - { - if (!_indexMarkerAlreadyVerified) - { - VerifyIndexMarker(); - } - - NumberOfRecords = _reader.ReadXZInteger(); - for (ulong i = 0; i < NumberOfRecords; i++) - { - Records.Add(XZIndexRecord.FromBinaryReader(_reader)); - } - SkipPadding(); - VerifyCrc32(); - } - - private void VerifyIndexMarker() - { - byte marker = _reader.ReadByte(); - if (marker != 0) - { - throw new InvalidDataException("Not an index block"); - } - } - - private void SkipPadding() - { - int bytes = (int)(_reader.BaseStream.Position - StreamStartPosition) % 4; - if (bytes > 0) - { - byte[] paddingBytes = _reader.ReadBytes(4 - bytes); - if (paddingBytes.Any(b => b != 0)) - { - throw new InvalidDataException("Padding bytes were non-null"); - } - } - } - - private void VerifyCrc32() - { - uint crc = _reader.ReadLittleEndianUInt32(); - // TODO verify this matches + StreamStartPosition--; } } + + public static XZIndex FromStream(Stream stream, bool indexMarkerAlreadyVerified) + { + var index = new XZIndex( + new BinaryReader(NonDisposingStream.Create(stream), Encoding.UTF8), + indexMarkerAlreadyVerified + ); + index.Process(); + return index; + } + + public void Process() + { + if (!_indexMarkerAlreadyVerified) + { + VerifyIndexMarker(); + } + + NumberOfRecords = _reader.ReadXZInteger(); + for (ulong i = 0; i < NumberOfRecords; i++) + { + Records.Add(XZIndexRecord.FromBinaryReader(_reader)); + } + SkipPadding(); + VerifyCrc32(); + } + + private void VerifyIndexMarker() + { + var marker = _reader.ReadByte(); + if (marker != 0) + { + throw new InvalidDataException("Not an index block"); + } + } + + private void SkipPadding() + { + var bytes = (int)(_reader.BaseStream.Position - StreamStartPosition) % 4; + if (bytes > 0) + { + var paddingBytes = _reader.ReadBytes(4 - bytes); + if (paddingBytes.Any(b => b != 0)) + { + throw new InvalidDataException("Padding bytes were non-null"); + } + } + } + + private void VerifyCrc32() + { + var crc = _reader.ReadLittleEndianUInt32(); + // TODO verify this matches + } } diff --git a/src/SharpCompress/Compressors/Xz/XZIndexMarkerReachedException.cs b/src/SharpCompress/Compressors/Xz/XZIndexMarkerReachedException.cs index d5be9a82..bb006a35 100644 --- a/src/SharpCompress/Compressors/Xz/XZIndexMarkerReachedException.cs +++ b/src/SharpCompress/Compressors/Xz/XZIndexMarkerReachedException.cs @@ -1,6 +1,5 @@ -using System; +using System; -namespace SharpCompress.Compressors.Xz -{ - public class XZIndexMarkerReachedException : Exception { } -} +namespace SharpCompress.Compressors.Xz; + +public class XZIndexMarkerReachedException : Exception { } diff --git a/src/SharpCompress/Compressors/Xz/XZIndexRecord.cs b/src/SharpCompress/Compressors/Xz/XZIndexRecord.cs index f0ee443e..e05b988b 100644 --- a/src/SharpCompress/Compressors/Xz/XZIndexRecord.cs +++ b/src/SharpCompress/Compressors/Xz/XZIndexRecord.cs @@ -1,22 +1,21 @@ -using System; +using System; using System.IO; -namespace SharpCompress.Compressors.Xz +namespace SharpCompress.Compressors.Xz; + +[CLSCompliant(false)] +public class XZIndexRecord { - [CLSCompliant(false)] - public class XZIndexRecord + public ulong UnpaddedSize { get; private set; } + public ulong UncompressedSize { get; private set; } + + protected XZIndexRecord() { } + + public static XZIndexRecord FromBinaryReader(BinaryReader br) { - public ulong UnpaddedSize { get; private set; } - public ulong UncompressedSize { get; private set; } - - protected XZIndexRecord() { } - - public static XZIndexRecord FromBinaryReader(BinaryReader br) - { - var record = new XZIndexRecord(); - record.UnpaddedSize = br.ReadXZInteger(); - record.UncompressedSize = br.ReadXZInteger(); - return record; - } + var record = new XZIndexRecord(); + record.UnpaddedSize = br.ReadXZInteger(); + record.UncompressedSize = br.ReadXZInteger(); + return record; } } diff --git a/src/SharpCompress/Compressors/Xz/XZReadOnlyStream.cs b/src/SharpCompress/Compressors/Xz/XZReadOnlyStream.cs index fa376c51..4c1aa02b 100644 --- a/src/SharpCompress/Compressors/Xz/XZReadOnlyStream.cs +++ b/src/SharpCompress/Compressors/Xz/XZReadOnlyStream.cs @@ -1,16 +1,15 @@ -using System.IO; +using System.IO; -namespace SharpCompress.Compressors.Xz +namespace SharpCompress.Compressors.Xz; + +public abstract class XZReadOnlyStream : ReadOnlyStream { - public abstract class XZReadOnlyStream : ReadOnlyStream + public XZReadOnlyStream(Stream stream) { - public XZReadOnlyStream(Stream stream) + BaseStream = stream; + if (!BaseStream.CanRead) { - BaseStream = stream; - if (!BaseStream.CanRead) - { - throw new InvalidDataException("Must be able to read from stream"); - } + throw new InvalidDataException("Must be able to read from stream"); } } } diff --git a/src/SharpCompress/Compressors/Xz/XZStream.cs b/src/SharpCompress/Compressors/Xz/XZStream.cs index 41d968f5..f1157182 100644 --- a/src/SharpCompress/Compressors/Xz/XZStream.cs +++ b/src/SharpCompress/Compressors/Xz/XZStream.cs @@ -1,134 +1,133 @@ -#nullable disable +#nullable disable using System; using System.IO; -namespace SharpCompress.Compressors.Xz +namespace SharpCompress.Compressors.Xz; + +[CLSCompliant(false)] +public sealed class XZStream : XZReadOnlyStream { - [CLSCompliant(false)] - public sealed class XZStream : XZReadOnlyStream + public static bool IsXZStream(Stream stream) { - public static bool IsXZStream(Stream stream) + try + { + return null != XZHeader.FromStream(stream); + } + catch (Exception) + { + return false; + } + } + + private void AssertBlockCheckTypeIsSupported() + { + switch (Header.BlockCheckType) + { + case CheckType.NONE: + break; + case CheckType.CRC32: + break; + case CheckType.CRC64: + break; + case CheckType.SHA256: + throw new NotImplementedException(); + default: + throw new NotSupportedException( + "Check Type unknown to this version of decoder." + ); + } + } + + public XZHeader Header { get; private set; } + public XZIndex Index { get; private set; } + public XZFooter Footer { get; private set; } + public bool HeaderIsRead { get; private set; } + private XZBlock _currentBlock; + + private bool _endOfStream; + + public XZStream(Stream stream) : base(stream) { } + + public override int Read(byte[] buffer, int offset, int count) + { + var bytesRead = 0; + if (_endOfStream) + { + return bytesRead; + } + + if (!HeaderIsRead) + { + ReadHeader(); + } + + bytesRead = ReadBlocks(buffer, offset, count); + if (bytesRead < count) + { + _endOfStream = true; + ReadIndex(); + ReadFooter(); + } + return bytesRead; + } + + private void ReadHeader() + { + Header = XZHeader.FromStream(BaseStream); + AssertBlockCheckTypeIsSupported(); + HeaderIsRead = true; + } + + private void ReadIndex() + { + Index = XZIndex.FromStream(BaseStream, true); + // TODO veryfy Index + } + + private void ReadFooter() + { + Footer = XZFooter.FromStream(BaseStream); + // TODO verify footer + } + + private int ReadBlocks(byte[] buffer, int offset, int count) + { + var bytesRead = 0; + if (_currentBlock is null) + { + NextBlock(); + } + + for (; ; ) { try { - return null != XZHeader.FromStream(stream); - } - catch (Exception) - { - return false; - } - } - - private void AssertBlockCheckTypeIsSupported() - { - switch (Header.BlockCheckType) - { - case CheckType.NONE: - break; - case CheckType.CRC32: - break; - case CheckType.CRC64: - break; - case CheckType.SHA256: - throw new NotImplementedException(); - default: - throw new NotSupportedException( - "Check Type unknown to this version of decoder." - ); - } - } - - public XZHeader Header { get; private set; } - public XZIndex Index { get; private set; } - public XZFooter Footer { get; private set; } - public bool HeaderIsRead { get; private set; } - private XZBlock _currentBlock; - - private bool _endOfStream; - - public XZStream(Stream stream) : base(stream) { } - - public override int Read(byte[] buffer, int offset, int count) - { - int bytesRead = 0; - if (_endOfStream) - { - return bytesRead; - } - - if (!HeaderIsRead) - { - ReadHeader(); - } - - bytesRead = ReadBlocks(buffer, offset, count); - if (bytesRead < count) - { - _endOfStream = true; - ReadIndex(); - ReadFooter(); - } - return bytesRead; - } - - private void ReadHeader() - { - Header = XZHeader.FromStream(BaseStream); - AssertBlockCheckTypeIsSupported(); - HeaderIsRead = true; - } - - private void ReadIndex() - { - Index = XZIndex.FromStream(BaseStream, true); - // TODO veryfy Index - } - - private void ReadFooter() - { - Footer = XZFooter.FromStream(BaseStream); - // TODO verify footer - } - - private int ReadBlocks(byte[] buffer, int offset, int count) - { - int bytesRead = 0; - if (_currentBlock is null) - { - NextBlock(); - } - - for (; ; ) - { - try - { - if (bytesRead >= count) - { - break; - } - - int remaining = count - bytesRead; - int newOffset = offset + bytesRead; - int justRead = _currentBlock.Read(buffer, newOffset, remaining); - if (justRead < remaining) - { - NextBlock(); - } - - bytesRead += justRead; - } - catch (XZIndexMarkerReachedException) + if (bytesRead >= count) { break; } - } - return bytesRead; - } - private void NextBlock() - { - _currentBlock = new XZBlock(BaseStream, Header.BlockCheckType, Header.BlockCheckSize); + var remaining = count - bytesRead; + var newOffset = offset + bytesRead; + var justRead = _currentBlock.Read(buffer, newOffset, remaining); + if (justRead < remaining) + { + NextBlock(); + } + + bytesRead += justRead; + } + catch (XZIndexMarkerReachedException) + { + break; + } } + return bytesRead; + } + + private void NextBlock() + { + _currentBlock = new XZBlock(BaseStream, Header.BlockCheckType, Header.BlockCheckSize); } } diff --git a/src/SharpCompress/Crypto/Crc32Stream.cs b/src/SharpCompress/Crypto/Crc32Stream.cs index d3349bf5..827b1fad 100644 --- a/src/SharpCompress/Crypto/Crc32Stream.cs +++ b/src/SharpCompress/Crypto/Crc32Stream.cs @@ -1,145 +1,144 @@ -#nullable disable +#nullable disable using System; using System.IO; -namespace SharpCompress.Crypto +namespace SharpCompress.Crypto; + +[CLSCompliant(false)] +public sealed class Crc32Stream : Stream { - [CLSCompliant(false)] - public sealed class Crc32Stream : Stream + public const uint DefaultPolynomial = 0xedb88320u; + public const uint DefaultSeed = 0xffffffffu; + + private static uint[] defaultTable; + + private readonly uint[] table; + private uint hash; + + private readonly Stream stream; + + public Crc32Stream(Stream stream) : this(stream, DefaultPolynomial, DefaultSeed) { } + + public Crc32Stream(Stream stream, uint polynomial, uint seed) { - public const uint DefaultPolynomial = 0xedb88320u; - public const uint DefaultSeed = 0xffffffffu; + this.stream = stream; + table = InitializeTable(polynomial); + hash = seed; + } - private static uint[] defaultTable; + public Stream WrappedStream => stream; - private readonly uint[] table; - private uint hash; + public override void Flush() + { + stream.Flush(); + } - private readonly Stream stream; + public override int Read(byte[] buffer, int offset, int count) => + throw new NotSupportedException(); - public Crc32Stream(Stream stream) : this(stream, DefaultPolynomial, DefaultSeed) { } + public override long Seek(long offset, SeekOrigin origin) => + throw new NotSupportedException(); - public Crc32Stream(Stream stream, uint polynomial, uint seed) - { - this.stream = stream; - table = InitializeTable(polynomial); - hash = seed; - } - - public Stream WrappedStream => stream; - - public override void Flush() - { - stream.Flush(); - } - - public override int Read(byte[] buffer, int offset, int count) => - throw new NotSupportedException(); - - public override long Seek(long offset, SeekOrigin origin) => - throw new NotSupportedException(); - - public override void SetLength(long value) => throw new NotSupportedException(); + public override void SetLength(long value) => throw new NotSupportedException(); #if !NETFRAMEWORK && !NETSTANDARD2_0 - public override void Write(ReadOnlySpan buffer) - { - stream.Write(buffer); + public override void Write(ReadOnlySpan buffer) + { + stream.Write(buffer); - hash = CalculateCrc(table, hash, buffer); - } + hash = CalculateCrc(table, hash, buffer); + } #endif - public override void Write(byte[] buffer, int offset, int count) + public override void Write(byte[] buffer, int offset, int count) + { + stream.Write(buffer, offset, count); + hash = CalculateCrc(table, hash, buffer.AsSpan(offset, count)); + } + + public override void WriteByte(byte value) + { + stream.WriteByte(value); + hash = CalculateCrc(table, hash, value); + } + + public override bool CanRead => stream.CanRead; + public override bool CanSeek => false; + public override bool CanWrite => stream.CanWrite; + public override long Length => throw new NotSupportedException(); + public override long Position + { + get => throw new NotSupportedException(); + set => throw new NotSupportedException(); + } + + public uint Crc => ~hash; + + public static uint Compute(byte[] buffer) + { + return Compute(DefaultSeed, buffer); + } + + public static uint Compute(uint seed, byte[] buffer) + { + return Compute(DefaultPolynomial, seed, buffer); + } + + public static uint Compute(uint polynomial, uint seed, ReadOnlySpan buffer) + { + return ~CalculateCrc(InitializeTable(polynomial), seed, buffer); + } + + private static uint[] InitializeTable(uint polynomial) + { + if (polynomial == DefaultPolynomial && defaultTable != null) { - stream.Write(buffer, offset, count); - hash = CalculateCrc(table, hash, buffer.AsSpan(offset, count)); + return defaultTable; } - public override void WriteByte(byte value) + var createTable = new uint[256]; + for (var i = 0; i < 256; i++) { - stream.WriteByte(value); - hash = CalculateCrc(table, hash, value); - } - - public override bool CanRead => stream.CanRead; - public override bool CanSeek => false; - public override bool CanWrite => stream.CanWrite; - public override long Length => throw new NotSupportedException(); - public override long Position - { - get => throw new NotSupportedException(); - set => throw new NotSupportedException(); - } - - public uint Crc => ~hash; - - public static uint Compute(byte[] buffer) - { - return Compute(DefaultSeed, buffer); - } - - public static uint Compute(uint seed, byte[] buffer) - { - return Compute(DefaultPolynomial, seed, buffer); - } - - public static uint Compute(uint polynomial, uint seed, ReadOnlySpan buffer) - { - return ~CalculateCrc(InitializeTable(polynomial), seed, buffer); - } - - private static uint[] InitializeTable(uint polynomial) - { - if (polynomial == DefaultPolynomial && defaultTable != null) + var entry = (uint)i; + for (var j = 0; j < 8; j++) { - return defaultTable; - } - - var createTable = new uint[256]; - for (var i = 0; i < 256; i++) - { - var entry = (uint)i; - for (var j = 0; j < 8; j++) + if ((entry & 1) == 1) { - if ((entry & 1) == 1) - { - entry = (entry >> 1) ^ polynomial; - } - else - { - entry = entry >> 1; - } + entry = (entry >> 1) ^ polynomial; } - - createTable[i] = entry; - } - - if (polynomial == DefaultPolynomial) - { - defaultTable = createTable; - } - - return createTable; - } - - private static uint CalculateCrc(uint[] table, uint crc, ReadOnlySpan buffer) - { - unchecked - { - for (int i = 0; i < buffer.Length; i++) + else { - crc = CalculateCrc(table, crc, buffer[i]); + entry >>= 1; } } - return crc; + + createTable[i] = entry; } - private static uint CalculateCrc(uint[] table, uint crc, byte b) + if (polynomial == DefaultPolynomial) { - return (crc >> 8) ^ table[(crc ^ b) & 0xFF]; + defaultTable = createTable; } + + return createTable; + } + + private static uint CalculateCrc(uint[] table, uint crc, ReadOnlySpan buffer) + { + unchecked + { + for (var i = 0; i < buffer.Length; i++) + { + crc = CalculateCrc(table, crc, buffer[i]); + } + } + return crc; + } + + private static uint CalculateCrc(uint[] table, uint crc, byte b) + { + return (crc >> 8) ^ table[(crc ^ b) & 0xFF]; } } diff --git a/src/SharpCompress/Crypto/CryptoException.cs b/src/SharpCompress/Crypto/CryptoException.cs index f67e6a01..575c34d9 100644 --- a/src/SharpCompress/Crypto/CryptoException.cs +++ b/src/SharpCompress/Crypto/CryptoException.cs @@ -1,13 +1,12 @@ -using System; +using System; -namespace SharpCompress.Crypto +namespace SharpCompress.Crypto; + +public class CryptoException : Exception { - public class CryptoException : Exception - { - public CryptoException() { } + public CryptoException() { } - public CryptoException(string message) : base(message) { } + public CryptoException(string message) : base(message) { } - public CryptoException(string message, Exception exception) : base(message, exception) { } - } + public CryptoException(string message, Exception exception) : base(message, exception) { } } diff --git a/src/SharpCompress/Crypto/DataLengthException.cs b/src/SharpCompress/Crypto/DataLengthException.cs index d1069755..f751adf5 100644 --- a/src/SharpCompress/Crypto/DataLengthException.cs +++ b/src/SharpCompress/Crypto/DataLengthException.cs @@ -1,24 +1,23 @@ -using System; +using System; -namespace SharpCompress.Crypto +namespace SharpCompress.Crypto; + +public class DataLengthException : CryptoException { - public class DataLengthException : CryptoException - { - /** - * base constructor. - */ + /** + * base constructor. + */ - public DataLengthException() { } + public DataLengthException() { } - /** - * create a DataLengthException with the given message. - * - * @param message the message to be carried with the exception. - */ + /** + * create a DataLengthException with the given message. + * + * @param message the message to be carried with the exception. + */ - public DataLengthException(string message) : base(message) { } + public DataLengthException(string message) : base(message) { } - public DataLengthException(string message, Exception exception) : base(message, exception) - { } - } + public DataLengthException(string message, Exception exception) : base(message, exception) + { } } diff --git a/src/SharpCompress/Crypto/IBlockCipher.cs b/src/SharpCompress/Crypto/IBlockCipher.cs index eed5fc48..50eb5fb3 100644 --- a/src/SharpCompress/Crypto/IBlockCipher.cs +++ b/src/SharpCompress/Crypto/IBlockCipher.cs @@ -1,34 +1,33 @@ -using System; +using System; -namespace SharpCompress.Crypto +namespace SharpCompress.Crypto; + +/// Base interface for a symmetric key block cipher. +public interface IBlockCipher { - /// Base interface for a symmetric key block cipher. - public interface IBlockCipher - { - /// The name of the algorithm this cipher implements. - string AlgorithmName { get; } + /// The name of the algorithm this cipher implements. + string AlgorithmName { get; } - /// Initialise the cipher. - /// Initialise for encryption if true, for decryption if false. - /// The key or other data required by the cipher. - void Init(bool forEncryption, ICipherParameters parameters); + /// Initialise the cipher. + /// Initialise for encryption if true, for decryption if false. + /// The key or other data required by the cipher. + void Init(bool forEncryption, ICipherParameters parameters); - /// The block size for this cipher, in bytes. - int GetBlockSize(); + /// The block size for this cipher, in bytes. + int GetBlockSize(); - /// Indicates whether this cipher can handle partial blocks. - bool IsPartialBlockOkay { get; } + /// Indicates whether this cipher can handle partial blocks. + bool IsPartialBlockOkay { get; } - /// Process a block. - /// The input buffer. - /// The output buffer. - /// If input block is wrong size, or outBuf too small. - /// The number of bytes processed and produced. - int ProcessBlock(ReadOnlySpan inBuf, Span outBuf); + /// Process a block. + /// The input buffer. + /// The output buffer. + /// If input block is wrong size, or outBuf too small. + /// The number of bytes processed and produced. + int ProcessBlock(ReadOnlySpan inBuf, Span outBuf); - /// - /// Reset the cipher to the same state as it was after the last init (if there was one). - /// - void Reset(); - } + /// + /// Reset the cipher to the same state as it was after the last init (if there was one). + /// + void Reset(); } diff --git a/src/SharpCompress/Crypto/ICipherParameters.cs b/src/SharpCompress/Crypto/ICipherParameters.cs index dbccaa77..9934637a 100644 --- a/src/SharpCompress/Crypto/ICipherParameters.cs +++ b/src/SharpCompress/Crypto/ICipherParameters.cs @@ -1,4 +1,3 @@ -namespace SharpCompress.Crypto -{ - public interface ICipherParameters { } -} +namespace SharpCompress.Crypto; + +public interface ICipherParameters { } diff --git a/src/SharpCompress/Crypto/KeyParameter.cs b/src/SharpCompress/Crypto/KeyParameter.cs index 3fb36f46..e3a7934c 100644 --- a/src/SharpCompress/Crypto/KeyParameter.cs +++ b/src/SharpCompress/Crypto/KeyParameter.cs @@ -1,43 +1,42 @@ -using System; +using System; -namespace SharpCompress.Crypto +namespace SharpCompress.Crypto; + +public class KeyParameter : ICipherParameters { - public class KeyParameter : ICipherParameters + private readonly byte[] key; + + public KeyParameter(byte[] key) { - private readonly byte[] key; - - public KeyParameter(byte[] key) + if (key is null) { - if (key is null) - { - throw new ArgumentNullException(nameof(key)); - } - - this.key = (byte[])key.Clone(); + throw new ArgumentNullException(nameof(key)); } - public KeyParameter(byte[] key, int keyOff, int keyLen) - { - if (key is null) - { - throw new ArgumentNullException(nameof(key)); - } - if (keyOff < 0 || keyOff > key.Length) - { - throw new ArgumentOutOfRangeException(nameof(keyOff)); - } - if (keyLen < 0 || (keyOff + keyLen) > key.Length) - { - throw new ArgumentOutOfRangeException(nameof(keyLen)); - } + this.key = (byte[])key.Clone(); + } - this.key = new byte[keyLen]; - Array.Copy(key, keyOff, this.key, 0, keyLen); + public KeyParameter(byte[] key, int keyOff, int keyLen) + { + if (key is null) + { + throw new ArgumentNullException(nameof(key)); + } + if (keyOff < 0 || keyOff > key.Length) + { + throw new ArgumentOutOfRangeException(nameof(keyOff)); + } + if (keyLen < 0 || (keyOff + keyLen) > key.Length) + { + throw new ArgumentOutOfRangeException(nameof(keyLen)); } - public byte[] GetKey() - { - return (byte[])key.Clone(); - } + this.key = new byte[keyLen]; + Array.Copy(key, keyOff, this.key, 0, keyLen); + } + + public byte[] GetKey() + { + return (byte[])key.Clone(); } } diff --git a/src/SharpCompress/Crypto/RijndaelEngine.cs b/src/SharpCompress/Crypto/RijndaelEngine.cs index 6b91306b..bbcc3da1 100644 --- a/src/SharpCompress/Crypto/RijndaelEngine.cs +++ b/src/SharpCompress/Crypto/RijndaelEngine.cs @@ -1,1913 +1,1911 @@ -using System; +using System; -namespace SharpCompress.Crypto +namespace SharpCompress.Crypto; + +public sealed class RijndaelEngine : IBlockCipher { - public sealed class RijndaelEngine : IBlockCipher + private const int MAXROUNDS = 14; + + private const int MAXKC = (256 / 4); + + private static ReadOnlySpan Logtable => + new byte[] + { + 0, + 0, + 25, + 1, + 50, + 2, + 26, + 198, + 75, + 199, + 27, + 104, + 51, + 238, + 223, + 3, + 100, + 4, + 224, + 14, + 52, + 141, + 129, + 239, + 76, + 113, + 8, + 200, + 248, + 105, + 28, + 193, + 125, + 194, + 29, + 181, + 249, + 185, + 39, + 106, + 77, + 228, + 166, + 114, + 154, + 201, + 9, + 120, + 101, + 47, + 138, + 5, + 33, + 15, + 225, + 36, + 18, + 240, + 130, + 69, + 53, + 147, + 218, + 142, + 150, + 143, + 219, + 189, + 54, + 208, + 206, + 148, + 19, + 92, + 210, + 241, + 64, + 70, + 131, + 56, + 102, + 221, + 253, + 48, + 191, + 6, + 139, + 98, + 179, + 37, + 226, + 152, + 34, + 136, + 145, + 16, + 126, + 110, + 72, + 195, + 163, + 182, + 30, + 66, + 58, + 107, + 40, + 84, + 250, + 133, + 61, + 186, + 43, + 121, + 10, + 21, + 155, + 159, + 94, + 202, + 78, + 212, + 172, + 229, + 243, + 115, + 167, + 87, + 175, + 88, + 168, + 80, + 244, + 234, + 214, + 116, + 79, + 174, + 233, + 213, + 231, + 230, + 173, + 232, + 44, + 215, + 117, + 122, + 235, + 22, + 11, + 245, + 89, + 203, + 95, + 176, + 156, + 169, + 81, + 160, + 127, + 12, + 246, + 111, + 23, + 196, + 73, + 236, + 216, + 67, + 31, + 45, + 164, + 118, + 123, + 183, + 204, + 187, + 62, + 90, + 251, + 96, + 177, + 134, + 59, + 82, + 161, + 108, + 170, + 85, + 41, + 157, + 151, + 178, + 135, + 144, + 97, + 190, + 220, + 252, + 188, + 149, + 207, + 205, + 55, + 63, + 91, + 209, + 83, + 57, + 132, + 60, + 65, + 162, + 109, + 71, + 20, + 42, + 158, + 93, + 86, + 242, + 211, + 171, + 68, + 17, + 146, + 217, + 35, + 32, + 46, + 137, + 180, + 124, + 184, + 38, + 119, + 153, + 227, + 165, + 103, + 74, + 237, + 222, + 197, + 49, + 254, + 24, + 13, + 99, + 140, + 128, + 192, + 247, + 112, + 7 + }; + + private static ReadOnlySpan Alogtable => + new byte[] + { + 0, + 3, + 5, + 15, + 17, + 51, + 85, + 255, + 26, + 46, + 114, + 150, + 161, + 248, + 19, + 53, + 95, + 225, + 56, + 72, + 216, + 115, + 149, + 164, + 247, + 2, + 6, + 10, + 30, + 34, + 102, + 170, + 229, + 52, + 92, + 228, + 55, + 89, + 235, + 38, + 106, + 190, + 217, + 112, + 144, + 171, + 230, + 49, + 83, + 245, + 4, + 12, + 20, + 60, + 68, + 204, + 79, + 209, + 104, + 184, + 211, + 110, + 178, + 205, + 76, + 212, + 103, + 169, + 224, + 59, + 77, + 215, + 98, + 166, + 241, + 8, + 24, + 40, + 120, + 136, + 131, + 158, + 185, + 208, + 107, + 189, + 220, + 127, + 129, + 152, + 179, + 206, + 73, + 219, + 118, + 154, + 181, + 196, + 87, + 249, + 16, + 48, + 80, + 240, + 11, + 29, + 39, + 105, + 187, + 214, + 97, + 163, + 254, + 25, + 43, + 125, + 135, + 146, + 173, + 236, + 47, + 113, + 147, + 174, + 233, + 32, + 96, + 160, + 251, + 22, + 58, + 78, + 210, + 109, + 183, + 194, + 93, + 231, + 50, + 86, + 250, + 21, + 63, + 65, + 195, + 94, + 226, + 61, + 71, + 201, + 64, + 192, + 91, + 237, + 44, + 116, + 156, + 191, + 218, + 117, + 159, + 186, + 213, + 100, + 172, + 239, + 42, + 126, + 130, + 157, + 188, + 223, + 122, + 142, + 137, + 128, + 155, + 182, + 193, + 88, + 232, + 35, + 101, + 175, + 234, + 37, + 111, + 177, + 200, + 67, + 197, + 84, + 252, + 31, + 33, + 99, + 165, + 244, + 7, + 9, + 27, + 45, + 119, + 153, + 176, + 203, + 70, + 202, + 69, + 207, + 74, + 222, + 121, + 139, + 134, + 145, + 168, + 227, + 62, + 66, + 198, + 81, + 243, + 14, + 18, + 54, + 90, + 238, + 41, + 123, + 141, + 140, + 143, + 138, + 133, + 148, + 167, + 242, + 13, + 23, + 57, + 75, + 221, + 124, + 132, + 151, + 162, + 253, + 28, + 36, + 108, + 180, + 199, + 82, + 246, + 1, + 3, + 5, + 15, + 17, + 51, + 85, + 255, + 26, + 46, + 114, + 150, + 161, + 248, + 19, + 53, + 95, + 225, + 56, + 72, + 216, + 115, + 149, + 164, + 247, + 2, + 6, + 10, + 30, + 34, + 102, + 170, + 229, + 52, + 92, + 228, + 55, + 89, + 235, + 38, + 106, + 190, + 217, + 112, + 144, + 171, + 230, + 49, + 83, + 245, + 4, + 12, + 20, + 60, + 68, + 204, + 79, + 209, + 104, + 184, + 211, + 110, + 178, + 205, + 76, + 212, + 103, + 169, + 224, + 59, + 77, + 215, + 98, + 166, + 241, + 8, + 24, + 40, + 120, + 136, + 131, + 158, + 185, + 208, + 107, + 189, + 220, + 127, + 129, + 152, + 179, + 206, + 73, + 219, + 118, + 154, + 181, + 196, + 87, + 249, + 16, + 48, + 80, + 240, + 11, + 29, + 39, + 105, + 187, + 214, + 97, + 163, + 254, + 25, + 43, + 125, + 135, + 146, + 173, + 236, + 47, + 113, + 147, + 174, + 233, + 32, + 96, + 160, + 251, + 22, + 58, + 78, + 210, + 109, + 183, + 194, + 93, + 231, + 50, + 86, + 250, + 21, + 63, + 65, + 195, + 94, + 226, + 61, + 71, + 201, + 64, + 192, + 91, + 237, + 44, + 116, + 156, + 191, + 218, + 117, + 159, + 186, + 213, + 100, + 172, + 239, + 42, + 126, + 130, + 157, + 188, + 223, + 122, + 142, + 137, + 128, + 155, + 182, + 193, + 88, + 232, + 35, + 101, + 175, + 234, + 37, + 111, + 177, + 200, + 67, + 197, + 84, + 252, + 31, + 33, + 99, + 165, + 244, + 7, + 9, + 27, + 45, + 119, + 153, + 176, + 203, + 70, + 202, + 69, + 207, + 74, + 222, + 121, + 139, + 134, + 145, + 168, + 227, + 62, + 66, + 198, + 81, + 243, + 14, + 18, + 54, + 90, + 238, + 41, + 123, + 141, + 140, + 143, + 138, + 133, + 148, + 167, + 242, + 13, + 23, + 57, + 75, + 221, + 124, + 132, + 151, + 162, + 253, + 28, + 36, + 108, + 180, + 199, + 82, + 246, + 1 + }; + + private static ReadOnlySpan S => + new byte[] + { + 99, + 124, + 119, + 123, + 242, + 107, + 111, + 197, + 48, + 1, + 103, + 43, + 254, + 215, + 171, + 118, + 202, + 130, + 201, + 125, + 250, + 89, + 71, + 240, + 173, + 212, + 162, + 175, + 156, + 164, + 114, + 192, + 183, + 253, + 147, + 38, + 54, + 63, + 247, + 204, + 52, + 165, + 229, + 241, + 113, + 216, + 49, + 21, + 4, + 199, + 35, + 195, + 24, + 150, + 5, + 154, + 7, + 18, + 128, + 226, + 235, + 39, + 178, + 117, + 9, + 131, + 44, + 26, + 27, + 110, + 90, + 160, + 82, + 59, + 214, + 179, + 41, + 227, + 47, + 132, + 83, + 209, + 0, + 237, + 32, + 252, + 177, + 91, + 106, + 203, + 190, + 57, + 74, + 76, + 88, + 207, + 208, + 239, + 170, + 251, + 67, + 77, + 51, + 133, + 69, + 249, + 2, + 127, + 80, + 60, + 159, + 168, + 81, + 163, + 64, + 143, + 146, + 157, + 56, + 245, + 188, + 182, + 218, + 33, + 16, + 255, + 243, + 210, + 205, + 12, + 19, + 236, + 95, + 151, + 68, + 23, + 196, + 167, + 126, + 61, + 100, + 93, + 25, + 115, + 96, + 129, + 79, + 220, + 34, + 42, + 144, + 136, + 70, + 238, + 184, + 20, + 222, + 94, + 11, + 219, + 224, + 50, + 58, + 10, + 73, + 6, + 36, + 92, + 194, + 211, + 172, + 98, + 145, + 149, + 228, + 121, + 231, + 200, + 55, + 109, + 141, + 213, + 78, + 169, + 108, + 86, + 244, + 234, + 101, + 122, + 174, + 8, + 186, + 120, + 37, + 46, + 28, + 166, + 180, + 198, + 232, + 221, + 116, + 31, + 75, + 189, + 139, + 138, + 112, + 62, + 181, + 102, + 72, + 3, + 246, + 14, + 97, + 53, + 87, + 185, + 134, + 193, + 29, + 158, + 225, + 248, + 152, + 17, + 105, + 217, + 142, + 148, + 155, + 30, + 135, + 233, + 206, + 85, + 40, + 223, + 140, + 161, + 137, + 13, + 191, + 230, + 66, + 104, + 65, + 153, + 45, + 15, + 176, + 84, + 187, + 22 + }; + + private static ReadOnlySpan Si => + new byte[] + { + 82, + 9, + 106, + 213, + 48, + 54, + 165, + 56, + 191, + 64, + 163, + 158, + 129, + 243, + 215, + 251, + 124, + 227, + 57, + 130, + 155, + 47, + 255, + 135, + 52, + 142, + 67, + 68, + 196, + 222, + 233, + 203, + 84, + 123, + 148, + 50, + 166, + 194, + 35, + 61, + 238, + 76, + 149, + 11, + 66, + 250, + 195, + 78, + 8, + 46, + 161, + 102, + 40, + 217, + 36, + 178, + 118, + 91, + 162, + 73, + 109, + 139, + 209, + 37, + 114, + 248, + 246, + 100, + 134, + 104, + 152, + 22, + 212, + 164, + 92, + 204, + 93, + 101, + 182, + 146, + 108, + 112, + 72, + 80, + 253, + 237, + 185, + 218, + 94, + 21, + 70, + 87, + 167, + 141, + 157, + 132, + 144, + 216, + 171, + 0, + 140, + 188, + 211, + 10, + 247, + 228, + 88, + 5, + 184, + 179, + 69, + 6, + 208, + 44, + 30, + 143, + 202, + 63, + 15, + 2, + 193, + 175, + 189, + 3, + 1, + 19, + 138, + 107, + 58, + 145, + 17, + 65, + 79, + 103, + 220, + 234, + 151, + 242, + 207, + 206, + 240, + 180, + 230, + 115, + 150, + 172, + 116, + 34, + 231, + 173, + 53, + 133, + 226, + 249, + 55, + 232, + 28, + 117, + 223, + 110, + 71, + 241, + 26, + 113, + 29, + 41, + 197, + 137, + 111, + 183, + 98, + 14, + 170, + 24, + 190, + 27, + 252, + 86, + 62, + 75, + 198, + 210, + 121, + 32, + 154, + 219, + 192, + 254, + 120, + 205, + 90, + 244, + 31, + 221, + 168, + 51, + 136, + 7, + 199, + 49, + 177, + 18, + 16, + 89, + 39, + 128, + 236, + 95, + 96, + 81, + 127, + 169, + 25, + 181, + 74, + 13, + 45, + 229, + 122, + 159, + 147, + 201, + 156, + 239, + 160, + 224, + 59, + 77, + 174, + 42, + 245, + 176, + 200, + 235, + 187, + 60, + 131, + 83, + 153, + 97, + 23, + 43, + 4, + 126, + 186, + 119, + 214, + 38, + 225, + 105, + 20, + 99, + 85, + 33, + 12, + 125 + }; + + private static ReadOnlySpan rcon => + new byte[] + { + 0x01, + 0x02, + 0x04, + 0x08, + 0x10, + 0x20, + 0x40, + 0x80, + 0x1b, + 0x36, + 0x6c, + 0xd8, + 0xab, + 0x4d, + 0x9a, + 0x2f, + 0x5e, + 0xbc, + 0x63, + 0xc6, + 0x97, + 0x35, + 0x6a, + 0xd4, + 0xb3, + 0x7d, + 0xfa, + 0xef, + 0xc5, + 0x91 + }; + + private static readonly byte[][] shifts0 = { - private const int MAXROUNDS = 14; + new byte[] { 0, 8, 16, 24 }, + new byte[] { 0, 8, 16, 24 }, + new byte[] { 0, 8, 16, 24 }, + new byte[] { 0, 8, 16, 32 }, + new byte[] { 0, 8, 24, 32 } + }; - private const int MAXKC = (256 / 4); + private static readonly byte[][] shifts1 = + { + new byte[] { 0, 24, 16, 8 }, + new byte[] { 0, 32, 24, 16 }, + new byte[] { 0, 40, 32, 24 }, + new byte[] { 0, 48, 40, 24 }, + new byte[] { 0, 56, 40, 32 } + }; - private static ReadOnlySpan Logtable => - new byte[] - { - 0, - 0, - 25, - 1, - 50, - 2, - 26, - 198, - 75, - 199, - 27, - 104, - 51, - 238, - 223, - 3, - 100, - 4, - 224, - 14, - 52, - 141, - 129, - 239, - 76, - 113, - 8, - 200, - 248, - 105, - 28, - 193, - 125, - 194, - 29, - 181, - 249, - 185, - 39, - 106, - 77, - 228, - 166, - 114, - 154, - 201, - 9, - 120, - 101, - 47, - 138, - 5, - 33, - 15, - 225, - 36, - 18, - 240, - 130, - 69, - 53, - 147, - 218, - 142, - 150, - 143, - 219, - 189, - 54, - 208, - 206, - 148, - 19, - 92, - 210, - 241, - 64, - 70, - 131, - 56, - 102, - 221, - 253, - 48, - 191, - 6, - 139, - 98, - 179, - 37, - 226, - 152, - 34, - 136, - 145, - 16, - 126, - 110, - 72, - 195, - 163, - 182, - 30, - 66, - 58, - 107, - 40, - 84, - 250, - 133, - 61, - 186, - 43, - 121, - 10, - 21, - 155, - 159, - 94, - 202, - 78, - 212, - 172, - 229, - 243, - 115, - 167, - 87, - 175, - 88, - 168, - 80, - 244, - 234, - 214, - 116, - 79, - 174, - 233, - 213, - 231, - 230, - 173, - 232, - 44, - 215, - 117, - 122, - 235, - 22, - 11, - 245, - 89, - 203, - 95, - 176, - 156, - 169, - 81, - 160, - 127, - 12, - 246, - 111, - 23, - 196, - 73, - 236, - 216, - 67, - 31, - 45, - 164, - 118, - 123, - 183, - 204, - 187, - 62, - 90, - 251, - 96, - 177, - 134, - 59, - 82, - 161, - 108, - 170, - 85, - 41, - 157, - 151, - 178, - 135, - 144, - 97, - 190, - 220, - 252, - 188, - 149, - 207, - 205, - 55, - 63, - 91, - 209, - 83, - 57, - 132, - 60, - 65, - 162, - 109, - 71, - 20, - 42, - 158, - 93, - 86, - 242, - 211, - 171, - 68, - 17, - 146, - 217, - 35, - 32, - 46, - 137, - 180, - 124, - 184, - 38, - 119, - 153, - 227, - 165, - 103, - 74, - 237, - 222, - 197, - 49, - 254, - 24, - 13, - 99, - 140, - 128, - 192, - 247, - 112, - 7 - }; + /** + * multiply two elements of GF(2^m) + * needed for MixColumn and InvMixColumn + */ - private static ReadOnlySpan Alogtable => - new byte[] - { - 0, - 3, - 5, - 15, - 17, - 51, - 85, - 255, - 26, - 46, - 114, - 150, - 161, - 248, - 19, - 53, - 95, - 225, - 56, - 72, - 216, - 115, - 149, - 164, - 247, - 2, - 6, - 10, - 30, - 34, - 102, - 170, - 229, - 52, - 92, - 228, - 55, - 89, - 235, - 38, - 106, - 190, - 217, - 112, - 144, - 171, - 230, - 49, - 83, - 245, - 4, - 12, - 20, - 60, - 68, - 204, - 79, - 209, - 104, - 184, - 211, - 110, - 178, - 205, - 76, - 212, - 103, - 169, - 224, - 59, - 77, - 215, - 98, - 166, - 241, - 8, - 24, - 40, - 120, - 136, - 131, - 158, - 185, - 208, - 107, - 189, - 220, - 127, - 129, - 152, - 179, - 206, - 73, - 219, - 118, - 154, - 181, - 196, - 87, - 249, - 16, - 48, - 80, - 240, - 11, - 29, - 39, - 105, - 187, - 214, - 97, - 163, - 254, - 25, - 43, - 125, - 135, - 146, - 173, - 236, - 47, - 113, - 147, - 174, - 233, - 32, - 96, - 160, - 251, - 22, - 58, - 78, - 210, - 109, - 183, - 194, - 93, - 231, - 50, - 86, - 250, - 21, - 63, - 65, - 195, - 94, - 226, - 61, - 71, - 201, - 64, - 192, - 91, - 237, - 44, - 116, - 156, - 191, - 218, - 117, - 159, - 186, - 213, - 100, - 172, - 239, - 42, - 126, - 130, - 157, - 188, - 223, - 122, - 142, - 137, - 128, - 155, - 182, - 193, - 88, - 232, - 35, - 101, - 175, - 234, - 37, - 111, - 177, - 200, - 67, - 197, - 84, - 252, - 31, - 33, - 99, - 165, - 244, - 7, - 9, - 27, - 45, - 119, - 153, - 176, - 203, - 70, - 202, - 69, - 207, - 74, - 222, - 121, - 139, - 134, - 145, - 168, - 227, - 62, - 66, - 198, - 81, - 243, - 14, - 18, - 54, - 90, - 238, - 41, - 123, - 141, - 140, - 143, - 138, - 133, - 148, - 167, - 242, - 13, - 23, - 57, - 75, - 221, - 124, - 132, - 151, - 162, - 253, - 28, - 36, - 108, - 180, - 199, - 82, - 246, - 1, - 3, - 5, - 15, - 17, - 51, - 85, - 255, - 26, - 46, - 114, - 150, - 161, - 248, - 19, - 53, - 95, - 225, - 56, - 72, - 216, - 115, - 149, - 164, - 247, - 2, - 6, - 10, - 30, - 34, - 102, - 170, - 229, - 52, - 92, - 228, - 55, - 89, - 235, - 38, - 106, - 190, - 217, - 112, - 144, - 171, - 230, - 49, - 83, - 245, - 4, - 12, - 20, - 60, - 68, - 204, - 79, - 209, - 104, - 184, - 211, - 110, - 178, - 205, - 76, - 212, - 103, - 169, - 224, - 59, - 77, - 215, - 98, - 166, - 241, - 8, - 24, - 40, - 120, - 136, - 131, - 158, - 185, - 208, - 107, - 189, - 220, - 127, - 129, - 152, - 179, - 206, - 73, - 219, - 118, - 154, - 181, - 196, - 87, - 249, - 16, - 48, - 80, - 240, - 11, - 29, - 39, - 105, - 187, - 214, - 97, - 163, - 254, - 25, - 43, - 125, - 135, - 146, - 173, - 236, - 47, - 113, - 147, - 174, - 233, - 32, - 96, - 160, - 251, - 22, - 58, - 78, - 210, - 109, - 183, - 194, - 93, - 231, - 50, - 86, - 250, - 21, - 63, - 65, - 195, - 94, - 226, - 61, - 71, - 201, - 64, - 192, - 91, - 237, - 44, - 116, - 156, - 191, - 218, - 117, - 159, - 186, - 213, - 100, - 172, - 239, - 42, - 126, - 130, - 157, - 188, - 223, - 122, - 142, - 137, - 128, - 155, - 182, - 193, - 88, - 232, - 35, - 101, - 175, - 234, - 37, - 111, - 177, - 200, - 67, - 197, - 84, - 252, - 31, - 33, - 99, - 165, - 244, - 7, - 9, - 27, - 45, - 119, - 153, - 176, - 203, - 70, - 202, - 69, - 207, - 74, - 222, - 121, - 139, - 134, - 145, - 168, - 227, - 62, - 66, - 198, - 81, - 243, - 14, - 18, - 54, - 90, - 238, - 41, - 123, - 141, - 140, - 143, - 138, - 133, - 148, - 167, - 242, - 13, - 23, - 57, - 75, - 221, - 124, - 132, - 151, - 162, - 253, - 28, - 36, - 108, - 180, - 199, - 82, - 246, - 1 - }; - - private static ReadOnlySpan S => - new byte[] - { - 99, - 124, - 119, - 123, - 242, - 107, - 111, - 197, - 48, - 1, - 103, - 43, - 254, - 215, - 171, - 118, - 202, - 130, - 201, - 125, - 250, - 89, - 71, - 240, - 173, - 212, - 162, - 175, - 156, - 164, - 114, - 192, - 183, - 253, - 147, - 38, - 54, - 63, - 247, - 204, - 52, - 165, - 229, - 241, - 113, - 216, - 49, - 21, - 4, - 199, - 35, - 195, - 24, - 150, - 5, - 154, - 7, - 18, - 128, - 226, - 235, - 39, - 178, - 117, - 9, - 131, - 44, - 26, - 27, - 110, - 90, - 160, - 82, - 59, - 214, - 179, - 41, - 227, - 47, - 132, - 83, - 209, - 0, - 237, - 32, - 252, - 177, - 91, - 106, - 203, - 190, - 57, - 74, - 76, - 88, - 207, - 208, - 239, - 170, - 251, - 67, - 77, - 51, - 133, - 69, - 249, - 2, - 127, - 80, - 60, - 159, - 168, - 81, - 163, - 64, - 143, - 146, - 157, - 56, - 245, - 188, - 182, - 218, - 33, - 16, - 255, - 243, - 210, - 205, - 12, - 19, - 236, - 95, - 151, - 68, - 23, - 196, - 167, - 126, - 61, - 100, - 93, - 25, - 115, - 96, - 129, - 79, - 220, - 34, - 42, - 144, - 136, - 70, - 238, - 184, - 20, - 222, - 94, - 11, - 219, - 224, - 50, - 58, - 10, - 73, - 6, - 36, - 92, - 194, - 211, - 172, - 98, - 145, - 149, - 228, - 121, - 231, - 200, - 55, - 109, - 141, - 213, - 78, - 169, - 108, - 86, - 244, - 234, - 101, - 122, - 174, - 8, - 186, - 120, - 37, - 46, - 28, - 166, - 180, - 198, - 232, - 221, - 116, - 31, - 75, - 189, - 139, - 138, - 112, - 62, - 181, - 102, - 72, - 3, - 246, - 14, - 97, - 53, - 87, - 185, - 134, - 193, - 29, - 158, - 225, - 248, - 152, - 17, - 105, - 217, - 142, - 148, - 155, - 30, - 135, - 233, - 206, - 85, - 40, - 223, - 140, - 161, - 137, - 13, - 191, - 230, - 66, - 104, - 65, - 153, - 45, - 15, - 176, - 84, - 187, - 22 - }; - - private static ReadOnlySpan Si => - new byte[] - { - 82, - 9, - 106, - 213, - 48, - 54, - 165, - 56, - 191, - 64, - 163, - 158, - 129, - 243, - 215, - 251, - 124, - 227, - 57, - 130, - 155, - 47, - 255, - 135, - 52, - 142, - 67, - 68, - 196, - 222, - 233, - 203, - 84, - 123, - 148, - 50, - 166, - 194, - 35, - 61, - 238, - 76, - 149, - 11, - 66, - 250, - 195, - 78, - 8, - 46, - 161, - 102, - 40, - 217, - 36, - 178, - 118, - 91, - 162, - 73, - 109, - 139, - 209, - 37, - 114, - 248, - 246, - 100, - 134, - 104, - 152, - 22, - 212, - 164, - 92, - 204, - 93, - 101, - 182, - 146, - 108, - 112, - 72, - 80, - 253, - 237, - 185, - 218, - 94, - 21, - 70, - 87, - 167, - 141, - 157, - 132, - 144, - 216, - 171, - 0, - 140, - 188, - 211, - 10, - 247, - 228, - 88, - 5, - 184, - 179, - 69, - 6, - 208, - 44, - 30, - 143, - 202, - 63, - 15, - 2, - 193, - 175, - 189, - 3, - 1, - 19, - 138, - 107, - 58, - 145, - 17, - 65, - 79, - 103, - 220, - 234, - 151, - 242, - 207, - 206, - 240, - 180, - 230, - 115, - 150, - 172, - 116, - 34, - 231, - 173, - 53, - 133, - 226, - 249, - 55, - 232, - 28, - 117, - 223, - 110, - 71, - 241, - 26, - 113, - 29, - 41, - 197, - 137, - 111, - 183, - 98, - 14, - 170, - 24, - 190, - 27, - 252, - 86, - 62, - 75, - 198, - 210, - 121, - 32, - 154, - 219, - 192, - 254, - 120, - 205, - 90, - 244, - 31, - 221, - 168, - 51, - 136, - 7, - 199, - 49, - 177, - 18, - 16, - 89, - 39, - 128, - 236, - 95, - 96, - 81, - 127, - 169, - 25, - 181, - 74, - 13, - 45, - 229, - 122, - 159, - 147, - 201, - 156, - 239, - 160, - 224, - 59, - 77, - 174, - 42, - 245, - 176, - 200, - 235, - 187, - 60, - 131, - 83, - 153, - 97, - 23, - 43, - 4, - 126, - 186, - 119, - 214, - 38, - 225, - 105, - 20, - 99, - 85, - 33, - 12, - 125 - }; - - private static ReadOnlySpan rcon => - new byte[] - { - 0x01, - 0x02, - 0x04, - 0x08, - 0x10, - 0x20, - 0x40, - 0x80, - 0x1b, - 0x36, - 0x6c, - 0xd8, - 0xab, - 0x4d, - 0x9a, - 0x2f, - 0x5e, - 0xbc, - 0x63, - 0xc6, - 0x97, - 0x35, - 0x6a, - 0xd4, - 0xb3, - 0x7d, - 0xfa, - 0xef, - 0xc5, - 0x91 - }; - - private static readonly byte[][] shifts0 = + private byte Mul0x2(int b) + { + if (b != 0) { - new byte[] { 0, 8, 16, 24 }, - new byte[] { 0, 8, 16, 24 }, - new byte[] { 0, 8, 16, 24 }, - new byte[] { 0, 8, 16, 32 }, - new byte[] { 0, 8, 24, 32 } + return Alogtable[25 + (Logtable[b] & 0xff)]; + } + return 0; + } + + private byte Mul0x3(int b) + { + if (b != 0) + { + return Alogtable[1 + (Logtable[b] & 0xff)]; + } + return 0; + } + + private byte Mul0x9(int b) + { + if (b >= 0) + { + return Alogtable[199 + b]; + } + return 0; + } + + private byte Mul0xb(int b) + { + if (b >= 0) + { + return Alogtable[104 + b]; + } + return 0; + } + + private byte Mul0xd(int b) + { + if (b >= 0) + { + return Alogtable[238 + b]; + } + return 0; + } + + private byte Mul0xe(int b) + { + if (b >= 0) + { + return Alogtable[223 + b]; + } + return 0; + } + + /** + * xor corresponding text input and round key input bytes + */ + + private void KeyAddition(long[] rk) + { + A0 ^= rk[0]; + A1 ^= rk[1]; + A2 ^= rk[2]; + A3 ^= rk[3]; + } + + private long Shift(long r, int shift) + { + //return (((long)((ulong) r >> shift) | (r << (BC - shift)))) & BC_MASK; + + var temp = (ulong)r >> shift; + + // NB: This corrects for Mono Bug #79087 (fixed in 1.1.17) + if (shift > 31) + { + temp &= 0xFFFFFFFFUL; + } + + return ((long)temp | (r << (BC - shift))) & BC_MASK; + } + + /** + * Row 0 remains unchanged + * The other three rows are shifted a variable amount + */ + + private void ShiftRow(byte[] shiftsSC) + { + A1 = Shift(A1, shiftsSC[1]); + A2 = Shift(A2, shiftsSC[2]); + A3 = Shift(A3, shiftsSC[3]); + } + + private long ApplyS(long r, ReadOnlySpan box) + { + long res = 0; + + for (var j = 0; j < BC; j += 8) + { + res |= (long)(box[(int)((r >> j) & 0xff)] & 0xff) << j; + } + + return res; + } + + /** + * Replace every byte of the input by the byte at that place + * in the nonlinear S-box + */ + + private void Substitution(ReadOnlySpan box) + { + A0 = ApplyS(A0, box); + A1 = ApplyS(A1, box); + A2 = ApplyS(A2, box); + A3 = ApplyS(A3, box); + } + + /** + * Mix the bytes of every column in a linear way + */ + + private void MixColumn() + { + long r0, + r1, + r2, + r3; + + r0 = r1 = r2 = r3 = 0; + + for (var j = 0; j < BC; j += 8) + { + var a0 = (int)((A0 >> j) & 0xff); + var a1 = (int)((A1 >> j) & 0xff); + var a2 = (int)((A2 >> j) & 0xff); + var a3 = (int)((A3 >> j) & 0xff); + + r0 |= (long)((Mul0x2(a0) ^ Mul0x3(a1) ^ a2 ^ a3) & 0xff) << j; + + r1 |= (long)((Mul0x2(a1) ^ Mul0x3(a2) ^ a3 ^ a0) & 0xff) << j; + + r2 |= (long)((Mul0x2(a2) ^ Mul0x3(a3) ^ a0 ^ a1) & 0xff) << j; + + r3 |= (long)((Mul0x2(a3) ^ Mul0x3(a0) ^ a1 ^ a2) & 0xff) << j; + } + + A0 = r0; + A1 = r1; + A2 = r2; + A3 = r3; + } + + /** + * Mix the bytes of every column in a linear way + * This is the opposite operation of Mixcolumn + */ + + private void InvMixColumn() + { + long r0, + r1, + r2, + r3; + + r0 = r1 = r2 = r3 = 0; + for (var j = 0; j < BC; j += 8) + { + var a0 = (int)((A0 >> j) & 0xff); + var a1 = (int)((A1 >> j) & 0xff); + var a2 = (int)((A2 >> j) & 0xff); + var a3 = (int)((A3 >> j) & 0xff); + + // + // pre-lookup the log table + // + a0 = (a0 != 0) ? (Logtable[a0 & 0xff] & 0xff) : -1; + a1 = (a1 != 0) ? (Logtable[a1 & 0xff] & 0xff) : -1; + a2 = (a2 != 0) ? (Logtable[a2 & 0xff] & 0xff) : -1; + a3 = (a3 != 0) ? (Logtable[a3 & 0xff] & 0xff) : -1; + + r0 |= (long)((Mul0xe(a0) ^ Mul0xb(a1) ^ Mul0xd(a2) ^ Mul0x9(a3)) & 0xff) << j; + + r1 |= (long)((Mul0xe(a1) ^ Mul0xb(a2) ^ Mul0xd(a3) ^ Mul0x9(a0)) & 0xff) << j; + + r2 |= (long)((Mul0xe(a2) ^ Mul0xb(a3) ^ Mul0xd(a0) ^ Mul0x9(a1)) & 0xff) << j; + + r3 |= (long)((Mul0xe(a3) ^ Mul0xb(a0) ^ Mul0xd(a1) ^ Mul0x9(a2)) & 0xff) << j; + } + + A0 = r0; + A1 = r1; + A2 = r2; + A3 = r3; + } + + /** + * Calculate the necessary round keys + * The number of calculations depends on keyBits and blockBits + */ + + private long[][] GenerateWorkingKey(byte[] key) + { + int t, + rconpointer = 0; + var keyBits = key.Length * 8; + var tk = new byte[4, MAXKC]; + + //long[,] W = new long[MAXROUNDS+1,4]; + var W = new long[MAXROUNDS + 1][]; + + for (var i = 0; i < MAXROUNDS + 1; i++) + { + W[i] = new long[4]; + } + + var KC = keyBits switch + { + 128 => 4, + 160 => 5, + 192 => 6, + 224 => 7, + 256 => 8, + _ => throw new ArgumentException("Key length not 128/160/192/224/256 bits."), }; - - private static readonly byte[][] shifts1 = + if (keyBits >= blockBits) { - new byte[] { 0, 24, 16, 8 }, - new byte[] { 0, 32, 24, 16 }, - new byte[] { 0, 40, 32, 24 }, - new byte[] { 0, 48, 40, 24 }, - new byte[] { 0, 56, 40, 32 } - }; - - /** - * multiply two elements of GF(2^m) - * needed for MixColumn and InvMixColumn - */ - - private byte Mul0x2(int b) + ROUNDS = KC + 6; + } + else { - if (b != 0) + ROUNDS = (BC / 8) + 6; + } + + // + // copy the key into the processing area + // + var index = 0; + + for (var i = 0; i < key.Length; i++) + { + tk[i % 4, i / 4] = key[index++]; + } + + t = 0; + + // + // copy values into round key array + // + for (var j = 0; (j < KC) && (t < (ROUNDS + 1) * (BC / 8)); j++, t++) + { + for (var i = 0; i < 4; i++) { - return Alogtable[25 + (Logtable[b] & 0xff)]; + W[t / (BC / 8)][i] |= (long)(tk[i, j] & 0xff) << ((t * 8) % BC); } - return 0; } - private byte Mul0x3(int b) + // + // while not enough round key material calculated + // calculate new values + // + while (t < (ROUNDS + 1) * (BC / 8)) { - if (b != 0) + for (var i = 0; i < 4; i++) { - return Alogtable[1 + (Logtable[b] & 0xff)]; + tk[i, 0] ^= S[tk[(i + 1) % 4, KC - 1] & 0xff]; } - return 0; - } + tk[0, 0] ^= rcon[rconpointer++]; - private byte Mul0x9(int b) - { - if (b >= 0) + if (KC <= 6) { - return Alogtable[199 + b]; - } - return 0; - } - - private byte Mul0xb(int b) - { - if (b >= 0) - { - return Alogtable[104 + b]; - } - return 0; - } - - private byte Mul0xd(int b) - { - if (b >= 0) - { - return Alogtable[238 + b]; - } - return 0; - } - - private byte Mul0xe(int b) - { - if (b >= 0) - { - return Alogtable[223 + b]; - } - return 0; - } - - /** - * xor corresponding text input and round key input bytes - */ - - private void KeyAddition(long[] rk) - { - A0 ^= rk[0]; - A1 ^= rk[1]; - A2 ^= rk[2]; - A3 ^= rk[3]; - } - - private long Shift(long r, int shift) - { - //return (((long)((ulong) r >> shift) | (r << (BC - shift)))) & BC_MASK; - - ulong temp = (ulong)r >> shift; - - // NB: This corrects for Mono Bug #79087 (fixed in 1.1.17) - if (shift > 31) - { - temp &= 0xFFFFFFFFUL; - } - - return ((long)temp | (r << (BC - shift))) & BC_MASK; - } - - /** - * Row 0 remains unchanged - * The other three rows are shifted a variable amount - */ - - private void ShiftRow(byte[] shiftsSC) - { - A1 = Shift(A1, shiftsSC[1]); - A2 = Shift(A2, shiftsSC[2]); - A3 = Shift(A3, shiftsSC[3]); - } - - private long ApplyS(long r, ReadOnlySpan box) - { - long res = 0; - - for (int j = 0; j < BC; j += 8) - { - res |= (long)(box[(int)((r >> j) & 0xff)] & 0xff) << j; - } - - return res; - } - - /** - * Replace every byte of the input by the byte at that place - * in the nonlinear S-box - */ - - private void Substitution(ReadOnlySpan box) - { - A0 = ApplyS(A0, box); - A1 = ApplyS(A1, box); - A2 = ApplyS(A2, box); - A3 = ApplyS(A3, box); - } - - /** - * Mix the bytes of every column in a linear way - */ - - private void MixColumn() - { - long r0, - r1, - r2, - r3; - - r0 = r1 = r2 = r3 = 0; - - for (int j = 0; j < BC; j += 8) - { - int a0 = (int)((A0 >> j) & 0xff); - int a1 = (int)((A1 >> j) & 0xff); - int a2 = (int)((A2 >> j) & 0xff); - int a3 = (int)((A3 >> j) & 0xff); - - r0 |= (long)((Mul0x2(a0) ^ Mul0x3(a1) ^ a2 ^ a3) & 0xff) << j; - - r1 |= (long)((Mul0x2(a1) ^ Mul0x3(a2) ^ a3 ^ a0) & 0xff) << j; - - r2 |= (long)((Mul0x2(a2) ^ Mul0x3(a3) ^ a0 ^ a1) & 0xff) << j; - - r3 |= (long)((Mul0x2(a3) ^ Mul0x3(a0) ^ a1 ^ a2) & 0xff) << j; - } - - A0 = r0; - A1 = r1; - A2 = r2; - A3 = r3; - } - - /** - * Mix the bytes of every column in a linear way - * This is the opposite operation of Mixcolumn - */ - - private void InvMixColumn() - { - long r0, - r1, - r2, - r3; - - r0 = r1 = r2 = r3 = 0; - for (int j = 0; j < BC; j += 8) - { - int a0 = (int)((A0 >> j) & 0xff); - int a1 = (int)((A1 >> j) & 0xff); - int a2 = (int)((A2 >> j) & 0xff); - int a3 = (int)((A3 >> j) & 0xff); - - // - // pre-lookup the log table - // - a0 = (a0 != 0) ? (Logtable[a0 & 0xff] & 0xff) : -1; - a1 = (a1 != 0) ? (Logtable[a1 & 0xff] & 0xff) : -1; - a2 = (a2 != 0) ? (Logtable[a2 & 0xff] & 0xff) : -1; - a3 = (a3 != 0) ? (Logtable[a3 & 0xff] & 0xff) : -1; - - r0 |= (long)((Mul0xe(a0) ^ Mul0xb(a1) ^ Mul0xd(a2) ^ Mul0x9(a3)) & 0xff) << j; - - r1 |= (long)((Mul0xe(a1) ^ Mul0xb(a2) ^ Mul0xd(a3) ^ Mul0x9(a0)) & 0xff) << j; - - r2 |= (long)((Mul0xe(a2) ^ Mul0xb(a3) ^ Mul0xd(a0) ^ Mul0x9(a1)) & 0xff) << j; - - r3 |= (long)((Mul0xe(a3) ^ Mul0xb(a0) ^ Mul0xd(a1) ^ Mul0x9(a2)) & 0xff) << j; - } - - A0 = r0; - A1 = r1; - A2 = r2; - A3 = r3; - } - - /** - * Calculate the necessary round keys - * The number of calculations depends on keyBits and blockBits - */ - - private long[][] GenerateWorkingKey(byte[] key) - { - int t, - rconpointer = 0; - int keyBits = key.Length * 8; - byte[,] tk = new byte[4, MAXKC]; - - //long[,] W = new long[MAXROUNDS+1,4]; - long[][] W = new long[MAXROUNDS + 1][]; - - for (int i = 0; i < MAXROUNDS + 1; i++) - { - W[i] = new long[4]; - } - - var KC = keyBits switch - { - 128 => 4, - 160 => 5, - 192 => 6, - 224 => 7, - 256 => 8, - _ => throw new ArgumentException("Key length not 128/160/192/224/256 bits."), - }; - if (keyBits >= blockBits) - { - ROUNDS = KC + 6; + for (var j = 1; j < KC; j++) + { + for (var i = 0; i < 4; i++) + { + tk[i, j] ^= tk[i, j - 1]; + } + } } else { - ROUNDS = (BC / 8) + 6; + for (var j = 1; j < 4; j++) + { + for (var i = 0; i < 4; i++) + { + tk[i, j] ^= tk[i, j - 1]; + } + } + for (var i = 0; i < 4; i++) + { + tk[i, 4] ^= S[tk[i, 3] & 0xff]; + } + for (var j = 5; j < KC; j++) + { + for (var i = 0; i < 4; i++) + { + tk[i, j] ^= tk[i, j - 1]; + } + } } - // - // copy the key into the processing area - // - int index = 0; - - for (int i = 0; i < key.Length; i++) - { - tk[i % 4, i / 4] = key[index++]; - } - - t = 0; - // // copy values into round key array // - for (int j = 0; (j < KC) && (t < (ROUNDS + 1) * (BC / 8)); j++, t++) + for (var j = 0; (j < KC) && (t < (ROUNDS + 1) * (BC / 8)); j++, t++) { - for (int i = 0; i < 4; i++) + for (var i = 0; i < 4; i++) { - W[t / (BC / 8)][i] |= (long)(tk[i, j] & 0xff) << ((t * 8) % BC); + W[t / (BC / 8)][i] |= (long)(tk[i, j] & 0xff) << ((t * 8) % (BC)); } } + } + return W; + } - // - // while not enough round key material calculated - // calculate new values - // - while (t < (ROUNDS + 1) * (BC / 8)) - { - for (int i = 0; i < 4; i++) - { - tk[i, 0] ^= S[tk[(i + 1) % 4, KC - 1] & 0xff]; - } - tk[0, 0] ^= rcon[rconpointer++]; + private readonly int BC; + private readonly long BC_MASK; + private int ROUNDS; + private readonly int blockBits; + private long[][]? workingKey; + private long A0, + A1, + A2, + A3; + private bool forEncryption; + private readonly byte[] shifts0SC; + private readonly byte[] shifts1SC; - if (KC <= 6) - { - for (int j = 1; j < KC; j++) - { - for (int i = 0; i < 4; i++) - { - tk[i, j] ^= tk[i, j - 1]; - } - } - } - else - { - for (int j = 1; j < 4; j++) - { - for (int i = 0; i < 4; i++) - { - tk[i, j] ^= tk[i, j - 1]; - } - } - for (int i = 0; i < 4; i++) - { - tk[i, 4] ^= S[tk[i, 3] & 0xff]; - } - for (int j = 5; j < KC; j++) - { - for (int i = 0; i < 4; i++) - { - tk[i, j] ^= tk[i, j - 1]; - } - } - } + /** + * default constructor - 128 bit block size. + */ - // - // copy values into round key array - // - for (int j = 0; (j < KC) && (t < (ROUNDS + 1) * (BC / 8)); j++, t++) - { - for (int i = 0; i < 4; i++) - { - W[t / (BC / 8)][i] |= (long)(tk[i, j] & 0xff) << ((t * 8) % (BC)); - } - } - } - return W; + public RijndaelEngine() : this(128) { } + + /** + * basic constructor - set the cipher up for a given blocksize + * + * @param blocksize the blocksize in bits, must be 128, 192, or 256. + */ + + public RijndaelEngine(int blockBits) + { + switch (blockBits) + { + case 128: + BC = 32; + BC_MASK = 0xffffffffL; + shifts0SC = shifts0[0]; + shifts1SC = shifts1[0]; + break; + case 160: + BC = 40; + BC_MASK = 0xffffffffffL; + shifts0SC = shifts0[1]; + shifts1SC = shifts1[1]; + break; + case 192: + BC = 48; + BC_MASK = 0xffffffffffffL; + shifts0SC = shifts0[2]; + shifts1SC = shifts1[2]; + break; + case 224: + BC = 56; + BC_MASK = 0xffffffffffffffL; + shifts0SC = shifts0[3]; + shifts1SC = shifts1[3]; + break; + case 256: + BC = 64; + BC_MASK = unchecked((long)0xffffffffffffffffL); + shifts0SC = shifts0[4]; + shifts1SC = shifts1[4]; + break; + default: + throw new ArgumentException("unknown blocksize to Rijndael"); } - private readonly int BC; - private readonly long BC_MASK; - private int ROUNDS; - private readonly int blockBits; - private long[][]? workingKey; - private long A0, - A1, - A2, - A3; - private bool forEncryption; - private readonly byte[] shifts0SC; - private readonly byte[] shifts1SC; + this.blockBits = blockBits; + } - /** - * default constructor - 128 bit block size. - */ + /** + * initialise a Rijndael cipher. + * + * @param forEncryption whether or not we are for encryption. + * @param parameters the parameters required to set up the cipher. + * @exception ArgumentException if the parameters argument is + * inappropriate. + */ - public RijndaelEngine() : this(128) { } - - /** - * basic constructor - set the cipher up for a given blocksize - * - * @param blocksize the blocksize in bits, must be 128, 192, or 256. - */ - - public RijndaelEngine(int blockBits) + public void Init(bool forEncryption, ICipherParameters parameters) + { + if (parameters is KeyParameter parameter) { - switch (blockBits) - { - case 128: - BC = 32; - BC_MASK = 0xffffffffL; - shifts0SC = shifts0[0]; - shifts1SC = shifts1[0]; - break; - case 160: - BC = 40; - BC_MASK = 0xffffffffffL; - shifts0SC = shifts0[1]; - shifts1SC = shifts1[1]; - break; - case 192: - BC = 48; - BC_MASK = 0xffffffffffffL; - shifts0SC = shifts0[2]; - shifts1SC = shifts1[2]; - break; - case 224: - BC = 56; - BC_MASK = 0xffffffffffffffL; - shifts0SC = shifts0[3]; - shifts1SC = shifts1[3]; - break; - case 256: - BC = 64; - BC_MASK = unchecked((long)0xffffffffffffffffL); - shifts0SC = shifts0[4]; - shifts1SC = shifts1[4]; - break; - default: - throw new ArgumentException("unknown blocksize to Rijndael"); - } - - this.blockBits = blockBits; + workingKey = GenerateWorkingKey(parameter.GetKey()); + this.forEncryption = forEncryption; + return; } - /** - * initialise a Rijndael cipher. - * - * @param forEncryption whether or not we are for encryption. - * @param parameters the parameters required to set up the cipher. - * @exception ArgumentException if the parameters argument is - * inappropriate. - */ + throw new ArgumentException( + "invalid parameter passed to Rijndael init - " + parameters.GetType() + ); + } - public void Init(bool forEncryption, ICipherParameters parameters) + public string AlgorithmName => "Rijndael"; + + public bool IsPartialBlockOkay => false; + + public int GetBlockSize() + { + return BC / 2; + } + + public int ProcessBlock(ReadOnlySpan input, Span output) + { + if (workingKey is null) { - var parameter = parameters as KeyParameter; - if (parameter != null) - { - workingKey = GenerateWorkingKey(parameter.GetKey()); - this.forEncryption = forEncryption; - return; - } - - throw new ArgumentException( - "invalid parameter passed to Rijndael init - " + parameters.GetType() - ); + throw new InvalidOperationException("Rijndael engine not initialised"); } - public string AlgorithmName => "Rijndael"; - - public bool IsPartialBlockOkay => false; - - public int GetBlockSize() + if (BC / 2 > input.Length) { - return BC / 2; + throw new DataLengthException("input buffer too short"); } - public int ProcessBlock(ReadOnlySpan input, Span output) + if (BC / 2 > output.Length) { - if (workingKey is null) - { - throw new InvalidOperationException("Rijndael engine not initialised"); - } - - if (BC / 2 > input.Length) - { - throw new DataLengthException("input buffer too short"); - } - - if (BC / 2 > output.Length) - { - throw new DataLengthException("output buffer too short"); - } - - UnPackBlock(input); - - if (forEncryption) - { - EncryptBlock(workingKey); - } - else - { - DecryptBlock(workingKey); - } - - PackBlock(output); - - return BC / 2; + throw new DataLengthException("output buffer too short"); } - public void Reset() { } + UnPackBlock(input); - private void UnPackBlock(ReadOnlySpan bytes) + if (forEncryption) { - int index = 0; - - A0 = bytes[index++] & 0xff; - A1 = bytes[index++] & 0xff; - A2 = bytes[index++] & 0xff; - A3 = bytes[index++] & 0xff; - - for (int j = 8; j != BC; j += 8) - { - A0 |= (long)(bytes[index++] & 0xff) << j; - A1 |= (long)(bytes[index++] & 0xff) << j; - A2 |= (long)(bytes[index++] & 0xff) << j; - A3 |= (long)(bytes[index++] & 0xff) << j; - } + EncryptBlock(workingKey); + } + else + { + DecryptBlock(workingKey); } - private void PackBlock(Span bytes) + PackBlock(output); + + return BC / 2; + } + + public void Reset() { } + + private void UnPackBlock(ReadOnlySpan bytes) + { + var index = 0; + + A0 = bytes[index++] & 0xff; + A1 = bytes[index++] & 0xff; + A2 = bytes[index++] & 0xff; + A3 = bytes[index++] & 0xff; + + for (var j = 8; j != BC; j += 8) { - int index = 0; - - for (int j = 0; j != BC; j += 8) - { - bytes[index++] = (byte)(A0 >> j); - bytes[index++] = (byte)(A1 >> j); - bytes[index++] = (byte)(A2 >> j); - bytes[index++] = (byte)(A3 >> j); - } - } - - private void EncryptBlock(long[][] rk) - { - int r; - - // - // begin with a key addition - // - KeyAddition(rk[0]); - - // - // ROUNDS-1 ordinary rounds - // - for (r = 1; r < ROUNDS; r++) - { - Substitution(S); - ShiftRow(shifts0SC); - MixColumn(); - KeyAddition(rk[r]); - } - - // - // Last round is special: there is no MixColumn - // - Substitution(S); - ShiftRow(shifts0SC); - KeyAddition(rk[ROUNDS]); - } - - private void DecryptBlock(long[][] rk) - { - int r; - - // To decrypt: apply the inverse operations of the encrypt routine, - // in opposite order - // - // (KeyAddition is an involution: it 's equal to its inverse) - // (the inverse of Substitution with table S is Substitution with the inverse table of S) - // (the inverse of Shiftrow is Shiftrow over a suitable distance) - // - - // First the special round: - // without InvMixColumn - // with extra KeyAddition - // - KeyAddition(rk[ROUNDS]); - Substitution(Si); - ShiftRow(shifts1SC); - - // - // ROUNDS-1 ordinary rounds - // - for (r = ROUNDS - 1; r > 0; r--) - { - KeyAddition(rk[r]); - InvMixColumn(); - Substitution(Si); - ShiftRow(shifts1SC); - } - - // - // End with the extra key addition - // - KeyAddition(rk[0]); + A0 |= (long)(bytes[index++] & 0xff) << j; + A1 |= (long)(bytes[index++] & 0xff) << j; + A2 |= (long)(bytes[index++] & 0xff) << j; + A3 |= (long)(bytes[index++] & 0xff) << j; } } + + private void PackBlock(Span bytes) + { + var index = 0; + + for (var j = 0; j != BC; j += 8) + { + bytes[index++] = (byte)(A0 >> j); + bytes[index++] = (byte)(A1 >> j); + bytes[index++] = (byte)(A2 >> j); + bytes[index++] = (byte)(A3 >> j); + } + } + + private void EncryptBlock(long[][] rk) + { + int r; + + // + // begin with a key addition + // + KeyAddition(rk[0]); + + // + // ROUNDS-1 ordinary rounds + // + for (r = 1; r < ROUNDS; r++) + { + Substitution(S); + ShiftRow(shifts0SC); + MixColumn(); + KeyAddition(rk[r]); + } + + // + // Last round is special: there is no MixColumn + // + Substitution(S); + ShiftRow(shifts0SC); + KeyAddition(rk[ROUNDS]); + } + + private void DecryptBlock(long[][] rk) + { + int r; + + // To decrypt: apply the inverse operations of the encrypt routine, + // in opposite order + // + // (KeyAddition is an involution: it 's equal to its inverse) + // (the inverse of Substitution with table S is Substitution with the inverse table of S) + // (the inverse of Shiftrow is Shiftrow over a suitable distance) + // + + // First the special round: + // without InvMixColumn + // with extra KeyAddition + // + KeyAddition(rk[ROUNDS]); + Substitution(Si); + ShiftRow(shifts1SC); + + // + // ROUNDS-1 ordinary rounds + // + for (r = ROUNDS - 1; r > 0; r--) + { + KeyAddition(rk[r]); + InvMixColumn(); + Substitution(Si); + ShiftRow(shifts1SC); + } + + // + // End with the extra key addition + // + KeyAddition(rk[0]); + } } diff --git a/src/SharpCompress/Factories/Factory.cs b/src/SharpCompress/Factories/Factory.cs index ba0bae88..b092a23a 100644 --- a/src/SharpCompress/Factories/Factory.cs +++ b/src/SharpCompress/Factories/Factory.cs @@ -1,96 +1,90 @@ using System; using System.Collections.Generic; using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -using SharpCompress.Archives; using SharpCompress.Common; using SharpCompress.IO; using SharpCompress.Readers; -namespace SharpCompress.Factories +namespace SharpCompress.Factories; + +/// +public abstract class Factory : IFactory { - /// - public abstract class Factory : IFactory + static Factory() { - static Factory() + RegisterFactory(new ZipFactory()); + RegisterFactory(new RarFactory()); + RegisterFactory(new SevenZipFactory()); + RegisterFactory(new GZipFactory()); + RegisterFactory(new TarFactory()); + } + + private static readonly HashSet _factories = new HashSet(); + + /// + /// Gets the collection of registered . + /// + public static IEnumerable Factories => _factories; + + /// + /// Registers an archive factory. + /// + /// The factory to register. + /// must not be null. + public static void RegisterFactory(Factory factory) + { + factory.CheckNotNull(nameof(factory)); + + _factories.Add(factory); + } + + /// + public abstract string Name { get; } + + /// + public virtual ArchiveType? KnownArchiveType => null; + + /// + public abstract IEnumerable GetSupportedExtensions(); + + /// + public abstract bool IsArchive(Stream stream, string? password = null); + + /// + public virtual FileInfo? GetFilePart(int index, FileInfo part1) + { + return null; + } + + /// + /// Tries to open an from a . + /// + /// + /// This method provides extra insight to support loading compressed TAR files. + /// + /// + /// + /// + /// + internal virtual bool TryOpenReader( + RewindableStream rewindableStream, + ReaderOptions options, + out IReader? reader + ) + { + reader = null; + + if (this is IReaderFactory readerFactory) { - RegisterFactory(new ZipFactory()); - RegisterFactory(new RarFactory()); - RegisterFactory(new SevenZipFactory()); - RegisterFactory(new GZipFactory()); - RegisterFactory(new TarFactory()); - } - - private static readonly HashSet _factories = new HashSet(); - - /// - /// Gets the collection of registered . - /// - public static IEnumerable Factories => _factories; - - /// - /// Registers an archive factory. - /// - /// The factory to register. - /// must not be null. - public static void RegisterFactory(Factory factory) - { - factory.CheckNotNull(nameof(factory)); - - _factories.Add(factory); - } - - /// - public abstract string Name { get; } - - /// - public virtual ArchiveType? KnownArchiveType => null; - - /// - public abstract IEnumerable GetSupportedExtensions(); - - /// - public abstract bool IsArchive(Stream stream, string? password = null); - - /// - public virtual FileInfo? GetFilePart(int index, FileInfo part1) - { - return null; - } - - /// - /// Tries to open an from a . - /// - /// - /// This method provides extra insight to support loading compressed TAR files. - /// - /// - /// - /// - /// - internal virtual bool TryOpenReader( - RewindableStream rewindableStream, - ReaderOptions options, - out IReader? reader - ) - { - reader = null; - - if (this is IReaderFactory readerFactory) + rewindableStream.Rewind(false); + if (IsArchive(rewindableStream, options.Password)) { - rewindableStream.Rewind(false); - if (this.IsArchive(rewindableStream, options.Password)) - { - rewindableStream.Rewind(true); - reader = readerFactory.OpenReader(rewindableStream, options); - return true; - } + rewindableStream.Rewind(true); + reader = readerFactory.OpenReader(rewindableStream, options); + return true; } - - return false; } + + return false; } } diff --git a/src/SharpCompress/Factories/GZipFactory.cs b/src/SharpCompress/Factories/GZipFactory.cs index 1c473e55..e504e577 100644 --- a/src/SharpCompress/Factories/GZipFactory.cs +++ b/src/SharpCompress/Factories/GZipFactory.cs @@ -1,8 +1,6 @@ -using System; using System.Collections.Generic; using System.IO; using System.IO.Compression; -using System.Linq; using SharpCompress.Archives; using SharpCompress.Archives.GZip; @@ -15,136 +13,135 @@ using SharpCompress.Readers.Tar; using SharpCompress.Writers; using SharpCompress.Writers.GZip; -namespace SharpCompress.Factories +namespace SharpCompress.Factories; + +/// +/// Represents the foundation factory of GZip archive. +/// +public class GZipFactory + : Factory, + IArchiveFactory, + IMultiArchiveFactory, + IReaderFactory, + IWriterFactory, + IWriteableArchiveFactory { - /// - /// Represents the foundation factory of GZip archive. - /// - public class GZipFactory - : Factory, - IArchiveFactory, - IMultiArchiveFactory, - IReaderFactory, - IWriterFactory, - IWriteableArchiveFactory + #region IFactory + + /// + public override string Name => "GZip"; + + /// + public override ArchiveType? KnownArchiveType => ArchiveType.GZip; + + /// + public override IEnumerable GetSupportedExtensions() { - #region IFactory + yield return "gz"; + } - /// - public override string Name => "GZip"; + /// + public override bool IsArchive(Stream stream, string? password = null) + { + return GZipArchive.IsGZipFile(stream); + } - /// - public override ArchiveType? KnownArchiveType => ArchiveType.GZip; + #endregion - /// - public override IEnumerable GetSupportedExtensions() + #region IArchiveFactory + + /// + public IArchive Open(Stream stream, ReaderOptions? readerOptions = null) + { + return GZipArchive.Open(stream, readerOptions); + } + + /// + public IArchive Open(FileInfo fileInfo, ReaderOptions? readerOptions = null) + { + return GZipArchive.Open(fileInfo, readerOptions); + } + + #endregion + + #region IMultiArchiveFactory + + /// + public IArchive Open(IReadOnlyList streams, ReaderOptions? readerOptions = null) + { + return GZipArchive.Open(streams, readerOptions); + } + + /// + public IArchive Open(IReadOnlyList fileInfos, ReaderOptions? readerOptions = null) + { + return GZipArchive.Open(fileInfos, readerOptions); + } + + #endregion + + #region IReaderFactory + + /// + internal override bool TryOpenReader( + RewindableStream rewindableStream, + ReaderOptions options, + out IReader? reader + ) + { + reader = null; + + rewindableStream.Rewind(false); + if (GZipArchive.IsGZipFile(rewindableStream)) { - yield return "gz"; - } - - /// - public override bool IsArchive(Stream stream, string? password = null) - { - return GZipArchive.IsGZipFile(stream); - } - - #endregion - - #region IArchiveFactory - - /// - public IArchive Open(Stream stream, ReaderOptions? readerOptions = null) - { - return GZipArchive.Open(stream, readerOptions); - } - - /// - public IArchive Open(FileInfo fileInfo, ReaderOptions? readerOptions = null) - { - return GZipArchive.Open(fileInfo, readerOptions); - } - - #endregion - - #region IMultiArchiveFactory - - /// - public IArchive Open(IReadOnlyList streams, ReaderOptions? readerOptions = null) - { - return GZipArchive.Open(streams, readerOptions); - } - - /// - public IArchive Open(IReadOnlyList fileInfos, ReaderOptions? readerOptions = null) - { - return GZipArchive.Open(fileInfos, readerOptions); - } - - #endregion - - #region IReaderFactory - - /// - internal override bool TryOpenReader( - RewindableStream rewindableStream, - ReaderOptions options, - out IReader? reader - ) - { - reader = null; - rewindableStream.Rewind(false); - if (GZipArchive.IsGZipFile(rewindableStream)) + var testStream = new GZipStream(rewindableStream, CompressionMode.Decompress); + if (TarArchive.IsTarFile(testStream)) { - rewindableStream.Rewind(false); - var testStream = new GZipStream(rewindableStream, CompressionMode.Decompress); - if (TarArchive.IsTarFile(testStream)) - { - rewindableStream.Rewind(true); - reader = new TarReader(rewindableStream, options, CompressionType.GZip); - return true; - } - rewindableStream.Rewind(true); - reader = OpenReader(rewindableStream, options); + reader = new TarReader(rewindableStream, options, CompressionType.GZip); return true; } - return false; + rewindableStream.Rewind(true); + reader = OpenReader(rewindableStream, options); + return true; } - /// - public IReader OpenReader(Stream stream, ReaderOptions? options) - { - return GZipReader.Open(stream, options); - } - - #endregion - - #region IWriterFactory - - /// - public IWriter Open(Stream stream, WriterOptions writerOptions) - { - if (writerOptions.CompressionType != CompressionType.GZip) - { - throw new InvalidFormatException( - "GZip archives only support GZip compression type." - ); - } - return new GZipWriter(stream, new GZipWriterOptions(writerOptions)); - } - - #endregion - - #region IWriteableArchiveFactory - - /// - public IWritableArchive CreateWriteableArchive() - { - return GZipArchive.Create(); - } - - #endregion + return false; } + + /// + public IReader OpenReader(Stream stream, ReaderOptions? options) + { + return GZipReader.Open(stream, options); + } + + #endregion + + #region IWriterFactory + + /// + public IWriter Open(Stream stream, WriterOptions writerOptions) + { + if (writerOptions.CompressionType != CompressionType.GZip) + { + throw new InvalidFormatException( + "GZip archives only support GZip compression type." + ); + } + return new GZipWriter(stream, new GZipWriterOptions(writerOptions)); + } + + #endregion + + #region IWriteableArchiveFactory + + /// + public IWritableArchive CreateWriteableArchive() + { + return GZipArchive.Create(); + } + + #endregion } diff --git a/src/SharpCompress/Factories/IFactory.cs b/src/SharpCompress/Factories/IFactory.cs index 39c2c384..08bedd50 100644 --- a/src/SharpCompress/Factories/IFactory.cs +++ b/src/SharpCompress/Factories/IFactory.cs @@ -1,54 +1,49 @@ -using System; using System.Collections.Generic; using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace SharpCompress.Factories +namespace SharpCompress.Factories; + +/// +/// Represents the foundation of an archive factory. +/// +/// +/// To get extended functionality, this type can be cast to:
+///
+///
+///
+///
+public interface IFactory { /// - /// Represents the foundation of an archive factory. + /// Gets the archive Type name /// - /// - /// To get extended functionality, this type can be cast to:
- ///
- ///
- ///
- ///
- public interface IFactory - { - /// - /// Gets the archive Type name - /// - string Name { get; } + string Name { get; } - /// - /// Gets the archive Type in case it is a well known archive format. - /// - Common.ArchiveType? KnownArchiveType { get; } + /// + /// Gets the archive Type in case it is a well known archive format. + /// + Common.ArchiveType? KnownArchiveType { get; } - /// - /// returns the extensions typically used by this archive type. - /// - /// - IEnumerable GetSupportedExtensions(); + /// + /// returns the extensions typically used by this archive type. + /// + /// + IEnumerable GetSupportedExtensions(); - /// - /// Returns true if the stream represents an archive of the format defined by this type. - /// - /// A stream, pointing to the beginning of the archive. - /// optional password - bool IsArchive(Stream stream, string? password = null); + /// + /// Returns true if the stream represents an archive of the format defined by this type. + /// + /// A stream, pointing to the beginning of the archive. + /// optional password + bool IsArchive(Stream stream, string? password = null); - /// - /// From a passed in archive (zip, rar, 7z, 001), return all parts. - /// - /// Path to the first part. - /// - /// The path to the requested part, - /// or NULL if the part does not exist. - /// - FileInfo? GetFilePart(int index, FileInfo part1); - } + /// + /// From a passed in archive (zip, rar, 7z, 001), return all parts. + /// + /// Path to the first part. + /// + /// The path to the requested part, + /// or NULL if the part does not exist. + /// + FileInfo? GetFilePart(int index, FileInfo part1); } diff --git a/src/SharpCompress/Factories/RarFactory.cs b/src/SharpCompress/Factories/RarFactory.cs index f9ffdb8c..77c04932 100644 --- a/src/SharpCompress/Factories/RarFactory.cs +++ b/src/SharpCompress/Factories/RarFactory.cs @@ -1,90 +1,86 @@ -using System; using System.Collections.Generic; using System.IO; -using System.Linq; using SharpCompress.Archives; using SharpCompress.Archives.Rar; using SharpCompress.Common; -using SharpCompress.IO; using SharpCompress.Readers; using SharpCompress.Readers.Rar; -namespace SharpCompress.Factories +namespace SharpCompress.Factories; + +/// +/// Represents the foundation factory of RAR archive. +/// +public class RarFactory : Factory, IArchiveFactory, IMultiArchiveFactory, IReaderFactory { - /// - /// Represents the foundation factory of RAR archive. - /// - public class RarFactory : Factory, IArchiveFactory, IMultiArchiveFactory, IReaderFactory + #region IArchive + + /// + public override string Name => "Rar"; + + /// + public override ArchiveType? KnownArchiveType => ArchiveType.Rar; + + /// + public override IEnumerable GetSupportedExtensions() { - #region IArchive - - /// - public override string Name => "Rar"; - - /// - public override ArchiveType? KnownArchiveType => ArchiveType.Rar; - - /// - public override IEnumerable GetSupportedExtensions() - { - yield return "rar"; - yield return "cbr"; - } - - /// - public override bool IsArchive(Stream stream, string? password = null) - { - return RarArchive.IsRarFile(stream); - } - - /// - public override FileInfo? GetFilePart(int index, FileInfo part1) - { - return RarArchiveVolumeFactory.GetFilePart(index, part1); - } - - #endregion - - #region IArchiveFactory - - /// - public IArchive Open(Stream stream, ReaderOptions? readerOptions = null) - { - return RarArchive.Open(stream, readerOptions); - } - - /// - public IArchive Open(FileInfo fileInfo, ReaderOptions? readerOptions = null) - { - return RarArchive.Open(fileInfo, readerOptions); - } - - #endregion - - #region IMultiArchiveFactory - - /// - public IArchive Open(IReadOnlyList streams, ReaderOptions? readerOptions = null) - { - return RarArchive.Open(streams, readerOptions); - } - - /// - public IArchive Open(IReadOnlyList fileInfos, ReaderOptions? readerOptions = null) - { - return RarArchive.Open(fileInfos, readerOptions); - } - - #endregion - - #region IReaderFactory - - /// - public IReader OpenReader(Stream stream, ReaderOptions? options) - { - return RarReader.Open(stream, options); - } - - #endregion + yield return "rar"; + yield return "cbr"; } + + /// + public override bool IsArchive(Stream stream, string? password = null) + { + return RarArchive.IsRarFile(stream); + } + + /// + public override FileInfo? GetFilePart(int index, FileInfo part1) + { + return RarArchiveVolumeFactory.GetFilePart(index, part1); + } + + #endregion + + #region IArchiveFactory + + /// + public IArchive Open(Stream stream, ReaderOptions? readerOptions = null) + { + return RarArchive.Open(stream, readerOptions); + } + + /// + public IArchive Open(FileInfo fileInfo, ReaderOptions? readerOptions = null) + { + return RarArchive.Open(fileInfo, readerOptions); + } + + #endregion + + #region IMultiArchiveFactory + + /// + public IArchive Open(IReadOnlyList streams, ReaderOptions? readerOptions = null) + { + return RarArchive.Open(streams, readerOptions); + } + + /// + public IArchive Open(IReadOnlyList fileInfos, ReaderOptions? readerOptions = null) + { + return RarArchive.Open(fileInfos, readerOptions); + } + + #endregion + + #region IReaderFactory + + /// + public IReader OpenReader(Stream stream, ReaderOptions? options) + { + return RarReader.Open(stream, options); + } + + #endregion } diff --git a/src/SharpCompress/Factories/SevenZipFactory.cs b/src/SharpCompress/Factories/SevenZipFactory.cs index 8bdbb8d0..7e06d9e0 100644 --- a/src/SharpCompress/Factories/SevenZipFactory.cs +++ b/src/SharpCompress/Factories/SevenZipFactory.cs @@ -1,87 +1,83 @@ -using System; using System.Collections.Generic; using System.IO; -using System.Linq; using SharpCompress.Archives; using SharpCompress.Archives.SevenZip; using SharpCompress.Common; -using SharpCompress.Common.SevenZip; using SharpCompress.IO; using SharpCompress.Readers; -namespace SharpCompress.Factories +namespace SharpCompress.Factories; + +/// +/// Represents the foundation factory of 7Zip archive. +/// +public class SevenZipFactory : Factory, IArchiveFactory, IMultiArchiveFactory { - /// - /// Represents the foundation factory of 7Zip archive. - /// - public class SevenZipFactory : Factory, IArchiveFactory, IMultiArchiveFactory + #region IFactory + + /// + public override string Name => "7Zip"; + + /// + public override ArchiveType? KnownArchiveType => ArchiveType.SevenZip; + + /// + public override IEnumerable GetSupportedExtensions() { - #region IFactory - - /// - public override string Name => "7Zip"; - - /// - public override ArchiveType? KnownArchiveType => ArchiveType.SevenZip; - - /// - public override IEnumerable GetSupportedExtensions() - { - yield return "7z"; - } - - /// - public override bool IsArchive(Stream stream, string? password = null) - { - return SevenZipArchive.IsSevenZipFile(stream); - } - - #endregion - - #region IArchiveFactory - - /// - public IArchive Open(Stream stream, ReaderOptions? readerOptions = null) - { - return SevenZipArchive.Open(stream, readerOptions); - } - - /// - public IArchive Open(FileInfo fileInfo, ReaderOptions? readerOptions = null) - { - return SevenZipArchive.Open(fileInfo, readerOptions); - } - - #endregion - - #region IMultiArchiveFactory - - /// - public IArchive Open(IReadOnlyList streams, ReaderOptions? readerOptions = null) - { - return SevenZipArchive.Open(streams, readerOptions); - } - - /// - public IArchive Open(IReadOnlyList fileInfos, ReaderOptions? readerOptions = null) - { - return SevenZipArchive.Open(fileInfos, readerOptions); - } - - #endregion - - #region reader - - internal override bool TryOpenReader( - RewindableStream rewindableStream, - ReaderOptions options, - out IReader? reader - ) - { - reader = null; - return false; - } - - #endregion + yield return "7z"; } + + /// + public override bool IsArchive(Stream stream, string? password = null) + { + return SevenZipArchive.IsSevenZipFile(stream); + } + + #endregion + + #region IArchiveFactory + + /// + public IArchive Open(Stream stream, ReaderOptions? readerOptions = null) + { + return SevenZipArchive.Open(stream, readerOptions); + } + + /// + public IArchive Open(FileInfo fileInfo, ReaderOptions? readerOptions = null) + { + return SevenZipArchive.Open(fileInfo, readerOptions); + } + + #endregion + + #region IMultiArchiveFactory + + /// + public IArchive Open(IReadOnlyList streams, ReaderOptions? readerOptions = null) + { + return SevenZipArchive.Open(streams, readerOptions); + } + + /// + public IArchive Open(IReadOnlyList fileInfos, ReaderOptions? readerOptions = null) + { + return SevenZipArchive.Open(fileInfos, readerOptions); + } + + #endregion + + #region reader + + internal override bool TryOpenReader( + RewindableStream rewindableStream, + ReaderOptions options, + out IReader? reader + ) + { + reader = null; + return false; + } + + #endregion } diff --git a/src/SharpCompress/Factories/TarFactory.cs b/src/SharpCompress/Factories/TarFactory.cs index b2322d56..747ec17f 100644 --- a/src/SharpCompress/Factories/TarFactory.cs +++ b/src/SharpCompress/Factories/TarFactory.cs @@ -1,11 +1,8 @@ -using System; using System.Collections.Generic; using System.IO; -using System.Linq; using SharpCompress.Archives; using SharpCompress.Archives.Tar; -using SharpCompress.Archives.Zip; using SharpCompress.Common; using SharpCompress.Compressors; using SharpCompress.Compressors.BZip2; @@ -17,192 +14,191 @@ using SharpCompress.Readers.Tar; using SharpCompress.Writers; using SharpCompress.Writers.Tar; -namespace SharpCompress.Factories +namespace SharpCompress.Factories; + +/// +/// Represents the foundation factory of TAR archive. +/// +public class TarFactory + : Factory, + IArchiveFactory, + IMultiArchiveFactory, + IReaderFactory, + IWriterFactory, + IWriteableArchiveFactory { - /// - /// Represents the foundation factory of TAR archive. - /// - public class TarFactory - : Factory, - IArchiveFactory, - IMultiArchiveFactory, - IReaderFactory, - IWriterFactory, - IWriteableArchiveFactory + #region IFactory + + /// + public override string Name => "Tar"; + + /// + public override ArchiveType? KnownArchiveType => ArchiveType.Tar; + + /// + public override IEnumerable GetSupportedExtensions() { - #region IFactory + // from https://en.wikipedia.org/wiki/Tar_(computing)#Suffixes_for_compressed_files - /// - public override string Name => "Tar"; + yield return "tar"; - /// - public override ArchiveType? KnownArchiveType => ArchiveType.Tar; + // gzip + yield return "taz"; + yield return "tgz"; - /// - public override IEnumerable GetSupportedExtensions() + // bzip2 + yield return "tb2"; + yield return "tbz"; + yield return "tbz2"; + yield return "tz2"; + + // lzma + // yield return "tlz"; // unsupported + + // xz + // yield return "txz"; // unsupported + + // compress + yield return "tZ"; + yield return "taZ"; + + // zstd + // yield return "tzst"; // unsupported + } + + /// + public override bool IsArchive(Stream stream, string? password = null) + { + return TarArchive.IsTarFile(stream); + } + + #endregion + + #region IArchiveFactory + + /// + public IArchive Open(Stream stream, ReaderOptions? readerOptions = null) + { + return TarArchive.Open(stream, readerOptions); + } + + /// + public IArchive Open(FileInfo fileInfo, ReaderOptions? readerOptions = null) + { + return TarArchive.Open(fileInfo, readerOptions); + } + + #endregion + + #region IMultiArchiveFactory + + /// + public IArchive Open(IReadOnlyList streams, ReaderOptions? readerOptions = null) + { + return TarArchive.Open(streams, readerOptions); + } + + /// + public IArchive Open(IReadOnlyList fileInfos, ReaderOptions? readerOptions = null) + { + return TarArchive.Open(fileInfos, readerOptions); + } + + #endregion + + #region IReaderFactory + + /// + internal override bool TryOpenReader( + RewindableStream rewindableStream, + ReaderOptions options, + out IReader? reader + ) + { + reader = null; + + rewindableStream.Rewind(false); + if (TarArchive.IsTarFile(rewindableStream)) { - // from https://en.wikipedia.org/wiki/Tar_(computing)#Suffixes_for_compressed_files - - yield return "tar"; - - // gzip - yield return "taz"; - yield return "tgz"; - - // bzip2 - yield return "tb2"; - yield return "tbz"; - yield return "tbz2"; - yield return "tz2"; - - // lzma - // yield return "tlz"; // unsupported - - // xz - // yield return "txz"; // unsupported - - // compress - yield return "tZ"; - yield return "taZ"; - - // zstd - // yield return "tzst"; // unsupported + rewindableStream.Rewind(true); + reader = OpenReader(rewindableStream, options); + return true; } - /// - public override bool IsArchive(Stream stream, string? password = null) + rewindableStream.Rewind(false); + if (BZip2Stream.IsBZip2(rewindableStream)) { - return TarArchive.IsTarFile(stream); - } - - #endregion - - #region IArchiveFactory - - /// - public IArchive Open(Stream stream, ReaderOptions? readerOptions = null) - { - return TarArchive.Open(stream, readerOptions); - } - - /// - public IArchive Open(FileInfo fileInfo, ReaderOptions? readerOptions = null) - { - return TarArchive.Open(fileInfo, readerOptions); - } - - #endregion - - #region IMultiArchiveFactory - - /// - public IArchive Open(IReadOnlyList streams, ReaderOptions? readerOptions = null) - { - return TarArchive.Open(streams, readerOptions); - } - - /// - public IArchive Open(IReadOnlyList fileInfos, ReaderOptions? readerOptions = null) - { - return TarArchive.Open(fileInfos, readerOptions); - } - - #endregion - - #region IReaderFactory - - /// - internal override bool TryOpenReader( - RewindableStream rewindableStream, - ReaderOptions options, - out IReader? reader - ) - { - reader = null; - rewindableStream.Rewind(false); - if (TarArchive.IsTarFile(rewindableStream)) + var testStream = new BZip2Stream( + NonDisposingStream.Create(rewindableStream), + CompressionMode.Decompress, + false + ); + if (TarArchive.IsTarFile(testStream)) { rewindableStream.Rewind(true); - reader = OpenReader(rewindableStream, options); + reader = new TarReader(rewindableStream, options, CompressionType.BZip2); return true; } + } + rewindableStream.Rewind(false); + if (LZipStream.IsLZipFile(rewindableStream)) + { rewindableStream.Rewind(false); - if (BZip2Stream.IsBZip2(rewindableStream)) - { - rewindableStream.Rewind(false); - var testStream = new BZip2Stream( - NonDisposingStream.Create(rewindableStream), - CompressionMode.Decompress, - false - ); - if (TarArchive.IsTarFile(testStream)) - { - rewindableStream.Rewind(true); - reader = new TarReader(rewindableStream, options, CompressionType.BZip2); - return true; - } - } - - rewindableStream.Rewind(false); - if (LZipStream.IsLZipFile(rewindableStream)) - { - rewindableStream.Rewind(false); - var testStream = new LZipStream( - NonDisposingStream.Create(rewindableStream), - CompressionMode.Decompress - ); - if (TarArchive.IsTarFile(testStream)) - { - rewindableStream.Rewind(true); - reader = new TarReader(rewindableStream, options, CompressionType.LZip); - return true; - } - } - - rewindableStream.Rewind(false); - if (XZStream.IsXZStream(rewindableStream)) + var testStream = new LZipStream( + NonDisposingStream.Create(rewindableStream), + CompressionMode.Decompress + ); + if (TarArchive.IsTarFile(testStream)) { rewindableStream.Rewind(true); - var testStream = new XZStream(rewindableStream); - if (TarArchive.IsTarFile(testStream)) - { - rewindableStream.Rewind(true); - reader = new TarReader(rewindableStream, options, CompressionType.Xz); - return true; - } + reader = new TarReader(rewindableStream, options, CompressionType.LZip); + return true; } - - return false; } - /// - public IReader OpenReader(Stream stream, ReaderOptions? options) + rewindableStream.Rewind(false); + if (XZStream.IsXZStream(rewindableStream)) { - return TarReader.Open(stream, options); + rewindableStream.Rewind(true); + var testStream = new XZStream(rewindableStream); + if (TarArchive.IsTarFile(testStream)) + { + rewindableStream.Rewind(true); + reader = new TarReader(rewindableStream, options, CompressionType.Xz); + return true; + } } - #endregion - - #region IWriterFactory - - /// - public IWriter Open(Stream stream, WriterOptions writerOptions) - { - return new TarWriter(stream, new TarWriterOptions(writerOptions)); - } - - #endregion - - #region IWriteableArchiveFactory - - /// - public IWritableArchive CreateWriteableArchive() - { - return TarArchive.Create(); - } - - #endregion + return false; } + + /// + public IReader OpenReader(Stream stream, ReaderOptions? options) + { + return TarReader.Open(stream, options); + } + + #endregion + + #region IWriterFactory + + /// + public IWriter Open(Stream stream, WriterOptions writerOptions) + { + return new TarWriter(stream, new TarWriterOptions(writerOptions)); + } + + #endregion + + #region IWriteableArchiveFactory + + /// + public IWritableArchive CreateWriteableArchive() + { + return TarArchive.Create(); + } + + #endregion } diff --git a/src/SharpCompress/Factories/ZipFactory.cs b/src/SharpCompress/Factories/ZipFactory.cs index 66b274cb..64162b68 100644 --- a/src/SharpCompress/Factories/ZipFactory.cs +++ b/src/SharpCompress/Factories/ZipFactory.cs @@ -1,139 +1,140 @@ -using System; using System.Collections.Generic; using System.IO; -using System.Linq; using SharpCompress.Archives; using SharpCompress.Archives.Zip; using SharpCompress.Common; -using SharpCompress.Common.Tar.Headers; -using SharpCompress.IO; using SharpCompress.Readers; using SharpCompress.Readers.Zip; using SharpCompress.Writers; using SharpCompress.Writers.Zip; -namespace SharpCompress.Factories +namespace SharpCompress.Factories; + +/// +/// Represents the foundation factory of ZIP archive. +/// +public class ZipFactory + : Factory, + IArchiveFactory, + IMultiArchiveFactory, + IReaderFactory, + IWriterFactory, + IWriteableArchiveFactory { - /// - /// Represents the foundation factory of ZIP archive. - /// - public class ZipFactory - : Factory, - IArchiveFactory, - IMultiArchiveFactory, - IReaderFactory, - IWriterFactory, - IWriteableArchiveFactory + #region IFactory + + /// + public override string Name => "Zip"; + + /// + public override ArchiveType? KnownArchiveType => ArchiveType.Zip; + + /// + public override IEnumerable GetSupportedExtensions() { - #region IFactory + yield return "zip"; + yield return "zipx"; + yield return "cbz"; + } - /// - public override string Name => "Zip"; + /// + public override bool IsArchive(Stream stream, string? password = null) + { + var startPosition = stream.CanSeek ? stream.Position : -1; - /// - public override ArchiveType? KnownArchiveType => ArchiveType.Zip; + // probe for single volume zip - /// - public override IEnumerable GetSupportedExtensions() + if (ZipArchive.IsZipFile(stream, password)) { - yield return "zip"; - yield return "zipx"; - yield return "cbz"; + return true; } - /// - public override bool IsArchive(Stream stream, string? password = null) + // probe for a multipart zip + + if (!stream.CanSeek) { - var startPosition = stream.CanSeek ? stream.Position : -1; - - // probe for single volume zip - - if (ZipArchive.IsZipFile(stream, password)) - return true; - - // probe for a multipart zip - - if (!stream.CanSeek) - return false; - - stream.Position = startPosition; - - //test the zip (last) file of a multipart zip - if (ZipArchive.IsZipMulti(stream)) - return true; - return false; } - /// - public override FileInfo? GetFilePart(int index, FileInfo part1) + stream.Position = startPosition; + + //test the zip (last) file of a multipart zip + if (ZipArchive.IsZipMulti(stream)) { - return ZipArchiveVolumeFactory.GetFilePart(index, part1); + return true; } - #endregion - - #region IArchiveFactory - - /// - public IArchive Open(Stream stream, ReaderOptions? readerOptions = null) - { - return ZipArchive.Open(stream, readerOptions); - } - - /// - public IArchive Open(FileInfo fileInfo, ReaderOptions? readerOptions = null) - { - return ZipArchive.Open(fileInfo, readerOptions); - } - - #endregion - - #region IMultiArchiveFactory - - /// - public IArchive Open(IReadOnlyList streams, ReaderOptions? readerOptions = null) - { - return ZipArchive.Open(streams, readerOptions); - } - - /// - public IArchive Open(IReadOnlyList fileInfos, ReaderOptions? readerOptions = null) - { - return ZipArchive.Open(fileInfos, readerOptions); - } - - #endregion - - #region IReaderFactory - - /// - public IReader OpenReader(Stream stream, ReaderOptions? options) - { - return ZipReader.Open(stream, options); - } - - #endregion - - #region IWriterFactory - - /// - public IWriter Open(Stream stream, WriterOptions writerOptions) - { - return new ZipWriter(stream, new ZipWriterOptions(writerOptions)); - } - - #endregion - - #region IWriteableArchiveFactory - - /// - public IWritableArchive CreateWriteableArchive() - { - return ZipArchive.Create(); - } - - #endregion + return false; } + + /// + public override FileInfo? GetFilePart(int index, FileInfo part1) + { + return ZipArchiveVolumeFactory.GetFilePart(index, part1); + } + + #endregion + + #region IArchiveFactory + + /// + public IArchive Open(Stream stream, ReaderOptions? readerOptions = null) + { + return ZipArchive.Open(stream, readerOptions); + } + + /// + public IArchive Open(FileInfo fileInfo, ReaderOptions? readerOptions = null) + { + return ZipArchive.Open(fileInfo, readerOptions); + } + + #endregion + + #region IMultiArchiveFactory + + /// + public IArchive Open(IReadOnlyList streams, ReaderOptions? readerOptions = null) + { + return ZipArchive.Open(streams, readerOptions); + } + + /// + public IArchive Open(IReadOnlyList fileInfos, ReaderOptions? readerOptions = null) + { + return ZipArchive.Open(fileInfos, readerOptions); + } + + #endregion + + #region IReaderFactory + + /// + public IReader OpenReader(Stream stream, ReaderOptions? options) + { + return ZipReader.Open(stream, options); + } + + #endregion + + #region IWriterFactory + + /// + public IWriter Open(Stream stream, WriterOptions writerOptions) + { + return new ZipWriter(stream, new ZipWriterOptions(writerOptions)); + } + + #endregion + + #region IWriteableArchiveFactory + + /// + public IWritableArchive CreateWriteableArchive() + { + return ZipArchive.Create(); + } + + #endregion } diff --git a/src/SharpCompress/IO/BufferedSubStream.cs b/src/SharpCompress/IO/BufferedSubStream.cs index 94d70b17..37e7e0bb 100644 --- a/src/SharpCompress/IO/BufferedSubStream.cs +++ b/src/SharpCompress/IO/BufferedSubStream.cs @@ -1,88 +1,87 @@ -using System; +using System; using System.IO; -namespace SharpCompress.IO +namespace SharpCompress.IO; + +internal class BufferedSubStream : NonDisposingStream { - internal class BufferedSubStream : NonDisposingStream + private long position; + private int cacheOffset; + private int cacheLength; + private readonly byte[] cache; + + public BufferedSubStream(Stream stream, long origin, long bytesToRead) + : base(stream, throwOnDispose: false) { - private long position; - private int cacheOffset; - private int cacheLength; - private readonly byte[] cache; + position = origin; + BytesLeftToRead = bytesToRead; + cache = new byte[32 << 10]; + } - public BufferedSubStream(Stream stream, long origin, long bytesToRead) - : base(stream, throwOnDispose: false) + private long BytesLeftToRead { get; set; } + + public override bool CanRead => true; + + public override bool CanSeek => false; + + public override bool CanWrite => false; + + public override void Flush() + { + throw new NotSupportedException(); + } + + public override long Length => BytesLeftToRead; + + public override long Position + { + get => throw new NotSupportedException(); + set => throw new NotSupportedException(); + } + + public override int Read(byte[] buffer, int offset, int count) + { + if (count > BytesLeftToRead) { - position = origin; - BytesLeftToRead = bytesToRead; - cache = new byte[32 << 10]; + count = (int)BytesLeftToRead; } - private long BytesLeftToRead { get; set; } - - public override bool CanRead => true; - - public override bool CanSeek => false; - - public override bool CanWrite => false; - - public override void Flush() + if (count > 0) { - throw new NotSupportedException(); - } - - public override long Length => BytesLeftToRead; - - public override long Position - { - get => throw new NotSupportedException(); - set => throw new NotSupportedException(); - } - - public override int Read(byte[] buffer, int offset, int count) - { - if (count > BytesLeftToRead) + if (cacheLength == 0) { - count = (int)BytesLeftToRead; + cacheOffset = 0; + Stream.Position = position; + cacheLength = Stream.Read(cache, 0, cache.Length); + position += cacheLength; } - if (count > 0) + if (count > cacheLength) { - if (cacheLength == 0) - { - cacheOffset = 0; - Stream.Position = position; - cacheLength = Stream.Read(cache, 0, cache.Length); - position += cacheLength; - } - - if (count > cacheLength) - { - count = cacheLength; - } - - Buffer.BlockCopy(cache, cacheOffset, buffer, offset, count); - cacheOffset += count; - cacheLength -= count; - BytesLeftToRead -= count; + count = cacheLength; } - return count; + Buffer.BlockCopy(cache, cacheOffset, buffer, offset, count); + cacheOffset += count; + cacheLength -= count; + BytesLeftToRead -= count; } - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } + return count; + } - public override void SetLength(long value) - { - throw new NotSupportedException(); - } + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } - public override void Write(byte[] buffer, int offset, int count) - { - throw new NotSupportedException(); - } + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + public override void Write(byte[] buffer, int offset, int count) + { + throw new NotSupportedException(); } } diff --git a/src/SharpCompress/IO/CountingWritableSubStream.cs b/src/SharpCompress/IO/CountingWritableSubStream.cs index a5aa4465..5a3a990d 100644 --- a/src/SharpCompress/IO/CountingWritableSubStream.cs +++ b/src/SharpCompress/IO/CountingWritableSubStream.cs @@ -1,58 +1,57 @@ using System; using System.IO; -namespace SharpCompress.IO +namespace SharpCompress.IO; + +internal class CountingWritableSubStream : NonDisposingStream { - internal class CountingWritableSubStream : NonDisposingStream + internal CountingWritableSubStream(Stream stream) : base(stream, throwOnDispose: false) { } + + public ulong Count { get; private set; } + + public override bool CanRead => false; + + public override bool CanSeek => false; + + public override bool CanWrite => true; + + public override void Flush() { - internal CountingWritableSubStream(Stream stream) : base(stream, throwOnDispose: false) { } + Stream.Flush(); + } - public ulong Count { get; private set; } + public override long Length => throw new NotSupportedException(); - public override bool CanRead => false; + public override long Position + { + get => throw new NotSupportedException(); + set => throw new NotSupportedException(); + } - public override bool CanSeek => false; + public override int Read(byte[] buffer, int offset, int count) + { + throw new NotSupportedException(); + } - public override bool CanWrite => true; + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } - public override void Flush() - { - Stream.Flush(); - } + public override void SetLength(long value) + { + throw new NotSupportedException(); + } - public override long Length => throw new NotSupportedException(); + public override void Write(byte[] buffer, int offset, int count) + { + Stream.Write(buffer, offset, count); + Count += (uint)count; + } - public override long Position - { - get => throw new NotSupportedException(); - set => throw new NotSupportedException(); - } - - public override int Read(byte[] buffer, int offset, int count) - { - throw new NotSupportedException(); - } - - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } - - public override void SetLength(long value) - { - throw new NotSupportedException(); - } - - public override void Write(byte[] buffer, int offset, int count) - { - Stream.Write(buffer, offset, count); - Count += (uint)count; - } - - public override void WriteByte(byte value) - { - Stream.WriteByte(value); - ++Count; - } + public override void WriteByte(byte value) + { + Stream.WriteByte(value); + ++Count; } } diff --git a/src/SharpCompress/IO/ListeningStream.cs b/src/SharpCompress/IO/ListeningStream.cs index d914bec4..0cccdc6b 100644 --- a/src/SharpCompress/IO/ListeningStream.cs +++ b/src/SharpCompress/IO/ListeningStream.cs @@ -1,89 +1,88 @@ -using System.IO; +using System.IO; using SharpCompress.Common; -namespace SharpCompress.IO +namespace SharpCompress.IO; + +internal class ListeningStream : Stream { - internal class ListeningStream : Stream + private long currentEntryTotalReadBytes; + private readonly IExtractionListener listener; + + public ListeningStream(IExtractionListener listener, Stream stream) { - private long currentEntryTotalReadBytes; - private readonly IExtractionListener listener; + Stream = stream; + this.listener = listener; + } - public ListeningStream(IExtractionListener listener, Stream stream) + protected override void Dispose(bool disposing) + { + if (disposing) { - Stream = stream; - this.listener = listener; + Stream.Dispose(); + } + base.Dispose(disposing); + } + + public Stream Stream { get; } + + public override bool CanRead => Stream.CanRead; + + public override bool CanSeek => Stream.CanSeek; + + public override bool CanWrite => Stream.CanWrite; + + public override void Flush() + { + Stream.Flush(); + } + + public override long Length => Stream.Length; + + public override long Position + { + get => Stream.Position; + set => Stream.Position = value; + } + + public override int Read(byte[] buffer, int offset, int count) + { + var read = Stream.Read(buffer, offset, count); + currentEntryTotalReadBytes += read; + listener.FireCompressedBytesRead( + currentEntryTotalReadBytes, + currentEntryTotalReadBytes + ); + return read; + } + + public override int ReadByte() + { + var value = Stream.ReadByte(); + if (value == -1) + { + return -1; } - protected override void Dispose(bool disposing) - { - if (disposing) - { - Stream.Dispose(); - } - base.Dispose(disposing); - } + ++currentEntryTotalReadBytes; + listener.FireCompressedBytesRead( + currentEntryTotalReadBytes, + currentEntryTotalReadBytes + ); + return value; + } - public Stream Stream { get; } + public override long Seek(long offset, SeekOrigin origin) + { + return Stream.Seek(offset, origin); + } - public override bool CanRead => Stream.CanRead; + public override void SetLength(long value) + { + Stream.SetLength(value); + } - public override bool CanSeek => Stream.CanSeek; - - public override bool CanWrite => Stream.CanWrite; - - public override void Flush() - { - Stream.Flush(); - } - - public override long Length => Stream.Length; - - public override long Position - { - get => Stream.Position; - set => Stream.Position = value; - } - - public override int Read(byte[] buffer, int offset, int count) - { - int read = Stream.Read(buffer, offset, count); - currentEntryTotalReadBytes += read; - listener.FireCompressedBytesRead( - currentEntryTotalReadBytes, - currentEntryTotalReadBytes - ); - return read; - } - - public override int ReadByte() - { - int value = Stream.ReadByte(); - if (value == -1) - { - return -1; - } - - ++currentEntryTotalReadBytes; - listener.FireCompressedBytesRead( - currentEntryTotalReadBytes, - currentEntryTotalReadBytes - ); - return value; - } - - public override long Seek(long offset, SeekOrigin origin) - { - return Stream.Seek(offset, origin); - } - - public override void SetLength(long value) - { - Stream.SetLength(value); - } - - public override void Write(byte[] buffer, int offset, int count) - { - Stream.Write(buffer, offset, count); - } + public override void Write(byte[] buffer, int offset, int count) + { + Stream.Write(buffer, offset, count); } } diff --git a/src/SharpCompress/IO/MarkingBinaryReader.cs b/src/SharpCompress/IO/MarkingBinaryReader.cs index 01847518..144a702b 100644 --- a/src/SharpCompress/IO/MarkingBinaryReader.cs +++ b/src/SharpCompress/IO/MarkingBinaryReader.cs @@ -1,214 +1,213 @@ -using System; +using System; using System.Buffers.Binary; using System.IO; -namespace SharpCompress.IO +namespace SharpCompress.IO; + +internal class MarkingBinaryReader : BinaryReader { - internal class MarkingBinaryReader : BinaryReader + public MarkingBinaryReader(Stream stream) : base(stream) { } + + public virtual long CurrentReadByteCount { get; protected set; } + + public virtual void Mark() { - public MarkingBinaryReader(Stream stream) : base(stream) { } + CurrentReadByteCount = 0; + } - public virtual long CurrentReadByteCount { get; protected set; } + public override int Read() + { + throw new NotSupportedException(); + } - public virtual void Mark() + public override int Read(byte[] buffer, int index, int count) + { + throw new NotSupportedException(); + } + + public override int Read(char[] buffer, int index, int count) + { + throw new NotSupportedException(); + } + + public override bool ReadBoolean() + { + return ReadByte() != 0; + } + + // NOTE: there is a somewhat fragile dependency on the internals of this class + // with RarCrcBinaryReader and RarCryptoBinaryReader. + // + // RarCrcBinaryReader/RarCryptoBinaryReader need to override any specific methods + // that call directly to the base BinaryReader and do not delegate to other methods + // in this class so that it can track the each byte being read. + // + // if altering this class in a way that changes the implementation be sure to + // update RarCrcBinaryReader/RarCryptoBinaryReader. + public override byte ReadByte() + { + CurrentReadByteCount++; + return base.ReadByte(); + } + + public override byte[] ReadBytes(int count) + { + CurrentReadByteCount += count; + var bytes = base.ReadBytes(count); + if (bytes.Length != count) { - CurrentReadByteCount = 0; + throw new EndOfStreamException( + string.Format( + "Could not read the requested amount of bytes. End of stream reached. Requested: {0} Read: {1}", + count, + bytes.Length + ) + ); } + return bytes; + } - public override int Read() - { - throw new NotSupportedException(); - } + public override char ReadChar() + { + throw new NotSupportedException(); + } - public override int Read(byte[] buffer, int index, int count) - { - throw new NotSupportedException(); - } + public override char[] ReadChars(int count) + { + throw new NotSupportedException(); + } - public override int Read(char[] buffer, int index, int count) - { - throw new NotSupportedException(); - } + public override double ReadDouble() + { + throw new NotSupportedException(); + } - public override bool ReadBoolean() - { - return ReadByte() != 0; - } + public override short ReadInt16() + { + return BinaryPrimitives.ReadInt16LittleEndian(ReadBytes(2)); + } - // NOTE: there is a somewhat fragile dependency on the internals of this class - // with RarCrcBinaryReader and RarCryptoBinaryReader. - // - // RarCrcBinaryReader/RarCryptoBinaryReader need to override any specific methods - // that call directly to the base BinaryReader and do not delegate to other methods - // in this class so that it can track the each byte being read. - // - // if altering this class in a way that changes the implementation be sure to - // update RarCrcBinaryReader/RarCryptoBinaryReader. - public override byte ReadByte() - { - CurrentReadByteCount++; - return base.ReadByte(); - } + public override int ReadInt32() + { + return BinaryPrimitives.ReadInt32LittleEndian(ReadBytes(4)); + } - public override byte[] ReadBytes(int count) + public override long ReadInt64() + { + return BinaryPrimitives.ReadInt64LittleEndian(ReadBytes(8)); + } + + public override sbyte ReadSByte() + { + return (sbyte)ReadByte(); + } + + public override float ReadSingle() + { + throw new NotSupportedException(); + } + + public override string ReadString() + { + throw new NotSupportedException(); + } + + public override ushort ReadUInt16() + { + return BinaryPrimitives.ReadUInt16LittleEndian(ReadBytes(2)); + } + + public override uint ReadUInt32() + { + return BinaryPrimitives.ReadUInt32LittleEndian(ReadBytes(4)); + } + + public override ulong ReadUInt64() + { + return BinaryPrimitives.ReadUInt64LittleEndian(ReadBytes(8)); + } + + // RAR5 style variable length encoded value + // maximum value of 0xffffffffffffffff (64 bits) + // technote: "implies max 10 bytes consumed" -- but not really because we could extend indefinitely using 0x80 0x80 ... 0x80 00 + // + // Variable length integer. Can include one or more bytes, where lower 7 bits of every byte contain integer data + // and highest bit in every byte is the continuation flag. If highest bit is 0, this is the last byte in sequence. + // So first byte contains 7 least significant bits of integer and continuation flag. Second byte, if present, + // contains next 7 bits and so on. + public ulong ReadRarVInt(int maxBytes = 10) + { + // hopefully this gets inlined + return DoReadRarVInt((maxBytes - 1) * 7); + } + + private ulong DoReadRarVInt(int maxShift) + { + var shift = 0; + ulong result = 0; + do { - CurrentReadByteCount += count; - var bytes = base.ReadBytes(count); - if (bytes.Length != count) + var b0 = ReadByte(); + var b1 = ((uint)b0) & 0x7f; + ulong n = b1; + var shifted = n << shift; + if (n != shifted >> shift) { - throw new EndOfStreamException( - string.Format( - "Could not read the requested amount of bytes. End of stream reached. Requested: {0} Read: {1}", - count, - bytes.Length - ) - ); + // overflow + break; } - return bytes; - } - - public override char ReadChar() - { - throw new NotSupportedException(); - } - - public override char[] ReadChars(int count) - { - throw new NotSupportedException(); - } - - public override double ReadDouble() - { - throw new NotSupportedException(); - } - - public override short ReadInt16() - { - return BinaryPrimitives.ReadInt16LittleEndian(ReadBytes(2)); - } - - public override int ReadInt32() - { - return BinaryPrimitives.ReadInt32LittleEndian(ReadBytes(4)); - } - - public override long ReadInt64() - { - return BinaryPrimitives.ReadInt64LittleEndian(ReadBytes(8)); - } - - public override sbyte ReadSByte() - { - return (sbyte)ReadByte(); - } - - public override float ReadSingle() - { - throw new NotSupportedException(); - } - - public override string ReadString() - { - throw new NotSupportedException(); - } - - public override ushort ReadUInt16() - { - return BinaryPrimitives.ReadUInt16LittleEndian(ReadBytes(2)); - } - - public override uint ReadUInt32() - { - return BinaryPrimitives.ReadUInt32LittleEndian(ReadBytes(4)); - } - - public override ulong ReadUInt64() - { - return BinaryPrimitives.ReadUInt64LittleEndian(ReadBytes(8)); - } - - // RAR5 style variable length encoded value - // maximum value of 0xffffffffffffffff (64 bits) - // technote: "implies max 10 bytes consumed" -- but not really because we could extend indefinitely using 0x80 0x80 ... 0x80 00 - // - // Variable length integer. Can include one or more bytes, where lower 7 bits of every byte contain integer data - // and highest bit in every byte is the continuation flag. If highest bit is 0, this is the last byte in sequence. - // So first byte contains 7 least significant bits of integer and continuation flag. Second byte, if present, - // contains next 7 bits and so on. - public ulong ReadRarVInt(int maxBytes = 10) - { - // hopefully this gets inlined - return DoReadRarVInt((maxBytes - 1) * 7); - } - - private ulong DoReadRarVInt(int maxShift) - { - int shift = 0; - ulong result = 0; - do + result |= shifted; + if (b0 == b1) { - byte b0 = ReadByte(); - uint b1 = ((uint)b0) & 0x7f; - ulong n = b1; - ulong shifted = n << shift; - if (n != shifted >> shift) - { - // overflow - break; - } - result |= shifted; - if (b0 == b1) - { - return result; - } - shift += 7; - } while (shift <= maxShift); + return result; + } + shift += 7; + } while (shift <= maxShift); - throw new FormatException("malformed vint"); - } + throw new FormatException("malformed vint"); + } - public uint ReadRarVIntUInt32(int maxBytes = 5) + public uint ReadRarVIntUInt32(int maxBytes = 5) + { + // hopefully this gets inlined + return DoReadRarVIntUInt32((maxBytes - 1) * 7); + } + + public ushort ReadRarVIntUInt16(int maxBytes = 3) + { + // hopefully this gets inlined + return checked((ushort)DoReadRarVIntUInt32((maxBytes - 1) * 7)); + } + + public byte ReadRarVIntByte(int maxBytes = 2) + { + // hopefully this gets inlined + return checked((byte)DoReadRarVIntUInt32((maxBytes - 1) * 7)); + } + + private uint DoReadRarVIntUInt32(int maxShift) + { + var shift = 0; + uint result = 0; + do { - // hopefully this gets inlined - return DoReadRarVIntUInt32((maxBytes - 1) * 7); - } - - public ushort ReadRarVIntUInt16(int maxBytes = 3) - { - // hopefully this gets inlined - return checked((ushort)DoReadRarVIntUInt32((maxBytes - 1) * 7)); - } - - public byte ReadRarVIntByte(int maxBytes = 2) - { - // hopefully this gets inlined - return checked((byte)DoReadRarVIntUInt32((maxBytes - 1) * 7)); - } - - private uint DoReadRarVIntUInt32(int maxShift) - { - int shift = 0; - uint result = 0; - do + var b0 = ReadByte(); + var b1 = ((uint)b0) & 0x7f; + var n = b1; + var shifted = n << shift; + if (n != shifted >> shift) { - byte b0 = ReadByte(); - uint b1 = ((uint)b0) & 0x7f; - uint n = b1; - uint shifted = n << shift; - if (n != shifted >> shift) - { - // overflow - break; - } - result |= shifted; - if (b0 == b1) - { - return result; - } - shift += 7; - } while (shift <= maxShift); + // overflow + break; + } + result |= shifted; + if (b0 == b1) + { + return result; + } + shift += 7; + } while (shift <= maxShift); - throw new FormatException("malformed vint"); - } + throw new FormatException("malformed vint"); } } diff --git a/src/SharpCompress/IO/NonDisposingStream.cs b/src/SharpCompress/IO/NonDisposingStream.cs index a3b74469..78063c78 100644 --- a/src/SharpCompress/IO/NonDisposingStream.cs +++ b/src/SharpCompress/IO/NonDisposingStream.cs @@ -1,93 +1,92 @@ using System; using System.IO; -namespace SharpCompress.IO +namespace SharpCompress.IO; + +public class NonDisposingStream : Stream { - public class NonDisposingStream : Stream + public static NonDisposingStream Create(Stream stream, bool throwOnDispose = false) { - public static NonDisposingStream Create(Stream stream, bool throwOnDispose = false) + if ( + stream is NonDisposingStream nonDisposingStream + && nonDisposingStream.ThrowOnDispose == throwOnDispose + ) { - if ( - stream is NonDisposingStream nonDisposingStream - && nonDisposingStream.ThrowOnDispose == throwOnDispose - ) - { - return nonDisposingStream; - } - return new NonDisposingStream(stream, throwOnDispose); + return nonDisposingStream; } + return new NonDisposingStream(stream, throwOnDispose); + } - protected NonDisposingStream(Stream stream, bool throwOnDispose = false) + protected NonDisposingStream(Stream stream, bool throwOnDispose = false) + { + Stream = stream; + ThrowOnDispose = throwOnDispose; + } + + public bool ThrowOnDispose { get; set; } + + protected override void Dispose(bool disposing) + { + if (ThrowOnDispose) { - Stream = stream; - ThrowOnDispose = throwOnDispose; + throw new InvalidOperationException( + $"Attempt to dispose of a {nameof(NonDisposingStream)} when {nameof(ThrowOnDispose)} is {ThrowOnDispose}" + ); } + } - public bool ThrowOnDispose { get; set; } + protected Stream Stream { get; } - protected override void Dispose(bool disposing) - { - if (ThrowOnDispose) - { - throw new InvalidOperationException( - $"Attempt to dispose of a {nameof(NonDisposingStream)} when {nameof(ThrowOnDispose)} is {ThrowOnDispose}" - ); - } - } + public override bool CanRead => Stream.CanRead; - protected Stream Stream { get; } + public override bool CanSeek => Stream.CanSeek; - public override bool CanRead => Stream.CanRead; + public override bool CanWrite => Stream.CanWrite; - public override bool CanSeek => Stream.CanSeek; + public override void Flush() + { + Stream.Flush(); + } - public override bool CanWrite => Stream.CanWrite; + public override long Length => Stream.Length; - public override void Flush() - { - Stream.Flush(); - } + public override long Position + { + get => Stream.Position; + set => Stream.Position = value; + } - public override long Length => Stream.Length; + public override int Read(byte[] buffer, int offset, int count) + { + return Stream.Read(buffer, offset, count); + } - public override long Position - { - get => Stream.Position; - set => Stream.Position = value; - } + public override long Seek(long offset, SeekOrigin origin) + { + return Stream.Seek(offset, origin); + } - public override int Read(byte[] buffer, int offset, int count) - { - return Stream.Read(buffer, offset, count); - } + public override void SetLength(long value) + { + Stream.SetLength(value); + } - public override long Seek(long offset, SeekOrigin origin) - { - return Stream.Seek(offset, origin); - } - - public override void SetLength(long value) - { - Stream.SetLength(value); - } - - public override void Write(byte[] buffer, int offset, int count) - { - Stream.Write(buffer, offset, count); - } + public override void Write(byte[] buffer, int offset, int count) + { + Stream.Write(buffer, offset, count); + } #if !NETFRAMEWORK && !NETSTANDARD2_0 - public override int Read(Span buffer) - { - return Stream.Read(buffer); - } + public override int Read(Span buffer) + { + return Stream.Read(buffer); + } - public override void Write(ReadOnlySpan buffer) - { - Stream.Write(buffer); - } + public override void Write(ReadOnlySpan buffer) + { + Stream.Write(buffer); + } #endif - } } diff --git a/src/SharpCompress/IO/ReadOnlySubStream.cs b/src/SharpCompress/IO/ReadOnlySubStream.cs index f098db4c..acdb6e4a 100644 --- a/src/SharpCompress/IO/ReadOnlySubStream.cs +++ b/src/SharpCompress/IO/ReadOnlySubStream.cs @@ -1,98 +1,97 @@ using System; using System.IO; -namespace SharpCompress.IO +namespace SharpCompress.IO; + +internal class ReadOnlySubStream : NonDisposingStream { - internal class ReadOnlySubStream : NonDisposingStream + public ReadOnlySubStream(Stream stream, long bytesToRead) : this(stream, null, bytesToRead) + { } + + public ReadOnlySubStream(Stream stream, long? origin, long bytesToRead) + : base(stream, throwOnDispose: false) { - public ReadOnlySubStream(Stream stream, long bytesToRead) : this(stream, null, bytesToRead) - { } - - public ReadOnlySubStream(Stream stream, long? origin, long bytesToRead) - : base(stream, throwOnDispose: false) + if (origin != null) { - if (origin != null) - { - stream.Position = origin.Value; - } - BytesLeftToRead = bytesToRead; + stream.Position = origin.Value; } + BytesLeftToRead = bytesToRead; + } - private long BytesLeftToRead { get; set; } + private long BytesLeftToRead { get; set; } - public override bool CanRead => true; + public override bool CanRead => true; - public override bool CanSeek => false; + public override bool CanSeek => false; - public override bool CanWrite => false; + public override bool CanWrite => false; - public override void Flush() + public override void Flush() + { + throw new NotSupportedException(); + } + + public override long Length => throw new NotSupportedException(); + + public override long Position + { + get => throw new NotSupportedException(); + set => throw new NotSupportedException(); + } + + public override int Read(byte[] buffer, int offset, int count) + { + if (BytesLeftToRead < count) { - throw new NotSupportedException(); + count = (int)BytesLeftToRead; } - - public override long Length => throw new NotSupportedException(); - - public override long Position + var read = Stream.Read(buffer, offset, count); + if (read > 0) { - get => throw new NotSupportedException(); - set => throw new NotSupportedException(); + BytesLeftToRead -= read; } + return read; + } - public override int Read(byte[] buffer, int offset, int count) + public override int ReadByte() + { + if (BytesLeftToRead <= 0) { - if (BytesLeftToRead < count) - { - count = (int)BytesLeftToRead; - } - int read = Stream.Read(buffer, offset, count); - if (read > 0) - { - BytesLeftToRead -= read; - } - return read; + return -1; } - - public override int ReadByte() + var value = Stream.ReadByte(); + if (value != -1) { - if (BytesLeftToRead <= 0) - { - return -1; - } - int value = Stream.ReadByte(); - if (value != -1) - { - --BytesLeftToRead; - } - return value; + --BytesLeftToRead; } + return value; + } #if !NETFRAMEWORK && !NETSTANDARD2_0 - public override int Read(Span buffer) + public override int Read(Span buffer) + { + var slice_len = BytesLeftToRead < buffer.Length ? BytesLeftToRead : buffer.Length; + var read = Stream.Read(buffer.Slice(0, (int)slice_len)); + if (read > 0) { - var slice_len = BytesLeftToRead < buffer.Length ? BytesLeftToRead : buffer.Length; - var read = Stream.Read(buffer.Slice(0, (int)slice_len)); - if (read > 0) - { - BytesLeftToRead -= read; - } - return read; + BytesLeftToRead -= read; } + return read; + } #endif - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } - public override void SetLength(long value) - { - throw new NotSupportedException(); - } + public override void SetLength(long value) + { + throw new NotSupportedException(); + } - public override void Write(byte[] buffer, int offset, int count) - { - throw new NotSupportedException(); - } + public override void Write(byte[] buffer, int offset, int count) + { + throw new NotSupportedException(); } } diff --git a/src/SharpCompress/IO/RewindableStream.cs b/src/SharpCompress/IO/RewindableStream.cs index 281f08ea..aab9f459 100644 --- a/src/SharpCompress/IO/RewindableStream.cs +++ b/src/SharpCompress/IO/RewindableStream.cs @@ -1,164 +1,163 @@ using System; using System.IO; -namespace SharpCompress.IO +namespace SharpCompress.IO; + +public class RewindableStream : Stream { - public class RewindableStream : Stream + private readonly Stream stream; + private MemoryStream bufferStream = new MemoryStream(); + private bool isRewound; + private bool isDisposed; + + public RewindableStream(Stream stream) { - private readonly Stream stream; - private MemoryStream bufferStream = new MemoryStream(); - private bool isRewound; - private bool isDisposed; + this.stream = stream; + } - public RewindableStream(Stream stream) + internal bool IsRecording { get; private set; } + + protected override void Dispose(bool disposing) + { + if (isDisposed) { - this.stream = stream; + return; } - - internal bool IsRecording { get; private set; } - - protected override void Dispose(bool disposing) + isDisposed = true; + base.Dispose(disposing); + if (disposing) { - if (isDisposed) - { - return; - } - isDisposed = true; - base.Dispose(disposing); - if (disposing) - { - stream.Dispose(); - } + stream.Dispose(); } + } - public void Rewind(bool stopRecording) + public void Rewind(bool stopRecording) + { + isRewound = true; + IsRecording = !stopRecording; + bufferStream.Position = 0; + } + + public void Rewind(MemoryStream buffer) + { + if (bufferStream.Position >= buffer.Length) { - isRewound = true; - IsRecording = !stopRecording; + bufferStream.Position -= buffer.Length; + } + else + { + bufferStream.TransferTo(buffer); + //create new memorystream to allow proper resizing as memorystream could be a user provided buffer + //https://github.com/adamhathcock/sharpcompress/issues/306 + bufferStream = new MemoryStream(); + buffer.Position = 0; + buffer.TransferTo(bufferStream); bufferStream.Position = 0; } + isRewound = true; + } - public void Rewind(MemoryStream buffer) + public void StartRecording() + { + //if (isRewound && bufferStream.Position != 0) + // throw new System.NotImplementedException(); + if (bufferStream.Position != 0) { - if (bufferStream.Position >= buffer.Length) + var data = bufferStream.ToArray(); + var position = bufferStream.Position; + bufferStream.SetLength(0); + bufferStream.Write(data, (int)position, data.Length - (int)position); + bufferStream.Position = 0; + } + IsRecording = true; + } + + public override bool CanRead => true; + + public override bool CanSeek => stream.CanSeek; + + public override bool CanWrite => false; + + public override void Flush() + { + throw new NotSupportedException(); + } + + public override long Length => stream.Length; + + public override long Position + { + get => stream.Position + bufferStream.Position - bufferStream.Length; + set + { + if (!isRewound) { - bufferStream.Position -= buffer.Length; + stream.Position = value; + } + else if (value < stream.Position - bufferStream.Length || value >= stream.Position) + { + stream.Position = value; + isRewound = false; + bufferStream.SetLength(0); } else { - bufferStream.TransferTo(buffer); - //create new memorystream to allow proper resizing as memorystream could be a user provided buffer - //https://github.com/adamhathcock/sharpcompress/issues/306 - bufferStream = new MemoryStream(); - buffer.Position = 0; - buffer.TransferTo(bufferStream); - bufferStream.Position = 0; + bufferStream.Position = value - stream.Position + bufferStream.Length; } - isRewound = true; } + } - public void StartRecording() + public override int Read(byte[] buffer, int offset, int count) + { + //don't actually read if we don't really want to read anything + //currently a network stream bug on Windows for .NET Core + if (count == 0) { - //if (isRewound && bufferStream.Position != 0) - // throw new System.NotImplementedException(); - if (bufferStream.Position != 0) + return 0; + } + int read; + if (isRewound && bufferStream.Position != bufferStream.Length) + { + // don't read more than left + var readCount = Math.Min(count, (int)(bufferStream.Length - bufferStream.Position)); + read = bufferStream.Read(buffer, offset, readCount); + if (read < readCount) { - byte[] data = bufferStream.ToArray(); - long position = bufferStream.Position; + var tempRead = stream.Read(buffer, offset + read, count - read); + if (IsRecording) + { + bufferStream.Write(buffer, offset + read, tempRead); + } + read += tempRead; + } + if (bufferStream.Position == bufferStream.Length && !IsRecording) + { + isRewound = false; bufferStream.SetLength(0); - bufferStream.Write(data, (int)position, data.Length - (int)position); - bufferStream.Position = 0; - } - IsRecording = true; - } - - public override bool CanRead => true; - - public override bool CanSeek => stream.CanSeek; - - public override bool CanWrite => false; - - public override void Flush() - { - throw new NotSupportedException(); - } - - public override long Length => stream.Length; - - public override long Position - { - get => stream.Position + bufferStream.Position - bufferStream.Length; - set - { - if (!isRewound) - { - stream.Position = value; - } - else if (value < stream.Position - bufferStream.Length || value >= stream.Position) - { - stream.Position = value; - isRewound = false; - bufferStream.SetLength(0); - } - else - { - bufferStream.Position = value - stream.Position + bufferStream.Length; - } - } - } - - public override int Read(byte[] buffer, int offset, int count) - { - //don't actually read if we don't really want to read anything - //currently a network stream bug on Windows for .NET Core - if (count == 0) - { - return 0; - } - int read; - if (isRewound && bufferStream.Position != bufferStream.Length) - { - // don't read more than left - int readCount = Math.Min(count, (int)(bufferStream.Length - bufferStream.Position)); - read = bufferStream.Read(buffer, offset, readCount); - if (read < readCount) - { - int tempRead = stream.Read(buffer, offset + read, count - read); - if (IsRecording) - { - bufferStream.Write(buffer, offset + read, tempRead); - } - read += tempRead; - } - if (bufferStream.Position == bufferStream.Length && !IsRecording) - { - isRewound = false; - bufferStream.SetLength(0); - } - return read; - } - - read = stream.Read(buffer, offset, count); - if (IsRecording) - { - bufferStream.Write(buffer, offset, read); } return read; } - public override long Seek(long offset, SeekOrigin origin) + read = stream.Read(buffer, offset, count); + if (IsRecording) { - throw new NotSupportedException(); + bufferStream.Write(buffer, offset, read); } + return read; + } - public override void SetLength(long value) - { - throw new NotSupportedException(); - } + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } - public override void Write(byte[] buffer, int offset, int count) - { - throw new NotSupportedException(); - } + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + public override void Write(byte[] buffer, int offset, int count) + { + throw new NotSupportedException(); } } diff --git a/src/SharpCompress/IO/SourceStream.cs b/src/SharpCompress/IO/SourceStream.cs index 35fba988..5f722b65 100644 --- a/src/SharpCompress/IO/SourceStream.cs +++ b/src/SharpCompress/IO/SourceStream.cs @@ -2,237 +2,246 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; -using System.Text; -using System.Threading.Tasks; using SharpCompress.Readers; -namespace SharpCompress.IO +namespace SharpCompress.IO; + +public class SourceStream : Stream { - public class SourceStream : Stream + private long _prevSize; + private List _files; + private List _streams; + private Func _getFilePart; + private Func _getStreamPart; + private int _stream; + + public SourceStream(FileInfo file, Func getPart, ReaderOptions options) + : this(null, null, file, getPart, options) { } + + public SourceStream(Stream stream, Func getPart, ReaderOptions options) + : this(stream, getPart, null, null, options) { } + + private SourceStream( + Stream? stream, + Func? getStreamPart, + FileInfo? file, + Func? getFilePart, + ReaderOptions options + ) { - private long _prevSize; - private List _files; - private List _streams; - private Func _getFilePart; - private Func _getStreamPart; - private int _stream; + ReaderOptions = options; + _files = new List(); + _streams = new List(); + IsFileMode = file != null; + IsVolumes = false; - public SourceStream(FileInfo file, Func getPart, ReaderOptions options) - : this(null, null, file, getPart, options) { } - - public SourceStream(Stream stream, Func getPart, ReaderOptions options) - : this(stream, getPart, null, null, options) { } - - private SourceStream( - Stream? stream, - Func? getStreamPart, - FileInfo? file, - Func? getFilePart, - ReaderOptions options - ) + if (!IsFileMode) { - this.ReaderOptions = options; - _files = new List(); - _streams = new List(); - IsFileMode = file != null; - IsVolumes = false; - - if (!IsFileMode) + _streams.Add(stream!); + _getStreamPart = getStreamPart!; + _getFilePart = new Func(a => null!); + if (stream is FileStream) { - _streams.Add(stream!); - _getStreamPart = getStreamPart!; - _getFilePart = new Func(a => null!); - if (stream! is FileStream) - _files.Add(new FileInfo(((FileStream)stream!).Name)); + _files.Add(new FileInfo(((FileStream)stream!).Name)); + } + } + else + { + _files.Add(file!); + _streams.Add(_files[0].OpenRead()); + _getFilePart = getFilePart!; + _getStreamPart = new Func(a => null!); + } + _stream = 0; + _prevSize = 0; + } + + public void LoadAllParts() + { + for (var i = 1; SetStream(i); i++) + { } + SetStream(0); + } + + public bool IsVolumes { get; set; } + + public ReaderOptions ReaderOptions { get; } + public bool IsFileMode { get; } + + public IEnumerable Files => _files; + public IEnumerable Streams => _streams; + + private Stream Current => _streams[_stream]; + + public bool LoadStream(int index) //ensure all parts to id are loaded + { + while (_streams.Count <= index) + { + if (IsFileMode) + { + var f = _getFilePart(_streams.Count); + if (f == null) + { + _stream = _streams.Count - 1; + return false; + } + //throw new Exception($"File part {idx} not available."); + _files.Add(f); + _streams.Add(_files.Last().OpenRead()); } else { - _files.Add(file!); - _streams.Add(_files[0].OpenRead()); - _getFilePart = getFilePart!; - _getStreamPart = new Func(a => null!); + var s = _getStreamPart(_streams.Count); + if (s == null) + { + _stream = _streams.Count - 1; + return false; + } + //throw new Exception($"Stream part {idx} not available."); + _streams.Add(s); + if (s is FileStream) + { + _files.Add(new FileInfo(((FileStream)s).Name)); + } } - _stream = 0; - _prevSize = 0; + } + return true; + } + + public bool SetStream(int idx) //allow caller to switch part in multipart + { + if (LoadStream(idx)) + { + _stream = idx; } - public void LoadAllParts() + return _stream == idx; + } + + public override bool CanRead => true; + + public override bool CanSeek => true; + + public override bool CanWrite => false; + + public override long Length => (!IsVolumes ? _streams.Sum(a => a.Length) : Current.Length); + + public override long Position + { + get => _prevSize + Current.Position; //_prevSize is 0 for multivolume + set => Seek(value, SeekOrigin.Begin); + } + + public override void Flush() + { + Current.Flush(); + } + + public override int Read(byte[] buffer, int offset, int count) + { + if (count <= 0) + { + return 0; + } + + var total = count; + var r = -1; + + while (count != 0 && r != 0) + { + r = Current.Read( + buffer, + offset, + (int)Math.Min(count, Current.Length - Current.Position) + ); + count -= r; + offset += r; + + if (!IsVolumes && count != 0 && Current.Position == Current.Length) + { + var length = Current.Length; + + // Load next file if present + if (!SetStream(_stream + 1)) + { + break; + } + + // Current stream switched + // Add length of previous stream + _prevSize += length; + Current.Seek(0, SeekOrigin.Begin); + } + } + + return total - count; + } + + public override long Seek(long offset, SeekOrigin origin) + { + var pos = Position; + switch (origin) + { + case SeekOrigin.Begin: + pos = offset; + break; + case SeekOrigin.Current: + pos += offset; + break; + case SeekOrigin.End: + pos = Length + offset; + break; + } + + _prevSize = 0; + if (!IsVolumes) { - for (int i = 1; SetStream(i); i++) { } SetStream(0); - } - - public bool IsVolumes { get; set; } - - public ReaderOptions ReaderOptions { get; } - public bool IsFileMode { get; } - - public IEnumerable Files => _files; - public IEnumerable Streams => _streams; - - private Stream Current => _streams[_stream]; - - public bool LoadStream(int index) //ensure all parts to id are loaded - { - while (_streams.Count <= index) + while (_prevSize + Current.Length < pos) { - if (IsFileMode) - { - FileInfo? f = _getFilePart(_streams.Count); - if (f == null) - { - _stream = _streams.Count - 1; - return false; - } - //throw new Exception($"File part {idx} not available."); - _files.Add(f); - _streams.Add(_files.Last().OpenRead()); - } - else - { - Stream? s = _getStreamPart(_streams.Count); - if (s == null) - { - _stream = _streams.Count - 1; - return false; - } - //throw new Exception($"Stream part {idx} not available."); - _streams.Add(s); - if (s is FileStream) - _files.Add(new FileInfo(((FileStream)s).Name)); - } - } - return true; - } - - public bool SetStream(int idx) //allow caller to switch part in multipart - { - if (LoadStream(idx)) - _stream = idx; - return _stream == idx; - } - - public override bool CanRead => true; - - public override bool CanSeek => true; - - public override bool CanWrite => false; - - public override long Length => (!IsVolumes ? _streams.Sum(a => a.Length) : Current.Length); - - public override long Position - { - get => _prevSize + Current.Position; //_prevSize is 0 for multivolume - set => Seek(value, SeekOrigin.Begin); - } - - public override void Flush() - { - Current.Flush(); - } - - public override int Read(byte[] buffer, int offset, int count) - { - if (count <= 0) - return 0; - - int total = count; - int r = -1; - - while (count != 0 && r != 0) - { - r = Current.Read( - buffer, - offset, - (int)Math.Min(count, Current.Length - Current.Position) - ); - count -= r; - offset += r; - - if (!IsVolumes && count != 0 && Current.Position == Current.Length) - { - var length = Current.Length; - - // Load next file if present - if (!SetStream(_stream + 1)) - { - break; - } - - // Current stream switched - // Add length of previous stream - _prevSize += length; - Current.Seek(0, SeekOrigin.Begin); - } - } - - return total - count; - } - - public override long Seek(long offset, SeekOrigin origin) - { - long pos = this.Position; - switch (origin) - { - case SeekOrigin.Begin: - pos = offset; - break; - case SeekOrigin.Current: - pos += offset; - break; - case SeekOrigin.End: - pos = Length + offset; - break; - } - - _prevSize = 0; - if (!IsVolumes) - { - SetStream(0); - while (_prevSize + Current.Length < pos) - { - _prevSize += Current.Length; - SetStream(_stream + 1); - } - } - - if (pos != _prevSize + Current.Position) - Current.Seek(pos - _prevSize, SeekOrigin.Begin); - return pos; - } - - public override void SetLength(long value) - { - throw new NotImplementedException(); - } - - public override void Write(byte[] buffer, int offset, int count) - { - throw new NotImplementedException(); - } - - public override void Close() - { - if (this.IsFileMode || !this.ReaderOptions.LeaveStreamOpen) //close if file mode or options specify it - { - foreach (Stream stream in _streams) - { - try - { - if (stream != null) - stream.Dispose(); - } - catch { } - } - _streams.Clear(); - _files.Clear(); + _prevSize += Current.Length; + SetStream(_stream + 1); } } - protected override void Dispose(bool disposing) + if (pos != _prevSize + Current.Position) { - this.Close(); - base.Dispose(disposing); + Current.Seek(pos - _prevSize, SeekOrigin.Begin); + } + + return pos; + } + + public override void SetLength(long value) + { + throw new NotImplementedException(); + } + + public override void Write(byte[] buffer, int offset, int count) + { + throw new NotImplementedException(); + } + + public override void Close() + { + if (IsFileMode || !ReaderOptions.LeaveStreamOpen) //close if file mode or options specify it + { + foreach (var stream in _streams) + { + try + { + stream?.Dispose(); + } + catch { } + } + _streams.Clear(); + _files.Clear(); } } + + protected override void Dispose(bool disposing) + { + Close(); + base.Dispose(disposing); + } } diff --git a/src/SharpCompress/IO/StreamingMode.cs b/src/SharpCompress/IO/StreamingMode.cs index d2a8a823..0fdb674d 100644 --- a/src/SharpCompress/IO/StreamingMode.cs +++ b/src/SharpCompress/IO/StreamingMode.cs @@ -1,8 +1,7 @@ -namespace SharpCompress.IO +namespace SharpCompress.IO; + +public enum StreamingMode { - public enum StreamingMode - { - Streaming, - Seekable - } + Streaming, + Seekable } diff --git a/src/SharpCompress/Lazy.cs b/src/SharpCompress/Lazy.cs index 3ddd47d2..d7e5159a 100644 --- a/src/SharpCompress/Lazy.cs +++ b/src/SharpCompress/Lazy.cs @@ -2,30 +2,29 @@ using System; -namespace SharpCompress +namespace SharpCompress; + +public class Lazy { - public class Lazy + private readonly Func _lazyFunc; + private bool _evaluated; + private T _value; + + public Lazy(Func lazyFunc) { - private readonly Func _lazyFunc; - private bool _evaluated; - private T _value; + _lazyFunc = lazyFunc; + } - public Lazy(Func lazyFunc) + public T Value + { + get { - _lazyFunc = lazyFunc; - } - - public T Value - { - get + if (!_evaluated) { - if (!_evaluated) - { - _value = _lazyFunc(); - _evaluated = true; - } - return _value; + _value = _lazyFunc(); + _evaluated = true; } + return _value; } } } diff --git a/src/SharpCompress/LazyReadOnlyCollection.cs b/src/SharpCompress/LazyReadOnlyCollection.cs index 415e9904..6fc4ff87 100644 --- a/src/SharpCompress/LazyReadOnlyCollection.cs +++ b/src/SharpCompress/LazyReadOnlyCollection.cs @@ -1,153 +1,152 @@ -#nullable disable +#nullable disable using System; using System.Collections; using System.Collections.Generic; -namespace SharpCompress +namespace SharpCompress; + +internal sealed class LazyReadOnlyCollection : ICollection { - internal sealed class LazyReadOnlyCollection : ICollection + private readonly List backing = new List(); + private readonly IEnumerator source; + private bool fullyLoaded; + + public LazyReadOnlyCollection(IEnumerable source) { - private readonly List backing = new List(); - private readonly IEnumerator source; - private bool fullyLoaded; + this.source = source.GetEnumerator(); + } - public LazyReadOnlyCollection(IEnumerable source) + private class LazyLoader : IEnumerator + { + private readonly LazyReadOnlyCollection lazyReadOnlyCollection; + private bool disposed; + private int index = -1; + + internal LazyLoader(LazyReadOnlyCollection lazyReadOnlyCollection) { - this.source = source.GetEnumerator(); + this.lazyReadOnlyCollection = lazyReadOnlyCollection; } - private class LazyLoader : IEnumerator - { - private readonly LazyReadOnlyCollection lazyReadOnlyCollection; - private bool disposed; - private int index = -1; + #region IEnumerator Members - internal LazyLoader(LazyReadOnlyCollection lazyReadOnlyCollection) + public T Current => lazyReadOnlyCollection.backing[index]; + + #endregion + + #region IDisposable Members + + public void Dispose() + { + if (!disposed) { - this.lazyReadOnlyCollection = lazyReadOnlyCollection; + disposed = true; } - - #region IEnumerator Members - - public T Current => lazyReadOnlyCollection.backing[index]; - - #endregion - - #region IDisposable Members - - public void Dispose() - { - if (!disposed) - { - disposed = true; - } - } - - #endregion - - #region IEnumerator Members - - object IEnumerator.Current => Current; - - public bool MoveNext() - { - if (index + 1 < lazyReadOnlyCollection.backing.Count) - { - index++; - return true; - } - if (!lazyReadOnlyCollection.fullyLoaded && lazyReadOnlyCollection.source.MoveNext()) - { - lazyReadOnlyCollection.backing.Add(lazyReadOnlyCollection.source.Current); - index++; - return true; - } - lazyReadOnlyCollection.fullyLoaded = true; - return false; - } - - public void Reset() - { - throw new NotSupportedException(); - } - - #endregion - } - - internal void EnsureFullyLoaded() - { - if (!fullyLoaded) - { - this.ForEach(x => { }); - fullyLoaded = true; - } - } - - internal IEnumerable GetLoaded() - { - return backing; - } - - #region ICollection Members - - public void Add(T item) - { - throw new NotSupportedException(); - } - - public void Clear() - { - throw new NotSupportedException(); - } - - public bool Contains(T item) - { - EnsureFullyLoaded(); - return backing.Contains(item); - } - - public void CopyTo(T[] array, int arrayIndex) - { - EnsureFullyLoaded(); - backing.CopyTo(array, arrayIndex); - } - - public int Count - { - get - { - EnsureFullyLoaded(); - return backing.Count; - } - } - - public bool IsReadOnly => true; - - public bool Remove(T item) - { - throw new NotSupportedException(); } #endregion - #region IEnumerable Members + #region IEnumerator Members - //TODO check for concurrent access - public IEnumerator GetEnumerator() + object IEnumerator.Current => Current; + + public bool MoveNext() { - return new LazyLoader(this); + if (index + 1 < lazyReadOnlyCollection.backing.Count) + { + index++; + return true; + } + if (!lazyReadOnlyCollection.fullyLoaded && lazyReadOnlyCollection.source.MoveNext()) + { + lazyReadOnlyCollection.backing.Add(lazyReadOnlyCollection.source.Current); + index++; + return true; + } + lazyReadOnlyCollection.fullyLoaded = true; + return false; } - #endregion - - #region IEnumerable Members - - IEnumerator IEnumerable.GetEnumerator() + public void Reset() { - return GetEnumerator(); + throw new NotSupportedException(); } #endregion } + + internal void EnsureFullyLoaded() + { + if (!fullyLoaded) + { + this.ForEach(x => { }); + fullyLoaded = true; + } + } + + internal IEnumerable GetLoaded() + { + return backing; + } + + #region ICollection Members + + public void Add(T item) + { + throw new NotSupportedException(); + } + + public void Clear() + { + throw new NotSupportedException(); + } + + public bool Contains(T item) + { + EnsureFullyLoaded(); + return backing.Contains(item); + } + + public void CopyTo(T[] array, int arrayIndex) + { + EnsureFullyLoaded(); + backing.CopyTo(array, arrayIndex); + } + + public int Count + { + get + { + EnsureFullyLoaded(); + return backing.Count; + } + } + + public bool IsReadOnly => true; + + public bool Remove(T item) + { + throw new NotSupportedException(); + } + + #endregion + + #region IEnumerable Members + + //TODO check for concurrent access + public IEnumerator GetEnumerator() + { + return new LazyLoader(this); + } + + #endregion + + #region IEnumerable Members + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + #endregion } diff --git a/src/SharpCompress/Polyfills/StreamExtensions.cs b/src/SharpCompress/Polyfills/StreamExtensions.cs index 6dacef75..ab118a4f 100644 --- a/src/SharpCompress/Polyfills/StreamExtensions.cs +++ b/src/SharpCompress/Polyfills/StreamExtensions.cs @@ -1,45 +1,44 @@ -#if NETFRAMEWORK || NETSTANDARD2_0 +#if NETFRAMEWORK || NETSTANDARD2_0 using System; using System.Buffers; using System.IO; -namespace SharpCompress +namespace SharpCompress; + +internal static class StreamExtensions { - internal static class StreamExtensions + internal static int Read(this Stream stream, Span buffer) { - internal static int Read(this Stream stream, Span buffer) + var temp = ArrayPool.Shared.Rent(buffer.Length); + + try { - byte[] temp = ArrayPool.Shared.Rent(buffer.Length); + var read = stream.Read(temp, 0, buffer.Length); - try - { - int read = stream.Read(temp, 0, buffer.Length); + temp.AsSpan(0, read).CopyTo(buffer); - temp.AsSpan(0, read).CopyTo(buffer); - - return read; - } - finally - { - ArrayPool.Shared.Return(temp); - } + return read; } - - internal static void Write(this Stream stream, ReadOnlySpan buffer) + finally { - byte[] temp = ArrayPool.Shared.Rent(buffer.Length); + ArrayPool.Shared.Return(temp); + } + } - buffer.CopyTo(temp); + internal static void Write(this Stream stream, ReadOnlySpan buffer) + { + var temp = ArrayPool.Shared.Rent(buffer.Length); - try - { - stream.Write(temp, 0, buffer.Length); - } - finally - { - ArrayPool.Shared.Return(temp); - } + buffer.CopyTo(temp); + + try + { + stream.Write(temp, 0, buffer.Length); + } + finally + { + ArrayPool.Shared.Return(temp); } } } diff --git a/src/SharpCompress/Polyfills/StringExtensions.cs b/src/SharpCompress/Polyfills/StringExtensions.cs index c6283707..72d0abc6 100644 --- a/src/SharpCompress/Polyfills/StringExtensions.cs +++ b/src/SharpCompress/Polyfills/StringExtensions.cs @@ -1,18 +1,17 @@ -#if NETFRAMEWORK || NETSTANDARD2_0 +#if NETFRAMEWORK || NETSTANDARD2_0 -namespace SharpCompress +namespace SharpCompress; + +internal static class StringExtensions { - internal static class StringExtensions + internal static bool EndsWith(this string text, char value) { - internal static bool EndsWith(this string text, char value) - { - return text.Length > 0 && text[text.Length - 1] == value; - } + return text.Length > 0 && text[text.Length - 1] == value; + } - internal static bool Contains(this string text, char value) - { - return text.IndexOf(value) > -1; - } + internal static bool Contains(this string text, char value) + { + return text.IndexOf(value) > -1; } } diff --git a/src/SharpCompress/ReadOnlyCollection.cs b/src/SharpCompress/ReadOnlyCollection.cs index a116a056..b4c46716 100644 --- a/src/SharpCompress/ReadOnlyCollection.cs +++ b/src/SharpCompress/ReadOnlyCollection.cs @@ -1,55 +1,54 @@ -using System; +using System; using System.Collections; using System.Collections.Generic; -namespace SharpCompress +namespace SharpCompress; + +public class ReadOnlyCollection : ICollection { - public class ReadOnlyCollection : ICollection + private readonly ICollection collection; + + public ReadOnlyCollection(ICollection collection) { - private readonly ICollection collection; + this.collection = collection; + } - public ReadOnlyCollection(ICollection collection) - { - this.collection = collection; - } + public void Add(T item) + { + throw new NotSupportedException(); + } - public void Add(T item) - { - throw new NotSupportedException(); - } + public void Clear() + { + throw new NotSupportedException(); + } - public void Clear() - { - throw new NotSupportedException(); - } + public bool Contains(T item) + { + return collection.Contains(item); + } - public bool Contains(T item) - { - return collection.Contains(item); - } + public void CopyTo(T[] array, int arrayIndex) + { + collection.CopyTo(array, arrayIndex); + } - public void CopyTo(T[] array, int arrayIndex) - { - collection.CopyTo(array, arrayIndex); - } + public int Count => collection.Count; - public int Count => collection.Count; + public bool IsReadOnly => true; - public bool IsReadOnly => true; + public bool Remove(T item) + { + throw new NotSupportedException(); + } - public bool Remove(T item) - { - throw new NotSupportedException(); - } + public IEnumerator GetEnumerator() + { + return collection.GetEnumerator(); + } - public IEnumerator GetEnumerator() - { - return collection.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - throw new NotSupportedException(); - } + IEnumerator IEnumerable.GetEnumerator() + { + throw new NotSupportedException(); } } diff --git a/src/SharpCompress/Readers/AbstractReader.cs b/src/SharpCompress/Readers/AbstractReader.cs index f8d91ca1..5c383cb2 100644 --- a/src/SharpCompress/Readers/AbstractReader.cs +++ b/src/SharpCompress/Readers/AbstractReader.cs @@ -4,263 +4,258 @@ using System.IO; using System.Linq; using SharpCompress.Common; -namespace SharpCompress.Readers +namespace SharpCompress.Readers; + +/// +/// A generic push reader that reads unseekable comrpessed streams. +/// +public abstract class AbstractReader : IReader, IReaderExtractionListener + where TEntry : Entry + where TVolume : Volume { - /// - /// A generic push reader that reads unseekable comrpessed streams. - /// - public abstract class AbstractReader : IReader, IReaderExtractionListener - where TEntry : Entry - where TVolume : Volume + private bool completed; + private IEnumerator? entriesForCurrentReadStream; + private bool wroteCurrentEntry; + + public event EventHandler>? EntryExtractionProgress; + + public event EventHandler? CompressedBytesRead; + public event EventHandler? FilePartExtractionBegin; + + internal AbstractReader(ReaderOptions options, ArchiveType archiveType) { - private bool completed; - private IEnumerator? entriesForCurrentReadStream; - private bool wroteCurrentEntry; + ArchiveType = archiveType; + Options = options; + } - public event EventHandler>? EntryExtractionProgress; + internal ReaderOptions Options { get; } - public event EventHandler? CompressedBytesRead; - public event EventHandler? FilePartExtractionBegin; + public ArchiveType ArchiveType { get; } - internal AbstractReader(ReaderOptions options, ArchiveType archiveType) + /// + /// Current volume that the current entry resides in + /// + public abstract TVolume Volume { get; } + + /// + /// Current file entry + /// + public TEntry Entry => entriesForCurrentReadStream!.Current; + + #region IDisposable Members + + public void Dispose() + { + entriesForCurrentReadStream?.Dispose(); + Volume?.Dispose(); + } + + #endregion + + public bool Cancelled { get; private set; } + + /// + /// Indicates that the remaining entries are not required. + /// On dispose of an EntryStream, the stream will not skip to the end of the entry. + /// An attempt to move to the next entry will throw an exception, as the compressed stream is not positioned at an entry boundary. + /// + public void Cancel() + { + if (!completed) { - ArchiveType = archiveType; - Options = options; - } - - internal ReaderOptions Options { get; } - - public ArchiveType ArchiveType { get; } - - /// - /// Current volume that the current entry resides in - /// - public abstract TVolume Volume { get; } - - /// - /// Current file entry - /// - public TEntry Entry => entriesForCurrentReadStream!.Current; - - #region IDisposable Members - - public void Dispose() - { - entriesForCurrentReadStream?.Dispose(); - Volume?.Dispose(); - } - - #endregion - - public bool Cancelled { get; private set; } - - /// - /// Indicates that the remaining entries are not required. - /// On dispose of an EntryStream, the stream will not skip to the end of the entry. - /// An attempt to move to the next entry will throw an exception, as the compressed stream is not positioned at an entry boundary. - /// - public void Cancel() - { - if (!completed) - { - Cancelled = true; - } - } - - public bool MoveToNextEntry() - { - if (completed) - { - return false; - } - if (Cancelled) - { - throw new InvalidOperationException("Reader has been cancelled."); - } - if (entriesForCurrentReadStream is null) - { - return LoadStreamForReading(RequestInitialStream()); - } - if (!wroteCurrentEntry) - { - SkipEntry(); - } - wroteCurrentEntry = false; - if (NextEntryForCurrentStream()) - { - return true; - } - completed = true; - return false; - } - - protected bool LoadStreamForReading(Stream stream) - { - entriesForCurrentReadStream?.Dispose(); - if ((stream is null) || (!stream.CanRead)) - { - throw new MultipartStreamRequiredException( - "File is split into multiple archives: '" - + Entry.Key - + "'. A new readable stream is required. Use Cancel if it was intended." - ); - } - entriesForCurrentReadStream = GetEntries(stream).GetEnumerator(); - return entriesForCurrentReadStream.MoveNext(); - } - - protected virtual Stream RequestInitialStream() - { - return Volume.Stream; - } - - internal virtual bool NextEntryForCurrentStream() - { - return entriesForCurrentReadStream!.MoveNext(); - } - - protected abstract IEnumerable GetEntries(Stream stream); - - #region Entry Skip/Write - - private void SkipEntry() - { - if (!Entry.IsDirectory) - { - Skip(); - } - } - - private void Skip() - { - var part = Entry.Parts.First(); - - if (ArchiveType != ArchiveType.Rar && !Entry.IsSolid && Entry.CompressedSize > 0) - { - //not solid and has a known compressed size then we can skip raw bytes. - var rawStream = part.GetRawStream(); - - if (rawStream != null) - { - var bytesToAdvance = Entry.CompressedSize; - rawStream.Skip(bytesToAdvance); - part.Skipped = true; - return; - } - } - //don't know the size so we have to try to decompress to skip - using (var s = OpenEntryStream()) - { - s.SkipEntry(); - } - } - - public void WriteEntryTo(Stream writableStream) - { - if (wroteCurrentEntry) - { - throw new ArgumentException( - "WriteEntryTo or OpenEntryStream can only be called once." - ); - } - - if (writableStream is null) - { - throw new ArgumentNullException(nameof(writableStream)); - } - if (!writableStream.CanWrite) - { - throw new ArgumentException( - "A writable Stream was required. Use Cancel if that was intended." - ); - } - - Write(writableStream); - wroteCurrentEntry = true; - } - - internal void Write(Stream writeStream) - { - var streamListener = this as IReaderExtractionListener; - using (Stream s = OpenEntryStream()) - { - s.TransferTo(writeStream, Entry, streamListener); - } - } - - public EntryStream OpenEntryStream() - { - if (wroteCurrentEntry) - { - throw new ArgumentException( - "WriteEntryTo or OpenEntryStream can only be called once." - ); - } - var stream = GetEntryStream(); - wroteCurrentEntry = true; - return stream; - } - - /// - /// Retains a reference to the entry stream, so we can check whether it completed later. - /// - protected EntryStream CreateEntryStream(Stream decompressed) - { - return new EntryStream(this, decompressed); - } - - protected virtual EntryStream GetEntryStream() - { - return CreateEntryStream(Entry.Parts.First().GetCompressedStream()); - } - - #endregion - - IEntry IReader.Entry => Entry; - - void IExtractionListener.FireCompressedBytesRead( - long currentPartCompressedBytes, - long compressedReadBytes - ) - { - CompressedBytesRead?.Invoke( - this, - new CompressedBytesReadEventArgs( - currentFilePartCompressedBytesRead: currentPartCompressedBytes, - compressedBytesRead: compressedReadBytes - ) - ); - } - - void IExtractionListener.FireFilePartExtractionBegin( - string name, - long size, - long compressedSize - ) - { - FilePartExtractionBegin?.Invoke( - this, - new FilePartExtractionBeginEventArgs( - compressedSize: compressedSize, - size: size, - name: name - ) - ); - } - - void IReaderExtractionListener.FireEntryExtractionProgress( - Entry entry, - long bytesTransferred, - int iterations - ) - { - EntryExtractionProgress?.Invoke( - this, - new ReaderExtractionEventArgs( - entry, - new ReaderProgress(entry, bytesTransferred, iterations) - ) - ); + Cancelled = true; } } + + public bool MoveToNextEntry() + { + if (completed) + { + return false; + } + if (Cancelled) + { + throw new InvalidOperationException("Reader has been cancelled."); + } + if (entriesForCurrentReadStream is null) + { + return LoadStreamForReading(RequestInitialStream()); + } + if (!wroteCurrentEntry) + { + SkipEntry(); + } + wroteCurrentEntry = false; + if (NextEntryForCurrentStream()) + { + return true; + } + completed = true; + return false; + } + + protected bool LoadStreamForReading(Stream stream) + { + entriesForCurrentReadStream?.Dispose(); + if ((stream is null) || (!stream.CanRead)) + { + throw new MultipartStreamRequiredException( + "File is split into multiple archives: '" + + Entry.Key + + "'. A new readable stream is required. Use Cancel if it was intended." + ); + } + entriesForCurrentReadStream = GetEntries(stream).GetEnumerator(); + return entriesForCurrentReadStream.MoveNext(); + } + + protected virtual Stream RequestInitialStream() + { + return Volume.Stream; + } + + internal virtual bool NextEntryForCurrentStream() + { + return entriesForCurrentReadStream!.MoveNext(); + } + + protected abstract IEnumerable GetEntries(Stream stream); + + #region Entry Skip/Write + + private void SkipEntry() + { + if (!Entry.IsDirectory) + { + Skip(); + } + } + + private void Skip() + { + var part = Entry.Parts.First(); + + if (ArchiveType != ArchiveType.Rar && !Entry.IsSolid && Entry.CompressedSize > 0) + { + //not solid and has a known compressed size then we can skip raw bytes. + var rawStream = part.GetRawStream(); + + if (rawStream != null) + { + var bytesToAdvance = Entry.CompressedSize; + rawStream.Skip(bytesToAdvance); + part.Skipped = true; + return; + } + } + //don't know the size so we have to try to decompress to skip + using var s = OpenEntryStream(); + s.SkipEntry(); + } + + public void WriteEntryTo(Stream writableStream) + { + if (wroteCurrentEntry) + { + throw new ArgumentException( + "WriteEntryTo or OpenEntryStream can only be called once." + ); + } + + if (writableStream is null) + { + throw new ArgumentNullException(nameof(writableStream)); + } + if (!writableStream.CanWrite) + { + throw new ArgumentException( + "A writable Stream was required. Use Cancel if that was intended." + ); + } + + Write(writableStream); + wroteCurrentEntry = true; + } + + internal void Write(Stream writeStream) + { + var streamListener = this as IReaderExtractionListener; + using Stream s = OpenEntryStream(); + s.TransferTo(writeStream, Entry, streamListener); + } + + public EntryStream OpenEntryStream() + { + if (wroteCurrentEntry) + { + throw new ArgumentException( + "WriteEntryTo or OpenEntryStream can only be called once." + ); + } + var stream = GetEntryStream(); + wroteCurrentEntry = true; + return stream; + } + + /// + /// Retains a reference to the entry stream, so we can check whether it completed later. + /// + protected EntryStream CreateEntryStream(Stream decompressed) + { + return new EntryStream(this, decompressed); + } + + protected virtual EntryStream GetEntryStream() + { + return CreateEntryStream(Entry.Parts.First().GetCompressedStream()); + } + + #endregion + + IEntry IReader.Entry => Entry; + + void IExtractionListener.FireCompressedBytesRead( + long currentPartCompressedBytes, + long compressedReadBytes + ) + { + CompressedBytesRead?.Invoke( + this, + new CompressedBytesReadEventArgs( + currentFilePartCompressedBytesRead: currentPartCompressedBytes, + compressedBytesRead: compressedReadBytes + ) + ); + } + + void IExtractionListener.FireFilePartExtractionBegin( + string name, + long size, + long compressedSize + ) + { + FilePartExtractionBegin?.Invoke( + this, + new FilePartExtractionBeginEventArgs( + compressedSize: compressedSize, + size: size, + name: name + ) + ); + } + + void IReaderExtractionListener.FireEntryExtractionProgress( + Entry entry, + long bytesTransferred, + int iterations + ) + { + EntryExtractionProgress?.Invoke( + this, + new ReaderExtractionEventArgs( + entry, + new ReaderProgress(entry, bytesTransferred, iterations) + ) + ); + } } diff --git a/src/SharpCompress/Readers/GZip/GZipReader.cs b/src/SharpCompress/Readers/GZip/GZipReader.cs index d9a823f0..c757e351 100644 --- a/src/SharpCompress/Readers/GZip/GZipReader.cs +++ b/src/SharpCompress/Readers/GZip/GZipReader.cs @@ -1,38 +1,37 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.IO; using SharpCompress.Common; using SharpCompress.Common.GZip; -namespace SharpCompress.Readers.GZip +namespace SharpCompress.Readers.GZip; + +public class GZipReader : AbstractReader { - public class GZipReader : AbstractReader + internal GZipReader(Stream stream, ReaderOptions options) : base(options, ArchiveType.GZip) { - internal GZipReader(Stream stream, ReaderOptions options) : base(options, ArchiveType.GZip) - { - Volume = new GZipVolume(stream, options); - } + Volume = new GZipVolume(stream, options); + } - public override GZipVolume Volume { get; } + public override GZipVolume Volume { get; } - #region Open + #region Open - /// - /// Opens a GZipReader for Non-seeking usage with a single volume - /// - /// - /// - /// - public static GZipReader Open(Stream stream, ReaderOptions? options = null) - { - stream.CheckNotNull(nameof(stream)); - return new GZipReader(stream, options ?? new ReaderOptions()); - } + /// + /// Opens a GZipReader for Non-seeking usage with a single volume + /// + /// + /// + /// + public static GZipReader Open(Stream stream, ReaderOptions? options = null) + { + stream.CheckNotNull(nameof(stream)); + return new GZipReader(stream, options ?? new ReaderOptions()); + } - #endregion Open + #endregion Open - protected override IEnumerable GetEntries(Stream stream) - { - return GZipEntry.GetEntries(stream, Options); - } + protected override IEnumerable GetEntries(Stream stream) + { + return GZipEntry.GetEntries(stream, Options); } } diff --git a/src/SharpCompress/Readers/IReader.cs b/src/SharpCompress/Readers/IReader.cs index a4beaa80..50fc7f4d 100644 --- a/src/SharpCompress/Readers/IReader.cs +++ b/src/SharpCompress/Readers/IReader.cs @@ -1,39 +1,38 @@ -using System; +using System; using System.IO; using SharpCompress.Common; -namespace SharpCompress.Readers +namespace SharpCompress.Readers; + +public interface IReader : IDisposable { - public interface IReader : IDisposable - { - event EventHandler> EntryExtractionProgress; + event EventHandler> EntryExtractionProgress; - event EventHandler CompressedBytesRead; - event EventHandler FilePartExtractionBegin; + event EventHandler CompressedBytesRead; + event EventHandler FilePartExtractionBegin; - ArchiveType ArchiveType { get; } + ArchiveType ArchiveType { get; } - IEntry Entry { get; } + IEntry Entry { get; } - /// - /// Decompresses the current entry to the stream. This cannot be called twice for the current entry. - /// - /// - void WriteEntryTo(Stream writableStream); + /// + /// Decompresses the current entry to the stream. This cannot be called twice for the current entry. + /// + /// + void WriteEntryTo(Stream writableStream); - bool Cancelled { get; } - void Cancel(); + bool Cancelled { get; } + void Cancel(); - /// - /// Moves to the next entry by reading more data from the underlying stream. This skips if data has not been read. - /// - /// - bool MoveToNextEntry(); + /// + /// Moves to the next entry by reading more data from the underlying stream. This skips if data has not been read. + /// + /// + bool MoveToNextEntry(); - /// - /// Opens the current entry as a stream that will decompress as it is read. - /// Read the entire stream or use SkipEntry on EntryStream. - /// - EntryStream OpenEntryStream(); - } + /// + /// Opens the current entry as a stream that will decompress as it is read. + /// Read the entire stream or use SkipEntry on EntryStream. + /// + EntryStream OpenEntryStream(); } diff --git a/src/SharpCompress/Readers/IReaderExtensions.cs b/src/SharpCompress/Readers/IReaderExtensions.cs index 29f11ef1..5ef89352 100644 --- a/src/SharpCompress/Readers/IReaderExtensions.cs +++ b/src/SharpCompress/Readers/IReaderExtensions.cs @@ -1,79 +1,72 @@ -using System.IO; +using System.IO; using SharpCompress.Common; -namespace SharpCompress.Readers +namespace SharpCompress.Readers; + +public static class IReaderExtensions { - public static class IReaderExtensions + public static void WriteEntryTo(this IReader reader, string filePath) { - public static void WriteEntryTo(this IReader reader, string filePath) - { - using (Stream stream = File.Open(filePath, FileMode.Create, FileAccess.Write)) - { - reader.WriteEntryTo(stream); - } - } + using Stream stream = File.Open(filePath, FileMode.Create, FileAccess.Write); + reader.WriteEntryTo(stream); + } - public static void WriteEntryTo(this IReader reader, FileInfo filePath) - { - using (Stream stream = filePath.Open(FileMode.Create)) - { - reader.WriteEntryTo(stream); - } - } + public static void WriteEntryTo(this IReader reader, FileInfo filePath) + { + using Stream stream = filePath.Open(FileMode.Create); + reader.WriteEntryTo(stream); + } - /// - /// Extract all remaining unread entries to specific directory, retaining filename - /// - public static void WriteAllToDirectory( - this IReader reader, - string destinationDirectory, - ExtractionOptions? options = null - ) + /// + /// Extract all remaining unread entries to specific directory, retaining filename + /// + public static void WriteAllToDirectory( + this IReader reader, + string destinationDirectory, + ExtractionOptions? options = null + ) + { + while (reader.MoveToNextEntry()) { - while (reader.MoveToNextEntry()) - { - reader.WriteEntryToDirectory(destinationDirectory, options); - } - } - - /// - /// Extract to specific directory, retaining filename - /// - public static void WriteEntryToDirectory( - this IReader reader, - string destinationDirectory, - ExtractionOptions? options = null - ) - { - ExtractionMethods.WriteEntryToDirectory( - reader.Entry, - destinationDirectory, - options, - reader.WriteEntryToFile - ); - } - - /// - /// Extract to specific file - /// - public static void WriteEntryToFile( - this IReader reader, - string destinationFileName, - ExtractionOptions? options = null - ) - { - ExtractionMethods.WriteEntryToFile( - reader.Entry, - destinationFileName, - options, - (x, fm) => - { - using (FileStream fs = File.Open(destinationFileName, fm)) - { - reader.WriteEntryTo(fs); - } - } - ); + reader.WriteEntryToDirectory(destinationDirectory, options); } } + + /// + /// Extract to specific directory, retaining filename + /// + public static void WriteEntryToDirectory( + this IReader reader, + string destinationDirectory, + ExtractionOptions? options = null + ) + { + ExtractionMethods.WriteEntryToDirectory( + reader.Entry, + destinationDirectory, + options, + reader.WriteEntryToFile + ); + } + + /// + /// Extract to specific file + /// + public static void WriteEntryToFile( + this IReader reader, + string destinationFileName, + ExtractionOptions? options = null + ) + { + ExtractionMethods.WriteEntryToFile( + reader.Entry, + destinationFileName, + options, + (x, fm) => + { + using var fs = File.Open(destinationFileName, fm); + reader.WriteEntryTo(fs); + } + ); + } } diff --git a/src/SharpCompress/Readers/IReaderExtractionListener.cs b/src/SharpCompress/Readers/IReaderExtractionListener.cs index 2edbef17..49e5dae4 100644 --- a/src/SharpCompress/Readers/IReaderExtractionListener.cs +++ b/src/SharpCompress/Readers/IReaderExtractionListener.cs @@ -1,9 +1,8 @@ -using SharpCompress.Common; +using SharpCompress.Common; -namespace SharpCompress.Readers +namespace SharpCompress.Readers; + +public interface IReaderExtractionListener : IExtractionListener { - public interface IReaderExtractionListener : IExtractionListener - { - void FireEntryExtractionProgress(Entry entry, long sizeTransferred, int iterations); - } + void FireEntryExtractionProgress(Entry entry, long sizeTransferred, int iterations); } diff --git a/src/SharpCompress/Readers/IReaderFactory.cs b/src/SharpCompress/Readers/IReaderFactory.cs index 4587cca6..08c190a3 100644 --- a/src/SharpCompress/Readers/IReaderFactory.cs +++ b/src/SharpCompress/Readers/IReaderFactory.cs @@ -1,22 +1,14 @@ -using System; -using System.Collections.Generic; using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using SharpCompress.IO; +namespace SharpCompress.Readers; -namespace SharpCompress.Readers +public interface IReaderFactory : Factories.IFactory { - public interface IReaderFactory : Factories.IFactory - { - /// - /// Opens a Reader for Non-seeking usage - /// - /// - /// - /// - IReader OpenReader(Stream stream, ReaderOptions? options); - } + /// + /// Opens a Reader for Non-seeking usage + /// + /// + /// + /// + IReader OpenReader(Stream stream, ReaderOptions? options); } diff --git a/src/SharpCompress/Readers/Rar/MultiVolumeRarReader.cs b/src/SharpCompress/Readers/Rar/MultiVolumeRarReader.cs index 4e857626..2c29fb5f 100644 --- a/src/SharpCompress/Readers/Rar/MultiVolumeRarReader.cs +++ b/src/SharpCompress/Readers/Rar/MultiVolumeRarReader.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable using System.Collections; using System.Collections.Generic; @@ -7,117 +7,116 @@ using System.Linq; using SharpCompress.Common; using SharpCompress.Common.Rar; -namespace SharpCompress.Readers.Rar +namespace SharpCompress.Readers.Rar; + +internal class MultiVolumeRarReader : RarReader { - internal class MultiVolumeRarReader : RarReader + private readonly IEnumerator streams; + private Stream tempStream; + + internal MultiVolumeRarReader(IEnumerable streams, ReaderOptions options) + : base(options) { - private readonly IEnumerator streams; + this.streams = streams.GetEnumerator(); + } + + internal override void ValidateArchive(RarVolume archive) { } + + protected override Stream RequestInitialStream() + { + if (streams.MoveNext()) + { + return streams.Current; + } + throw new MultiVolumeExtractionException( + "No stream provided when requested by MultiVolumeRarReader" + ); + } + + internal override bool NextEntryForCurrentStream() + { + if (!base.NextEntryForCurrentStream()) + { + // if we're got another stream to try to process then do so + return streams.MoveNext() && LoadStreamForReading(streams.Current); + } + return true; + } + + protected override IEnumerable CreateFilePartEnumerableForCurrentEntry() + { + var enumerator = new MultiVolumeStreamEnumerator(this, streams, tempStream); + tempStream = null; + return enumerator; + } + + private class MultiVolumeStreamEnumerator : IEnumerable, IEnumerator + { + private readonly MultiVolumeRarReader reader; + private readonly IEnumerator nextReadableStreams; private Stream tempStream; + private bool isFirst = true; - internal MultiVolumeRarReader(IEnumerable streams, ReaderOptions options) - : base(options) + internal MultiVolumeStreamEnumerator( + MultiVolumeRarReader r, + IEnumerator nextReadableStreams, + Stream tempStream + ) { - this.streams = streams.GetEnumerator(); + reader = r; + this.nextReadableStreams = nextReadableStreams; + this.tempStream = tempStream; } - internal override void ValidateArchive(RarVolume archive) { } - - protected override Stream RequestInitialStream() + public IEnumerator GetEnumerator() { - if (streams.MoveNext()) - { - return streams.Current; - } - throw new MultiVolumeExtractionException( - "No stream provided when requested by MultiVolumeRarReader" - ); + return this; } - internal override bool NextEntryForCurrentStream() + IEnumerator IEnumerable.GetEnumerator() { - if (!base.NextEntryForCurrentStream()) - { - // if we're got another stream to try to process then do so - return streams.MoveNext() && LoadStreamForReading(streams.Current); - } - return true; + return this; } - protected override IEnumerable CreateFilePartEnumerableForCurrentEntry() + public FilePart Current { get; private set; } + + public void Dispose() { } + + object IEnumerator.Current => Current; + + public bool MoveNext() { - var enumerator = new MultiVolumeStreamEnumerator(this, streams, tempStream); - tempStream = null; - return enumerator; - } - - private class MultiVolumeStreamEnumerator : IEnumerable, IEnumerator - { - private readonly MultiVolumeRarReader reader; - private readonly IEnumerator nextReadableStreams; - private Stream tempStream; - private bool isFirst = true; - - internal MultiVolumeStreamEnumerator( - MultiVolumeRarReader r, - IEnumerator nextReadableStreams, - Stream tempStream - ) + if (isFirst) { - reader = r; - this.nextReadableStreams = nextReadableStreams; - this.tempStream = tempStream; - } - - public IEnumerator GetEnumerator() - { - return this; - } - - IEnumerator IEnumerable.GetEnumerator() - { - return this; - } - - public FilePart Current { get; private set; } - - public void Dispose() { } - - object IEnumerator.Current => Current; - - public bool MoveNext() - { - if (isFirst) - { - Current = reader.Entry.Parts.First(); - isFirst = false; //first stream already to go - return true; - } - - if (!reader.Entry.IsSplitAfter) - { - return false; - } - if (tempStream != null) - { - reader.LoadStreamForReading(tempStream); - tempStream = null; - } - else if (!nextReadableStreams.MoveNext()) - { - throw new MultiVolumeExtractionException( - "No stream provided when requested by MultiVolumeRarReader" - ); - } - else - { - reader.LoadStreamForReading(nextReadableStreams.Current); - } - Current = reader.Entry.Parts.First(); + isFirst = false; //first stream already to go return true; } - public void Reset() { } + if (!reader.Entry.IsSplitAfter) + { + return false; + } + if (tempStream != null) + { + reader.LoadStreamForReading(tempStream); + tempStream = null; + } + else if (!nextReadableStreams.MoveNext()) + { + throw new MultiVolumeExtractionException( + "No stream provided when requested by MultiVolumeRarReader" + ); + } + else + { + reader.LoadStreamForReading(nextReadableStreams.Current); + } + + Current = reader.Entry.Parts.First(); + return true; } + + public void Reset() { } } } diff --git a/src/SharpCompress/Readers/Rar/NonSeekableStreamFilePart.cs b/src/SharpCompress/Readers/Rar/NonSeekableStreamFilePart.cs index 5c545540..99db4583 100644 --- a/src/SharpCompress/Readers/Rar/NonSeekableStreamFilePart.cs +++ b/src/SharpCompress/Readers/Rar/NonSeekableStreamFilePart.cs @@ -2,19 +2,18 @@ using System.IO; using SharpCompress.Common.Rar; using SharpCompress.Common.Rar.Headers; -namespace SharpCompress.Readers.Rar +namespace SharpCompress.Readers.Rar; + +internal class NonSeekableStreamFilePart : RarFilePart { - internal class NonSeekableStreamFilePart : RarFilePart + internal NonSeekableStreamFilePart(MarkHeader mh, FileHeader fh, int index = 0) + : base(mh, fh, index) { } + + internal override Stream GetCompressedStream() { - internal NonSeekableStreamFilePart(MarkHeader mh, FileHeader fh, int index = 0) - : base(mh, fh, index) { } - - internal override Stream GetCompressedStream() - { - return FileHeader.PackedStream; - } - - internal override string FilePartName => - "Unknown Stream - File Entry: " + FileHeader.FileName; + return FileHeader.PackedStream; } + + internal override string FilePartName => + "Unknown Stream - File Entry: " + FileHeader.FileName; } diff --git a/src/SharpCompress/Readers/Rar/RarReader.cs b/src/SharpCompress/Readers/Rar/RarReader.cs index 32bf4124..b665ddf9 100644 --- a/src/SharpCompress/Readers/Rar/RarReader.cs +++ b/src/SharpCompress/Readers/Rar/RarReader.cs @@ -5,77 +5,76 @@ using SharpCompress.Common; using SharpCompress.Common.Rar; using SharpCompress.Compressors.Rar; -namespace SharpCompress.Readers.Rar +namespace SharpCompress.Readers.Rar; + +/// +/// This class faciliates Reading a Rar Archive in a non-seekable forward-only manner +/// +public abstract class RarReader : AbstractReader { + private RarVolume? volume; + internal Lazy UnpackV2017 { get; } = + new Lazy(() => new Compressors.Rar.UnpackV2017.Unpack()); + internal Lazy UnpackV1 { get; } = + new Lazy(() => new Compressors.Rar.UnpackV1.Unpack()); + + internal RarReader(ReaderOptions options) : base(options, ArchiveType.Rar) { } + + internal abstract void ValidateArchive(RarVolume archive); + + public override RarVolume Volume => volume!; + /// - /// This class faciliates Reading a Rar Archive in a non-seekable forward-only manner + /// Opens a RarReader for Non-seeking usage with a single volume /// - public abstract class RarReader : AbstractReader + /// + /// + /// + public static RarReader Open(Stream stream, ReaderOptions? options = null) { - private RarVolume? volume; - internal Lazy UnpackV2017 { get; } = - new Lazy(() => new SharpCompress.Compressors.Rar.UnpackV2017.Unpack()); - internal Lazy UnpackV1 { get; } = - new Lazy(() => new SharpCompress.Compressors.Rar.UnpackV1.Unpack()); + stream.CheckNotNull(nameof(stream)); + return new SingleVolumeRarReader(stream, options ?? new ReaderOptions()); + } - internal RarReader(ReaderOptions options) : base(options, ArchiveType.Rar) { } + /// + /// Opens a RarReader for Non-seeking usage with multiple volumes + /// + /// + /// + /// + public static RarReader Open(IEnumerable streams, ReaderOptions? options = null) + { + streams.CheckNotNull(nameof(streams)); + return new MultiVolumeRarReader(streams, options ?? new ReaderOptions()); + } - internal abstract void ValidateArchive(RarVolume archive); - - public override RarVolume Volume => volume!; - - /// - /// Opens a RarReader for Non-seeking usage with a single volume - /// - /// - /// - /// - public static RarReader Open(Stream stream, ReaderOptions? options = null) + protected override IEnumerable GetEntries(Stream stream) + { + volume = new RarReaderVolume(stream, Options); + foreach (var fp in volume.ReadFileParts()) { - stream.CheckNotNull(nameof(stream)); - return new SingleVolumeRarReader(stream, options ?? new ReaderOptions()); - } - - /// - /// Opens a RarReader for Non-seeking usage with multiple volumes - /// - /// - /// - /// - public static RarReader Open(IEnumerable streams, ReaderOptions? options = null) - { - streams.CheckNotNull(nameof(streams)); - return new MultiVolumeRarReader(streams, options ?? new ReaderOptions()); - } - - protected override IEnumerable GetEntries(Stream stream) - { - volume = new RarReaderVolume(stream, Options); - foreach (RarFilePart fp in volume.ReadFileParts()) - { - ValidateArchive(volume); - yield return new RarReaderEntry(volume.IsSolidArchive, fp); - } - } - - protected virtual IEnumerable CreateFilePartEnumerableForCurrentEntry() - { - return Entry.Parts; - } - - protected override EntryStream GetEntryStream() - { - var stream = new MultiVolumeReadOnlyStream( - CreateFilePartEnumerableForCurrentEntry().Cast(), - this - ); - if (Entry.IsRarV3) - { - return CreateEntryStream( - new RarCrcStream(UnpackV1.Value, Entry.FileHeader, stream) - ); - } - return CreateEntryStream(new RarCrcStream(UnpackV2017.Value, Entry.FileHeader, stream)); + ValidateArchive(volume); + yield return new RarReaderEntry(volume.IsSolidArchive, fp); } } + + protected virtual IEnumerable CreateFilePartEnumerableForCurrentEntry() + { + return Entry.Parts; + } + + protected override EntryStream GetEntryStream() + { + var stream = new MultiVolumeReadOnlyStream( + CreateFilePartEnumerableForCurrentEntry().Cast(), + this + ); + if (Entry.IsRarV3) + { + return CreateEntryStream( + new RarCrcStream(UnpackV1.Value, Entry.FileHeader, stream) + ); + } + return CreateEntryStream(new RarCrcStream(UnpackV2017.Value, Entry.FileHeader, stream)); + } } diff --git a/src/SharpCompress/Readers/Rar/RarReaderEntry.cs b/src/SharpCompress/Readers/Rar/RarReaderEntry.cs index 7a67392e..d6f7222f 100644 --- a/src/SharpCompress/Readers/Rar/RarReaderEntry.cs +++ b/src/SharpCompress/Readers/Rar/RarReaderEntry.cs @@ -1,34 +1,33 @@ -using System.Collections.Generic; +using System.Collections.Generic; using SharpCompress.Common; using SharpCompress.Common.Rar; using SharpCompress.Common.Rar.Headers; -namespace SharpCompress.Readers.Rar +namespace SharpCompress.Readers.Rar; + +public class RarReaderEntry : RarEntry { - public class RarReaderEntry : RarEntry + internal RarReaderEntry(bool solid, RarFilePart part) { - internal RarReaderEntry(bool solid, RarFilePart part) - { - Part = part; - IsSolid = solid; - } - - internal RarFilePart Part { get; } - - internal override IEnumerable Parts => Part.AsEnumerable(); - - internal override FileHeader FileHeader => Part.FileHeader; - - public override CompressionType CompressionType => CompressionType.Rar; - - /// - /// The compressed file size - /// - public override long CompressedSize => Part.FileHeader.CompressedSize; - - /// - /// The uncompressed file size - /// - public override long Size => Part.FileHeader.UncompressedSize; + Part = part; + IsSolid = solid; } + + internal RarFilePart Part { get; } + + internal override IEnumerable Parts => Part.AsEnumerable(); + + internal override FileHeader FileHeader => Part.FileHeader; + + public override CompressionType CompressionType => CompressionType.Rar; + + /// + /// The compressed file size + /// + public override long CompressedSize => Part.FileHeader.CompressedSize; + + /// + /// The uncompressed file size + /// + public override long Size => Part.FileHeader.UncompressedSize; } diff --git a/src/SharpCompress/Readers/Rar/RarReaderVolume.cs b/src/SharpCompress/Readers/Rar/RarReaderVolume.cs index 61e73ecb..b0f82bc3 100644 --- a/src/SharpCompress/Readers/Rar/RarReaderVolume.cs +++ b/src/SharpCompress/Readers/Rar/RarReaderVolume.cs @@ -4,21 +4,20 @@ using SharpCompress.Common.Rar; using SharpCompress.Common.Rar.Headers; using SharpCompress.IO; -namespace SharpCompress.Readers.Rar +namespace SharpCompress.Readers.Rar; + +public class RarReaderVolume : RarVolume { - public class RarReaderVolume : RarVolume + internal RarReaderVolume(Stream stream, ReaderOptions options, int index = 0) + : base(StreamingMode.Streaming, stream, options, index) { } + + internal override RarFilePart CreateFilePart(MarkHeader markHeader, FileHeader fileHeader) { - internal RarReaderVolume(Stream stream, ReaderOptions options, int index = 0) - : base(StreamingMode.Streaming, stream, options, index) { } + return new NonSeekableStreamFilePart(markHeader, fileHeader, Index); + } - internal override RarFilePart CreateFilePart(MarkHeader markHeader, FileHeader fileHeader) - { - return new NonSeekableStreamFilePart(markHeader, fileHeader, this.Index); - } - - internal override IEnumerable ReadFileParts() - { - return GetVolumeFileParts(); - } + internal override IEnumerable ReadFileParts() + { + return GetVolumeFileParts(); } } diff --git a/src/SharpCompress/Readers/Rar/SingleVolumeRarReader.cs b/src/SharpCompress/Readers/Rar/SingleVolumeRarReader.cs index 45bf884b..b7a9eff3 100644 --- a/src/SharpCompress/Readers/Rar/SingleVolumeRarReader.cs +++ b/src/SharpCompress/Readers/Rar/SingleVolumeRarReader.cs @@ -1,31 +1,30 @@ -using System.IO; +using System.IO; using SharpCompress.Common; using SharpCompress.Common.Rar; -namespace SharpCompress.Readers.Rar +namespace SharpCompress.Readers.Rar; + +internal class SingleVolumeRarReader : RarReader { - internal class SingleVolumeRarReader : RarReader + private readonly Stream stream; + + internal SingleVolumeRarReader(Stream stream, ReaderOptions options) : base(options) { - private readonly Stream stream; + this.stream = stream; + } - internal SingleVolumeRarReader(Stream stream, ReaderOptions options) : base(options) + internal override void ValidateArchive(RarVolume archive) + { + if (archive.IsMultiVolume) { - this.stream = stream; - } - - internal override void ValidateArchive(RarVolume archive) - { - if (archive.IsMultiVolume) - { - var msg = - "Streamed archive is a Multi-volume archive. Use different RarReader method to extract."; - throw new MultiVolumeExtractionException(msg); - } - } - - protected override Stream RequestInitialStream() - { - return stream; + var msg = + "Streamed archive is a Multi-volume archive. Use different RarReader method to extract."; + throw new MultiVolumeExtractionException(msg); } } + + protected override Stream RequestInitialStream() + { + return stream; + } } diff --git a/src/SharpCompress/Readers/ReaderFactory.cs b/src/SharpCompress/Readers/ReaderFactory.cs index d7e58f68..3fcb2dcd 100644 --- a/src/SharpCompress/Readers/ReaderFactory.cs +++ b/src/SharpCompress/Readers/ReaderFactory.cs @@ -1,40 +1,39 @@ using System; using System.IO; using System.Linq; - -using SharpCompress.Common; using SharpCompress.IO; -namespace SharpCompress.Readers +namespace SharpCompress.Readers; + +public static class ReaderFactory { - public static class ReaderFactory + /// + /// Opens a Reader for Non-seeking usage + /// + /// + /// + /// + public static IReader Open(Stream stream, ReaderOptions? options = null) { - /// - /// Opens a Reader for Non-seeking usage - /// - /// - /// - /// - public static IReader Open(Stream stream, ReaderOptions? options = null) + stream.CheckNotNull(nameof(stream)); + options ??= new ReaderOptions() { LeaveStreamOpen = false }; + + var rewindableStream = new RewindableStream(stream); + rewindableStream.StartRecording(); + + foreach (var factory in Factories.Factory.Factories.OfType()) { - stream.CheckNotNull(nameof(stream)); - options = options ?? new ReaderOptions() { LeaveStreamOpen = false }; - - RewindableStream rewindableStream = new RewindableStream(stream); - rewindableStream.StartRecording(); - - foreach (var factory in Factories.Factory.Factories.OfType()) + if ( + factory.TryOpenReader(rewindableStream, options, out var reader) + && reader != null + ) { - if ( - factory.TryOpenReader(rewindableStream, options, out var reader) - && reader != null - ) - return reader; + return reader; } - - throw new InvalidOperationException( - "Cannot determine compressed stream type. Supported Reader Formats: Zip, GZip, BZip2, Tar, Rar, LZip, XZ" - ); } + + throw new InvalidOperationException( + "Cannot determine compressed stream type. Supported Reader Formats: Zip, GZip, BZip2, Tar, Rar, LZip, XZ" + ); } } diff --git a/src/SharpCompress/Readers/ReaderOptions.cs b/src/SharpCompress/Readers/ReaderOptions.cs index 3891781d..706829cb 100644 --- a/src/SharpCompress/Readers/ReaderOptions.cs +++ b/src/SharpCompress/Readers/ReaderOptions.cs @@ -1,16 +1,15 @@ -using SharpCompress.Common; +using SharpCompress.Common; -namespace SharpCompress.Readers +namespace SharpCompress.Readers; + +public class ReaderOptions : OptionsBase { - public class ReaderOptions : OptionsBase - { - /// - /// Look for RarArchive (Check for self-extracting archives or cases where RarArchive isn't at the start of the file) - /// - public bool LookForHeader { get; set; } + /// + /// Look for RarArchive (Check for self-extracting archives or cases where RarArchive isn't at the start of the file) + /// + public bool LookForHeader { get; set; } - public string? Password { get; set; } + public string? Password { get; set; } - public bool DisableCheckIncomplete { get; set; } - } + public bool DisableCheckIncomplete { get; set; } } diff --git a/src/SharpCompress/Readers/ReaderProgress.cs b/src/SharpCompress/Readers/ReaderProgress.cs index 794929dd..2cffab9a 100644 --- a/src/SharpCompress/Readers/ReaderProgress.cs +++ b/src/SharpCompress/Readers/ReaderProgress.cs @@ -1,22 +1,21 @@ -using System; +using System; using SharpCompress.Common; -namespace SharpCompress.Readers +namespace SharpCompress.Readers; + +public class ReaderProgress { - public class ReaderProgress + private readonly IEntry _entry; + public long BytesTransferred { get; } + public int Iterations { get; } + + public int PercentageRead => (int)Math.Round(PercentageReadExact); + public double PercentageReadExact => (float)BytesTransferred / _entry.Size * 100; + + public ReaderProgress(IEntry entry, long bytesTransferred, int iterations) { - private readonly IEntry _entry; - public long BytesTransferred { get; } - public int Iterations { get; } - - public int PercentageRead => (int)Math.Round(PercentageReadExact); - public double PercentageReadExact => (float)BytesTransferred / _entry.Size * 100; - - public ReaderProgress(IEntry entry, long bytesTransferred, int iterations) - { - _entry = entry; - BytesTransferred = bytesTransferred; - Iterations = iterations; - } + _entry = entry; + BytesTransferred = bytesTransferred; + Iterations = iterations; } } diff --git a/src/SharpCompress/Readers/Tar/TarReader.cs b/src/SharpCompress/Readers/Tar/TarReader.cs index 707c2e58..b72b5982 100644 --- a/src/SharpCompress/Readers/Tar/TarReader.cs +++ b/src/SharpCompress/Readers/Tar/TarReader.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using SharpCompress.Archives.GZip; diff --git a/src/SharpCompress/Readers/Zip/ZipReader.cs b/src/SharpCompress/Readers/Zip/ZipReader.cs index 111b3860..2f0e34bb 100644 --- a/src/SharpCompress/Readers/Zip/ZipReader.cs +++ b/src/SharpCompress/Readers/Zip/ZipReader.cs @@ -1,62 +1,61 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.IO; using SharpCompress.Common; using SharpCompress.Common.Zip; using SharpCompress.Common.Zip.Headers; -namespace SharpCompress.Readers.Zip +namespace SharpCompress.Readers.Zip; + +public class ZipReader : AbstractReader { - public class ZipReader : AbstractReader + private readonly StreamingZipHeaderFactory _headerFactory; + + private ZipReader(Stream stream, ReaderOptions options) : base(options, ArchiveType.Zip) { - private readonly StreamingZipHeaderFactory _headerFactory; + Volume = new ZipVolume(stream, options); + _headerFactory = new StreamingZipHeaderFactory( + options.Password, + options.ArchiveEncoding + ); + } - private ZipReader(Stream stream, ReaderOptions options) : base(options, ArchiveType.Zip) + public override ZipVolume Volume { get; } + + #region Open + + /// + /// Opens a ZipReader for Non-seeking usage with a single volume + /// + /// + /// + /// + public static ZipReader Open(Stream stream, ReaderOptions? options = null) + { + stream.CheckNotNull(nameof(stream)); + return new ZipReader(stream, options ?? new ReaderOptions()); + } + + #endregion Open + + protected override IEnumerable GetEntries(Stream stream) + { + foreach (var h in _headerFactory.ReadStreamHeader(stream)) { - Volume = new ZipVolume(stream, options); - _headerFactory = new StreamingZipHeaderFactory( - options.Password, - options.ArchiveEncoding - ); - } - - public override ZipVolume Volume { get; } - - #region Open - - /// - /// Opens a ZipReader for Non-seeking usage with a single volume - /// - /// - /// - /// - public static ZipReader Open(Stream stream, ReaderOptions? options = null) - { - stream.CheckNotNull(nameof(stream)); - return new ZipReader(stream, options ?? new ReaderOptions()); - } - - #endregion Open - - protected override IEnumerable GetEntries(Stream stream) - { - foreach (ZipHeader h in _headerFactory.ReadStreamHeader(stream)) + if (h != null) { - if (h != null) + switch (h.ZipHeaderType) { - switch (h.ZipHeaderType) - { - case ZipHeaderType.LocalEntry: + case ZipHeaderType.LocalEntry: - { - yield return new ZipEntry( - new StreamingZipFilePart((LocalEntryHeader)h, stream) - ); - } - break; - case ZipHeaderType.DirectoryEnd: - { - yield break; - } + { + yield return new ZipEntry( + new StreamingZipFilePart((LocalEntryHeader)h, stream) + ); + } + break; + case ZipHeaderType.DirectoryEnd: + { + yield break; } } } diff --git a/src/SharpCompress/Utility.cs b/src/SharpCompress/Utility.cs index ff059ae6..a40da612 100644 --- a/src/SharpCompress/Utility.cs +++ b/src/SharpCompress/Utility.cs @@ -4,406 +4,406 @@ using System.Collections.Generic; using System.IO; using SharpCompress.Readers; -namespace SharpCompress +namespace SharpCompress; + +[CLSCompliant(false)] +public static class Utility { - [CLSCompliant(false)] - public static class Utility + public static ReadOnlyCollection ToReadOnly(this ICollection items) { - public static ReadOnlyCollection ToReadOnly(this ICollection items) - { - return new ReadOnlyCollection(items); - } + return new ReadOnlyCollection(items); + } - /// - /// Performs an unsigned bitwise right shift with the specified number - /// - /// Number to operate on - /// Amount of bits to shift - /// The resulting number from the shift operation - public static int URShift(int number, int bits) + /// + /// Performs an unsigned bitwise right shift with the specified number + /// + /// Number to operate on + /// Amount of bits to shift + /// The resulting number from the shift operation + public static int URShift(int number, int bits) + { + if (number >= 0) { - if (number >= 0) - { - return number >> bits; - } - return (number >> bits) + (2 << ~bits); + return number >> bits; } + return (number >> bits) + (2 << ~bits); + } - /// - /// Performs an unsigned bitwise right shift with the specified number - /// - /// Number to operate on - /// Amount of bits to shift - /// The resulting number from the shift operation - public static long URShift(long number, int bits) + /// + /// Performs an unsigned bitwise right shift with the specified number + /// + /// Number to operate on + /// Amount of bits to shift + /// The resulting number from the shift operation + public static long URShift(long number, int bits) + { + if (number >= 0) { - if (number >= 0) - { - return number >> bits; - } - return (number >> bits) + (2L << ~bits); + return number >> bits; } + return (number >> bits) + (2L << ~bits); + } - public static void SetSize(this List list, int count) + public static void SetSize(this List list, int count) + { + if (count > list.Count) { - if (count > list.Count) + // Ensure the list only needs to grow once + list.Capacity = count; + for (var i = list.Count; i < count; i++) { - // Ensure the list only needs to grow once - list.Capacity = count; - for (int i = list.Count; i < count; i++) - { - list.Add(0x0); - } - } - else - { - list.RemoveRange(count, list.Count - count); + list.Add(0x0); } } - - public static void ForEach(this IEnumerable items, Action action) + else { - foreach (T item in items) - { - action(item); - } - } - - public static void Copy( - Array sourceArray, - long sourceIndex, - Array destinationArray, - long destinationIndex, - long length - ) - { - if (sourceIndex > Int32.MaxValue || sourceIndex < Int32.MinValue) - { - throw new ArgumentOutOfRangeException(nameof(sourceIndex)); - } - - if (destinationIndex > Int32.MaxValue || destinationIndex < Int32.MinValue) - { - throw new ArgumentOutOfRangeException(nameof(destinationIndex)); - } - - if (length > Int32.MaxValue || length < Int32.MinValue) - { - throw new ArgumentOutOfRangeException(nameof(length)); - } - - Array.Copy( - sourceArray, - (int)sourceIndex, - destinationArray, - (int)destinationIndex, - (int)length - ); - } - - public static IEnumerable AsEnumerable(this T item) - { - yield return item; - } - - public static void CheckNotNull(this object obj, string name) - { - if (obj is null) - { - throw new ArgumentNullException(name); - } - } - - public static void CheckNotNullOrEmpty(this string obj, string name) - { - obj.CheckNotNull(name); - if (obj.Length == 0) - { - throw new ArgumentException("String is empty.", name); - } - } - - public static void Skip(this Stream source, long advanceAmount) - { - if (source.CanSeek) - { - source.Position += advanceAmount; - return; - } - - byte[] buffer = GetTransferByteArray(); - try - { - int read = 0; - int readCount = 0; - do - { - readCount = buffer.Length; - if (readCount > advanceAmount) - { - readCount = (int)advanceAmount; - } - read = source.Read(buffer, 0, readCount); - if (read <= 0) - { - break; - } - advanceAmount -= read; - if (advanceAmount == 0) - { - break; - } - } while (true); - } - finally - { - ArrayPool.Shared.Return(buffer); - } - } - - public static void Skip(this Stream source) - { - byte[] buffer = GetTransferByteArray(); - try - { - do { } while (source.Read(buffer, 0, buffer.Length) == buffer.Length); - } - finally - { - ArrayPool.Shared.Return(buffer); - } - } - - public static bool Find(this Stream source, byte[] array) - { - byte[] buffer = GetTransferByteArray(); - try - { - int count = 0; - var len = source.Read(buffer, 0, buffer.Length); - - do - { - for (int i = 0; i < len; i++) - { - if (array[count] == buffer[i]) - { - count++; - if (count == array.Length) - { - source.Position = source.Position - len + i - array.Length + 1; - return true; - } - } - } - } while ((len = source.Read(buffer, 0, buffer.Length)) > 0); - } - finally - { - ArrayPool.Shared.Return(buffer); - } - - return false; - } - - public static DateTime DosDateToDateTime(UInt16 iDate, UInt16 iTime) - { - int year = iDate / 512 + 1980; - int month = iDate % 512 / 32; - int day = iDate % 512 % 32; - int hour = iTime / 2048; - int minute = iTime % 2048 / 32; - int second = iTime % 2048 % 32 * 2; - - if (iDate == UInt16.MaxValue || month == 0 || day == 0) - { - year = 1980; - month = 1; - day = 1; - } - - if (iTime == UInt16.MaxValue) - { - hour = minute = second = 0; - } - - DateTime dt; - try - { - dt = new DateTime(year, month, day, hour, minute, second, DateTimeKind.Local); - } - catch - { - dt = new DateTime(); - } - return dt; - } - - public static uint DateTimeToDosTime(this DateTime? dateTime) - { - if (dateTime is null) - { - return 0; - } - - var localDateTime = dateTime.Value.ToLocalTime(); - - return (uint)( - (localDateTime.Second / 2) - | (localDateTime.Minute << 5) - | (localDateTime.Hour << 11) - | (localDateTime.Day << 16) - | (localDateTime.Month << 21) - | ((localDateTime.Year - 1980) << 25) - ); - } - - public static DateTime DosDateToDateTime(UInt32 iTime) - { - return DosDateToDateTime((UInt16)(iTime / 65536), (UInt16)(iTime % 65536)); - } - - /// - /// Convert Unix time value to a DateTime object. - /// - /// The Unix time stamp you want to convert to DateTime. - /// Returns a DateTime object that represents value of the Unix time. - public static DateTime UnixTimeToDateTime(long unixtime) - { - DateTime sTime = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); - return sTime.AddSeconds(unixtime); - } - - public static long TransferTo(this Stream source, Stream destination) - { - byte[] array = GetTransferByteArray(); - try - { - long total = 0; - while (ReadTransferBlock(source, array, out int count)) - { - total += count; - destination.Write(array, 0, count); - } - return total; - } - finally - { - ArrayPool.Shared.Return(array); - } - } - - public static long TransferTo( - this Stream source, - Stream destination, - Common.Entry entry, - IReaderExtractionListener readerExtractionListener - ) - { - byte[] array = GetTransferByteArray(); - try - { - var iterations = 0; - long total = 0; - while (ReadTransferBlock(source, array, out int count)) - { - total += count; - destination.Write(array, 0, count); - iterations++; - readerExtractionListener.FireEntryExtractionProgress(entry, total, iterations); - } - return total; - } - finally - { - ArrayPool.Shared.Return(array); - } - } - - private static bool ReadTransferBlock(Stream source, byte[] array, out int count) - { - return (count = source.Read(array, 0, array.Length)) != 0; - } - - private static byte[] GetTransferByteArray() - { - return ArrayPool.Shared.Rent(81920); - } - - public static bool ReadFully(this Stream stream, byte[] buffer) - { - int total = 0; - int read; - while ((read = stream.Read(buffer, total, buffer.Length - total)) > 0) - { - total += read; - if (total >= buffer.Length) - { - return true; - } - } - return (total >= buffer.Length); - } - - public static bool ReadFully(this Stream stream, Span buffer) - { - int total = 0; - int read; - while ((read = stream.Read(buffer.Slice(total, buffer.Length - total))) > 0) - { - total += read; - if (total >= buffer.Length) - { - return true; - } - } - return (total >= buffer.Length); - } - - public static string TrimNulls(this string source) - { - return source.Replace('\0', ' ').Trim(); - } - - /// - /// Swap the endianness of a UINT32 - /// - /// The UINT32 you want to swap his endianness - /// Return the new UINT32 in the other endianness format - public static UInt32 SwapUINT32(UInt32 number) - { - return (number >> 24) - | ((number << 8) & 0x00FF0000) - | ((number >> 8) & 0x0000FF00) - | (number << 24); - } - - /// - /// Insert a little endian UINT32 into a byte array - /// - /// The buffer to insert into - /// The UINT32 to insert - /// Offset of the buffer to insert into - public static void SetLittleUInt32(ref byte[] buffer, UInt32 number, long offset) - { - buffer[offset] = (byte)(number); - buffer[offset + 1] = (byte)(number >> 8); - buffer[offset + 2] = (byte)(number >> 16); - buffer[offset + 3] = (byte)(number >> 24); - } - - /// - /// Insert a big endian UINT32 into a byte array - /// - /// The buffer to insert into - /// The UINT32 to insert - /// Offset of the buffer to insert into - public static void SetBigUInt32(ref byte[] buffer, UInt32 number, long offset) - { - buffer[offset] = (byte)(number >> 24); - buffer[offset + 1] = (byte)(number >> 16); - buffer[offset + 2] = (byte)(number >> 8); - buffer[offset + 3] = (byte)number; + list.RemoveRange(count, list.Count - count); } } + + public static void ForEach(this IEnumerable items, Action action) + { + foreach (var item in items) + { + action(item); + } + } + + public static void Copy( + Array sourceArray, + long sourceIndex, + Array destinationArray, + long destinationIndex, + long length + ) + { + if (sourceIndex > int.MaxValue || sourceIndex < int.MinValue) + { + throw new ArgumentOutOfRangeException(nameof(sourceIndex)); + } + + if (destinationIndex > int.MaxValue || destinationIndex < int.MinValue) + { + throw new ArgumentOutOfRangeException(nameof(destinationIndex)); + } + + if (length > int.MaxValue || length < int.MinValue) + { + throw new ArgumentOutOfRangeException(nameof(length)); + } + + Array.Copy( + sourceArray, + (int)sourceIndex, + destinationArray, + (int)destinationIndex, + (int)length + ); + } + + public static IEnumerable AsEnumerable(this T item) + { + yield return item; + } + + public static void CheckNotNull(this object obj, string name) + { + if (obj is null) + { + throw new ArgumentNullException(name); + } + } + + public static void CheckNotNullOrEmpty(this string obj, string name) + { + obj.CheckNotNull(name); + if (obj.Length == 0) + { + throw new ArgumentException("String is empty.", name); + } + } + + public static void Skip(this Stream source, long advanceAmount) + { + if (source.CanSeek) + { + source.Position += advanceAmount; + return; + } + + var buffer = GetTransferByteArray(); + try + { + var read = 0; + var readCount = 0; + do + { + readCount = buffer.Length; + if (readCount > advanceAmount) + { + readCount = (int)advanceAmount; + } + read = source.Read(buffer, 0, readCount); + if (read <= 0) + { + break; + } + advanceAmount -= read; + if (advanceAmount == 0) + { + break; + } + } while (true); + } + finally + { + ArrayPool.Shared.Return(buffer); + } + } + + public static void Skip(this Stream source) + { + var buffer = GetTransferByteArray(); + try + { + do + { } while (source.Read(buffer, 0, buffer.Length) == buffer.Length); + } + finally + { + ArrayPool.Shared.Return(buffer); + } + } + + public static bool Find(this Stream source, byte[] array) + { + var buffer = GetTransferByteArray(); + try + { + var count = 0; + var len = source.Read(buffer, 0, buffer.Length); + + do + { + for (var i = 0; i < len; i++) + { + if (array[count] == buffer[i]) + { + count++; + if (count == array.Length) + { + source.Position = source.Position - len + i - array.Length + 1; + return true; + } + } + } + } while ((len = source.Read(buffer, 0, buffer.Length)) > 0); + } + finally + { + ArrayPool.Shared.Return(buffer); + } + + return false; + } + + public static DateTime DosDateToDateTime(ushort iDate, ushort iTime) + { + var year = (iDate / 512) + 1980; + var month = iDate % 512 / 32; + var day = iDate % 512 % 32; + var hour = iTime / 2048; + var minute = iTime % 2048 / 32; + var second = iTime % 2048 % 32 * 2; + + if (iDate == ushort.MaxValue || month == 0 || day == 0) + { + year = 1980; + month = 1; + day = 1; + } + + if (iTime == ushort.MaxValue) + { + hour = minute = second = 0; + } + + DateTime dt; + try + { + dt = new DateTime(year, month, day, hour, minute, second, DateTimeKind.Local); + } + catch + { + dt = new DateTime(); + } + return dt; + } + + public static uint DateTimeToDosTime(this DateTime? dateTime) + { + if (dateTime is null) + { + return 0; + } + + var localDateTime = dateTime.Value.ToLocalTime(); + + return (uint)( + (localDateTime.Second / 2) + | (localDateTime.Minute << 5) + | (localDateTime.Hour << 11) + | (localDateTime.Day << 16) + | (localDateTime.Month << 21) + | ((localDateTime.Year - 1980) << 25) + ); + } + + public static DateTime DosDateToDateTime(uint iTime) + { + return DosDateToDateTime((ushort)(iTime / 65536), (ushort)(iTime % 65536)); + } + + /// + /// Convert Unix time value to a DateTime object. + /// + /// The Unix time stamp you want to convert to DateTime. + /// Returns a DateTime object that represents value of the Unix time. + public static DateTime UnixTimeToDateTime(long unixtime) + { + var sTime = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + return sTime.AddSeconds(unixtime); + } + + public static long TransferTo(this Stream source, Stream destination) + { + var array = GetTransferByteArray(); + try + { + long total = 0; + while (ReadTransferBlock(source, array, out var count)) + { + total += count; + destination.Write(array, 0, count); + } + return total; + } + finally + { + ArrayPool.Shared.Return(array); + } + } + + public static long TransferTo( + this Stream source, + Stream destination, + Common.Entry entry, + IReaderExtractionListener readerExtractionListener + ) + { + var array = GetTransferByteArray(); + try + { + var iterations = 0; + long total = 0; + while (ReadTransferBlock(source, array, out var count)) + { + total += count; + destination.Write(array, 0, count); + iterations++; + readerExtractionListener.FireEntryExtractionProgress(entry, total, iterations); + } + return total; + } + finally + { + ArrayPool.Shared.Return(array); + } + } + + private static bool ReadTransferBlock(Stream source, byte[] array, out int count) + { + return (count = source.Read(array, 0, array.Length)) != 0; + } + + private static byte[] GetTransferByteArray() + { + return ArrayPool.Shared.Rent(81920); + } + + public static bool ReadFully(this Stream stream, byte[] buffer) + { + var total = 0; + int read; + while ((read = stream.Read(buffer, total, buffer.Length - total)) > 0) + { + total += read; + if (total >= buffer.Length) + { + return true; + } + } + return (total >= buffer.Length); + } + + public static bool ReadFully(this Stream stream, Span buffer) + { + var total = 0; + int read; + while ((read = stream.Read(buffer.Slice(total, buffer.Length - total))) > 0) + { + total += read; + if (total >= buffer.Length) + { + return true; + } + } + return (total >= buffer.Length); + } + + public static string TrimNulls(this string source) + { + return source.Replace('\0', ' ').Trim(); + } + + /// + /// Swap the endianness of a UINT32 + /// + /// The UINT32 you want to swap his endianness + /// Return the new UINT32 in the other endianness format + public static uint SwapUINT32(uint number) + { + return (number >> 24) + | ((number << 8) & 0x00FF0000) + | ((number >> 8) & 0x0000FF00) + | (number << 24); + } + + /// + /// Insert a little endian UINT32 into a byte array + /// + /// The buffer to insert into + /// The UINT32 to insert + /// Offset of the buffer to insert into + public static void SetLittleUInt32(ref byte[] buffer, uint number, long offset) + { + buffer[offset] = (byte)(number); + buffer[offset + 1] = (byte)(number >> 8); + buffer[offset + 2] = (byte)(number >> 16); + buffer[offset + 3] = (byte)(number >> 24); + } + + /// + /// Insert a big endian UINT32 into a byte array + /// + /// The buffer to insert into + /// The UINT32 to insert + /// Offset of the buffer to insert into + public static void SetBigUInt32(ref byte[] buffer, uint number, long offset) + { + buffer[offset] = (byte)(number >> 24); + buffer[offset + 1] = (byte)(number >> 16); + buffer[offset + 2] = (byte)(number >> 8); + buffer[offset + 3] = (byte)number; + } } diff --git a/src/SharpCompress/Writers/AbstractWriter.cs b/src/SharpCompress/Writers/AbstractWriter.cs index 0c910f69..0fe95c5b 100644 --- a/src/SharpCompress/Writers/AbstractWriter.cs +++ b/src/SharpCompress/Writers/AbstractWriter.cs @@ -1,59 +1,58 @@ -#nullable disable +#nullable disable using System; using System.IO; using SharpCompress.Common; -namespace SharpCompress.Writers +namespace SharpCompress.Writers; + +public abstract class AbstractWriter : IWriter { - public abstract class AbstractWriter : IWriter + private bool _isDisposed; + + protected AbstractWriter(ArchiveType type, WriterOptions writerOptions) { - private bool _isDisposed; + WriterType = type; + WriterOptions = writerOptions; + } - protected AbstractWriter(ArchiveType type, WriterOptions writerOptions) + protected void InitalizeStream(Stream stream) + { + OutputStream = stream; + } + + protected Stream OutputStream { get; private set; } + + public ArchiveType WriterType { get; } + + protected WriterOptions WriterOptions { get; } + + public abstract void Write(string filename, Stream source, DateTime? modificationTime); + + protected virtual void Dispose(bool isDisposing) + { + if (isDisposing) { - WriterType = type; - WriterOptions = writerOptions; + OutputStream.Dispose(); } + } - protected void InitalizeStream(Stream stream) + public void Dispose() + { + if (!_isDisposed) { - OutputStream = stream; + GC.SuppressFinalize(this); + Dispose(true); + _isDisposed = true; } + } - protected Stream OutputStream { get; private set; } - - public ArchiveType WriterType { get; } - - protected WriterOptions WriterOptions { get; } - - public abstract void Write(string filename, Stream source, DateTime? modificationTime); - - protected virtual void Dispose(bool isDisposing) + ~AbstractWriter() + { + if (!_isDisposed) { - if (isDisposing) - { - OutputStream.Dispose(); - } - } - - public void Dispose() - { - if (!_isDisposed) - { - GC.SuppressFinalize(this); - Dispose(true); - _isDisposed = true; - } - } - - ~AbstractWriter() - { - if (!_isDisposed) - { - Dispose(false); - _isDisposed = true; - } + Dispose(false); + _isDisposed = true; } } } diff --git a/src/SharpCompress/Writers/GZip/GZipWriter.cs b/src/SharpCompress/Writers/GZip/GZipWriter.cs index b7d32ed2..5c990a7d 100644 --- a/src/SharpCompress/Writers/GZip/GZipWriter.cs +++ b/src/SharpCompress/Writers/GZip/GZipWriter.cs @@ -5,50 +5,49 @@ using SharpCompress.Compressors; using SharpCompress.Compressors.Deflate; using SharpCompress.IO; -namespace SharpCompress.Writers.GZip +namespace SharpCompress.Writers.GZip; + +public sealed class GZipWriter : AbstractWriter { - public sealed class GZipWriter : AbstractWriter + private bool _wroteToStream; + + public GZipWriter(Stream destination, GZipWriterOptions? options = null) + : base(ArchiveType.GZip, options ?? new GZipWriterOptions()) { - private bool _wroteToStream; - - public GZipWriter(Stream destination, GZipWriterOptions? options = null) - : base(ArchiveType.GZip, options ?? new GZipWriterOptions()) + if (WriterOptions.LeaveStreamOpen) { - if (WriterOptions.LeaveStreamOpen) - { - destination = NonDisposingStream.Create(destination); - } - InitalizeStream( - new GZipStream( - destination, - CompressionMode.Compress, - options?.CompressionLevel ?? CompressionLevel.Default, - WriterOptions.ArchiveEncoding.GetEncoding() - ) - ); + destination = NonDisposingStream.Create(destination); } + InitalizeStream( + new GZipStream( + destination, + CompressionMode.Compress, + options?.CompressionLevel ?? CompressionLevel.Default, + WriterOptions.ArchiveEncoding.GetEncoding() + ) + ); + } - protected override void Dispose(bool isDisposing) + protected override void Dispose(bool isDisposing) + { + if (isDisposing) { - if (isDisposing) - { - //dispose here to finish the GZip, GZip won't close the underlying stream - OutputStream.Dispose(); - } - base.Dispose(isDisposing); + //dispose here to finish the GZip, GZip won't close the underlying stream + OutputStream.Dispose(); } + base.Dispose(isDisposing); + } - public override void Write(string filename, Stream source, DateTime? modificationTime) + public override void Write(string filename, Stream source, DateTime? modificationTime) + { + if (_wroteToStream) { - if (_wroteToStream) - { - throw new ArgumentException("Can only write a single stream to a GZip file."); - } - GZipStream stream = (GZipStream)OutputStream; - stream.FileName = filename; - stream.LastModified = modificationTime; - source.TransferTo(stream); - _wroteToStream = true; + throw new ArgumentException("Can only write a single stream to a GZip file."); } + var stream = (GZipStream)OutputStream; + stream.FileName = filename; + stream.LastModified = modificationTime; + source.TransferTo(stream); + _wroteToStream = true; } } diff --git a/src/SharpCompress/Writers/GZip/GZipWriterOptions.cs b/src/SharpCompress/Writers/GZip/GZipWriterOptions.cs index cef2744a..faff1cc0 100644 --- a/src/SharpCompress/Writers/GZip/GZipWriterOptions.cs +++ b/src/SharpCompress/Writers/GZip/GZipWriterOptions.cs @@ -1,24 +1,22 @@ -using SharpCompress.Common; +using SharpCompress.Common; using SharpCompress.Compressors.Deflate; -namespace SharpCompress.Writers.GZip +namespace SharpCompress.Writers.GZip; + +public class GZipWriterOptions : WriterOptions { - public class GZipWriterOptions : WriterOptions + public GZipWriterOptions() : base(CompressionType.GZip) { } + + internal GZipWriterOptions(WriterOptions options) : base(options.CompressionType) { - public GZipWriterOptions() : base(CompressionType.GZip) { } + LeaveStreamOpen = options.LeaveStreamOpen; + ArchiveEncoding = options.ArchiveEncoding; - internal GZipWriterOptions(WriterOptions options) : base(options.CompressionType) + if (options is GZipWriterOptions writerOptions) { - LeaveStreamOpen = options.LeaveStreamOpen; - ArchiveEncoding = options.ArchiveEncoding; - - var writerOptions = options as GZipWriterOptions; - if (writerOptions != null) - { - CompressionLevel = writerOptions.CompressionLevel; - } + CompressionLevel = writerOptions.CompressionLevel; } - - public CompressionLevel CompressionLevel { get; set; } = CompressionLevel.Default; } + + public CompressionLevel CompressionLevel { get; set; } = CompressionLevel.Default; } diff --git a/src/SharpCompress/Writers/IWriter.cs b/src/SharpCompress/Writers/IWriter.cs index 0c8cb5ab..bde2fcd9 100644 --- a/src/SharpCompress/Writers/IWriter.cs +++ b/src/SharpCompress/Writers/IWriter.cs @@ -1,12 +1,11 @@ -using System; +using System; using System.IO; using SharpCompress.Common; -namespace SharpCompress.Writers +namespace SharpCompress.Writers; + +public interface IWriter : IDisposable { - public interface IWriter : IDisposable - { - ArchiveType WriterType { get; } - void Write(string filename, Stream source, DateTime? modificationTime); - } + ArchiveType WriterType { get; } + void Write(string filename, Stream source, DateTime? modificationTime); } diff --git a/src/SharpCompress/Writers/IWriterExtensions.cs b/src/SharpCompress/Writers/IWriterExtensions.cs index 9335c46e..f61daf13 100644 --- a/src/SharpCompress/Writers/IWriterExtensions.cs +++ b/src/SharpCompress/Writers/IWriterExtensions.cs @@ -1,69 +1,62 @@ -using System; +using System; using System.IO; using System.Linq; -using System.Linq.Expressions; -namespace SharpCompress.Writers +namespace SharpCompress.Writers; + +public static class IWriterExtensions { - public static class IWriterExtensions + public static void Write(this IWriter writer, string entryPath, Stream source) { - public static void Write(this IWriter writer, string entryPath, Stream source) + writer.Write(entryPath, source, null); + } + + public static void Write(this IWriter writer, string entryPath, FileInfo source) + { + if (!source.Exists) { - writer.Write(entryPath, source, null); + throw new ArgumentException("Source does not exist: " + source.FullName); + } + using var stream = source.OpenRead(); + writer.Write(entryPath, stream, source.LastWriteTime); + } + + public static void Write(this IWriter writer, string entryPath, string source) + { + writer.Write(entryPath, new FileInfo(source)); + } + + public static void WriteAll( + this IWriter writer, + string directory, + string searchPattern = "*", + SearchOption option = SearchOption.TopDirectoryOnly + ) + { + writer.WriteAll(directory, searchPattern, null, option); + } + + public static void WriteAll( + this IWriter writer, + string directory, + string searchPattern = "*", + Func? fileSearchFunc = null, + SearchOption option = SearchOption.TopDirectoryOnly + ) + { + if (!Directory.Exists(directory)) + { + throw new ArgumentException("Directory does not exist: " + directory); } - public static void Write(this IWriter writer, string entryPath, FileInfo source) - { - if (!source.Exists) - { - throw new ArgumentException("Source does not exist: " + source.FullName); - } - using (var stream = source.OpenRead()) - { - writer.Write(entryPath, stream, source.LastWriteTime); - } - } - - public static void Write(this IWriter writer, string entryPath, string source) - { - writer.Write(entryPath, new FileInfo(source)); - } - - public static void WriteAll( - this IWriter writer, - string directory, - string searchPattern = "*", - SearchOption option = SearchOption.TopDirectoryOnly + fileSearchFunc ??= n => true; + foreach ( + var file in Directory + .EnumerateFiles(directory, searchPattern, option) + .Where(fileSearchFunc) ) { - writer.WriteAll(directory, searchPattern, null, option); - } - - public static void WriteAll( - this IWriter writer, - string directory, - string searchPattern = "*", - Func? fileSearchFunc = null, - SearchOption option = SearchOption.TopDirectoryOnly - ) - { - if (!Directory.Exists(directory)) - { - throw new ArgumentException("Directory does not exist: " + directory); - } - - if (fileSearchFunc is null) - { - fileSearchFunc = n => true; - } - foreach ( - var file in Directory - .EnumerateFiles(directory, searchPattern, option) - .Where(fileSearchFunc) - ) - { - writer.Write(file.Substring(directory.Length), file); - } + writer.Write(file.Substring(directory.Length), file); } } } diff --git a/src/SharpCompress/Writers/IWriterFactory.cs b/src/SharpCompress/Writers/IWriterFactory.cs index 1aed7c72..8e7bc701 100644 --- a/src/SharpCompress/Writers/IWriterFactory.cs +++ b/src/SharpCompress/Writers/IWriterFactory.cs @@ -1,16 +1,10 @@ -using System; -using System.Collections.Generic; using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using SharpCompress.Factories; -namespace SharpCompress.Writers +namespace SharpCompress.Writers; + +public interface IWriterFactory : IFactory { - public interface IWriterFactory : IFactory - { - IWriter Open(Stream stream, WriterOptions writerOptions); - } + IWriter Open(Stream stream, WriterOptions writerOptions); } diff --git a/src/SharpCompress/Writers/Tar/TarWriter.cs b/src/SharpCompress/Writers/Tar/TarWriter.cs index b6b4da5c..223e6303 100644 --- a/src/SharpCompress/Writers/Tar/TarWriter.cs +++ b/src/SharpCompress/Writers/Tar/TarWriter.cs @@ -8,125 +8,124 @@ using SharpCompress.Compressors.Deflate; using SharpCompress.Compressors.LZMA; using SharpCompress.IO; -namespace SharpCompress.Writers.Tar +namespace SharpCompress.Writers.Tar; + +public class TarWriter : AbstractWriter { - public class TarWriter : AbstractWriter + private readonly bool finalizeArchiveOnClose; + + public TarWriter(Stream destination, TarWriterOptions options) + : base(ArchiveType.Tar, options) { - private readonly bool finalizeArchiveOnClose; + finalizeArchiveOnClose = options.FinalizeArchiveOnClose; - public TarWriter(Stream destination, TarWriterOptions options) - : base(ArchiveType.Tar, options) + if (!destination.CanWrite) { - finalizeArchiveOnClose = options.FinalizeArchiveOnClose; + throw new ArgumentException("Tars require writable streams."); + } + if (WriterOptions.LeaveStreamOpen) + { + destination = NonDisposingStream.Create(destination); + } + switch (options.CompressionType) + { + case CompressionType.None: + break; + case CompressionType.BZip2: - if (!destination.CanWrite) { - throw new ArgumentException("Tars require writable streams."); + destination = new BZip2Stream(destination, CompressionMode.Compress, false); } - if (WriterOptions.LeaveStreamOpen) + break; + case CompressionType.GZip: + { - destination = NonDisposingStream.Create(destination); + destination = new GZipStream(destination, CompressionMode.Compress); } - switch (options.CompressionType) + break; + case CompressionType.LZip: + { - case CompressionType.None: - break; - case CompressionType.BZip2: + destination = new LZipStream(destination, CompressionMode.Compress); + } + break; + default: + { + throw new InvalidFormatException( + "Tar does not support compression: " + options.CompressionType + ); + } + } + InitalizeStream(destination); + } - { - destination = new BZip2Stream(destination, CompressionMode.Compress, false); - } - break; - case CompressionType.GZip: + public override void Write(string filename, Stream source, DateTime? modificationTime) + { + Write(filename, source, modificationTime, null); + } - { - destination = new GZipStream(destination, CompressionMode.Compress); - } - break; - case CompressionType.LZip: + private string NormalizeFilename(string filename) + { + filename = filename.Replace('\\', '/'); - { - destination = new LZipStream(destination, CompressionMode.Compress); - } - break; - default: + var pos = filename.IndexOf(':'); + if (pos >= 0) + { + filename = filename.Remove(0, pos + 1); + } + + return filename.Trim('/'); + } + + public void Write(string filename, Stream source, DateTime? modificationTime, long? size) + { + if (!source.CanSeek && size is null) + { + throw new ArgumentException("Seekable stream is required if no size is given."); + } + + var realSize = size ?? source.Length; + + var header = new TarHeader(WriterOptions.ArchiveEncoding); + + header.LastModifiedTime = modificationTime ?? TarHeader.EPOCH; + header.Name = NormalizeFilename(filename); + header.Size = realSize; + header.Write(OutputStream); + + size = source.TransferTo(OutputStream); + PadTo512(size.Value); + } + + private void PadTo512(long size) + { + var zeros = unchecked((int)(((size + 511L) & ~511L) - size)); + + OutputStream.Write(stackalloc byte[zeros]); + } + + protected override void Dispose(bool isDisposing) + { + if (isDisposing) + { + if (finalizeArchiveOnClose) + { + OutputStream.Write(stackalloc byte[1024]); + } + switch (OutputStream) + { + case BZip2Stream b: { - throw new InvalidFormatException( - "Tar does not support compression: " + options.CompressionType - ); + b.Finish(); + break; + } + case LZipStream l: + { + l.Finish(); + break; } } - InitalizeStream(destination); - } - - public override void Write(string filename, Stream source, DateTime? modificationTime) - { - Write(filename, source, modificationTime, null); - } - - private string NormalizeFilename(string filename) - { - filename = filename.Replace('\\', '/'); - - int pos = filename.IndexOf(':'); - if (pos >= 0) - { - filename = filename.Remove(0, pos + 1); - } - - return filename.Trim('/'); - } - - public void Write(string filename, Stream source, DateTime? modificationTime, long? size) - { - if (!source.CanSeek && size is null) - { - throw new ArgumentException("Seekable stream is required if no size is given."); - } - - long realSize = size ?? source.Length; - - TarHeader header = new TarHeader(WriterOptions.ArchiveEncoding); - - header.LastModifiedTime = modificationTime ?? TarHeader.EPOCH; - header.Name = NormalizeFilename(filename); - header.Size = realSize; - header.Write(OutputStream); - - size = source.TransferTo(OutputStream); - PadTo512(size.Value); - } - - private void PadTo512(long size) - { - int zeros = unchecked((int)(((size + 511L) & ~511L) - size)); - - OutputStream.Write(stackalloc byte[zeros]); - } - - protected override void Dispose(bool isDisposing) - { - if (isDisposing) - { - if (finalizeArchiveOnClose) - { - OutputStream.Write(stackalloc byte[1024]); - } - switch (OutputStream) - { - case BZip2Stream b: - { - b.Finish(); - break; - } - case LZipStream l: - { - l.Finish(); - break; - } - } - } - base.Dispose(isDisposing); } + base.Dispose(isDisposing); } } diff --git a/src/SharpCompress/Writers/Tar/TarWriterOptions.cs b/src/SharpCompress/Writers/Tar/TarWriterOptions.cs index f3cc26db..c95ceba4 100755 --- a/src/SharpCompress/Writers/Tar/TarWriterOptions.cs +++ b/src/SharpCompress/Writers/Tar/TarWriterOptions.cs @@ -1,23 +1,22 @@ using SharpCompress.Common; -namespace SharpCompress.Writers.Tar +namespace SharpCompress.Writers.Tar; + +public class TarWriterOptions : WriterOptions { - public class TarWriterOptions : WriterOptions + /// + /// Indicates if archive should be finalized (by 2 empty blocks) on close. + /// + public bool FinalizeArchiveOnClose { get; } + + public TarWriterOptions(CompressionType compressionType, bool finalizeArchiveOnClose) + : base(compressionType) { - /// - /// Indicates if archive should be finalized (by 2 empty blocks) on close. - /// - public bool FinalizeArchiveOnClose { get; } + FinalizeArchiveOnClose = finalizeArchiveOnClose; + } - public TarWriterOptions(CompressionType compressionType, bool finalizeArchiveOnClose) - : base(compressionType) - { - FinalizeArchiveOnClose = finalizeArchiveOnClose; - } - - internal TarWriterOptions(WriterOptions options) : this(options.CompressionType, true) - { - ArchiveEncoding = options.ArchiveEncoding; - } + internal TarWriterOptions(WriterOptions options) : this(options.CompressionType, true) + { + ArchiveEncoding = options.ArchiveEncoding; } } diff --git a/src/SharpCompress/Writers/WriterFactory.cs b/src/SharpCompress/Writers/WriterFactory.cs index cd7102c5..fc4f1319 100644 --- a/src/SharpCompress/Writers/WriterFactory.cs +++ b/src/SharpCompress/Writers/WriterFactory.cs @@ -4,24 +4,25 @@ using System.Linq; using SharpCompress.Common; -namespace SharpCompress.Writers +namespace SharpCompress.Writers; + +public static class WriterFactory { - public static class WriterFactory + public static IWriter Open( + Stream stream, + ArchiveType archiveType, + WriterOptions writerOptions + ) { - public static IWriter Open( - Stream stream, - ArchiveType archiveType, - WriterOptions writerOptions - ) + var factory = Factories.Factory.Factories + .OfType() + .FirstOrDefault(item => item.KnownArchiveType == archiveType); + + if (factory != null) { - var factory = Factories.Factory.Factories - .OfType() - .FirstOrDefault(item => item.KnownArchiveType == archiveType); - - if (factory != null) - return factory.Open(stream, writerOptions); - - throw new NotSupportedException("Archive Type does not have a Writer: " + archiveType); + return factory.Open(stream, writerOptions); } + + throw new NotSupportedException("Archive Type does not have a Writer: " + archiveType); } } diff --git a/src/SharpCompress/Writers/WriterOptions.cs b/src/SharpCompress/Writers/WriterOptions.cs index db3b83c7..01b21bea 100644 --- a/src/SharpCompress/Writers/WriterOptions.cs +++ b/src/SharpCompress/Writers/WriterOptions.cs @@ -1,19 +1,18 @@ -using SharpCompress.Common; +using SharpCompress.Common; -namespace SharpCompress.Writers +namespace SharpCompress.Writers; + +public class WriterOptions : OptionsBase { - public class WriterOptions : OptionsBase + public WriterOptions(CompressionType compressionType) { - public WriterOptions(CompressionType compressionType) - { - CompressionType = compressionType; - } + CompressionType = compressionType; + } - public CompressionType CompressionType { get; set; } + public CompressionType CompressionType { get; set; } - public static implicit operator WriterOptions(CompressionType compressionType) - { - return new WriterOptions(compressionType); - } + public static implicit operator WriterOptions(CompressionType compressionType) + { + return new WriterOptions(compressionType); } } diff --git a/src/SharpCompress/Writers/Zip/ZipCentralDirectoryEntry.cs b/src/SharpCompress/Writers/Zip/ZipCentralDirectoryEntry.cs index de54e622..111c7239 100644 --- a/src/SharpCompress/Writers/Zip/ZipCentralDirectoryEntry.cs +++ b/src/SharpCompress/Writers/Zip/ZipCentralDirectoryEntry.cs @@ -6,170 +6,169 @@ using SharpCompress.Common; using SharpCompress.Common.Zip; using SharpCompress.Common.Zip.Headers; -namespace SharpCompress.Writers.Zip +namespace SharpCompress.Writers.Zip; + +internal class ZipCentralDirectoryEntry { - internal class ZipCentralDirectoryEntry + private readonly ZipCompressionMethod compression; + private readonly string fileName; + private readonly ArchiveEncoding archiveEncoding; + + public ZipCentralDirectoryEntry( + ZipCompressionMethod compression, + string fileName, + ulong headerOffset, + ArchiveEncoding archiveEncoding + ) { - private readonly ZipCompressionMethod compression; - private readonly string fileName; - private readonly ArchiveEncoding archiveEncoding; + this.compression = compression; + this.fileName = fileName; + HeaderOffset = headerOffset; + this.archiveEncoding = archiveEncoding; + } - public ZipCentralDirectoryEntry( - ZipCompressionMethod compression, - string fileName, - ulong headerOffset, - ArchiveEncoding archiveEncoding - ) + internal DateTime? ModificationTime { get; set; } + internal string? Comment { get; set; } + internal uint Crc { get; set; } + internal ulong Compressed { get; set; } + internal ulong Decompressed { get; set; } + internal ushort Zip64HeaderOffset { get; set; } + internal ulong HeaderOffset { get; } + + internal uint Write(Stream outputStream) + { + var encodedFilename = archiveEncoding.Encode(fileName); + var encodedComment = archiveEncoding.Encode(Comment ?? string.Empty); + + var zip64_stream = Compressed >= uint.MaxValue || Decompressed >= uint.MaxValue; + var zip64 = zip64_stream || HeaderOffset >= uint.MaxValue; + var usedCompression = compression; + + var compressedvalue = zip64 ? uint.MaxValue : (uint)Compressed; + var decompressedvalue = zip64 ? uint.MaxValue : (uint)Decompressed; + var headeroffsetvalue = zip64 ? uint.MaxValue : (uint)HeaderOffset; + var extralength = zip64 ? (2 + 2 + 8 + 8 + 8 + 4) : 0; + var version = (byte)(zip64 ? 45 : 20); // Version 20 required for deflate/encryption + + var flags = Equals(archiveEncoding.GetEncoding(), Encoding.UTF8) + ? HeaderFlags.Efs + : HeaderFlags.None; + if (!outputStream.CanSeek) { - this.compression = compression; - this.fileName = fileName; - HeaderOffset = headerOffset; - this.archiveEncoding = archiveEncoding; + // Cannot use data descriptors with zip64: + // https://blogs.oracle.com/xuemingshen/entry/is_zipinput_outputstream_handling_of + + // We check that streams are not written too large in the ZipWritingStream, + // so this extra guard is not required, but kept to simplify changing the code + // once the zip64 post-data issue is resolved + if (!zip64_stream) + { + flags |= HeaderFlags.UsePostDataDescriptor; + } + + if (usedCompression == ZipCompressionMethod.LZMA) + { + flags |= HeaderFlags.Bit1; // eos marker + } } - internal DateTime? ModificationTime { get; set; } - internal string? Comment { get; set; } - internal uint Crc { get; set; } - internal ulong Compressed { get; set; } - internal ulong Decompressed { get; set; } - internal ushort Zip64HeaderOffset { get; set; } - internal ulong HeaderOffset { get; } - - internal uint Write(Stream outputStream) + // Support for zero byte files + if (Decompressed == 0 && Compressed == 0) { - byte[] encodedFilename = archiveEncoding.Encode(fileName); - byte[] encodedComment = archiveEncoding.Encode(Comment ?? string.Empty); + usedCompression = ZipCompressionMethod.None; + } - var zip64_stream = Compressed >= uint.MaxValue || Decompressed >= uint.MaxValue; - var zip64 = zip64_stream || HeaderOffset >= uint.MaxValue; - var usedCompression = compression; + Span intBuf = stackalloc byte[] { 80, 75, 1, 2, version, 0, version, 0 }; + //constant sig, then version made by, then version to extract + outputStream.Write(intBuf); - var compressedvalue = zip64 ? uint.MaxValue : (uint)Compressed; - var decompressedvalue = zip64 ? uint.MaxValue : (uint)Decompressed; - var headeroffsetvalue = zip64 ? uint.MaxValue : (uint)HeaderOffset; - var extralength = zip64 ? (2 + 2 + 8 + 8 + 8 + 4) : 0; - var version = (byte)(zip64 ? 45 : 20); // Version 20 required for deflate/encryption + BinaryPrimitives.WriteUInt16LittleEndian(intBuf, (ushort)flags); + outputStream.Write(intBuf.Slice(0, 2)); + BinaryPrimitives.WriteUInt16LittleEndian(intBuf, (ushort)usedCompression); + outputStream.Write(intBuf.Slice(0, 2)); // zipping method + BinaryPrimitives.WriteUInt32LittleEndian(intBuf, ModificationTime.DateTimeToDosTime()); + outputStream.Write(intBuf.Slice(0, 4)); - HeaderFlags flags = Equals(archiveEncoding.GetEncoding(), Encoding.UTF8) - ? HeaderFlags.Efs - : HeaderFlags.None; - if (!outputStream.CanSeek) - { - // Cannot use data descriptors with zip64: - // https://blogs.oracle.com/xuemingshen/entry/is_zipinput_outputstream_handling_of + // zipping date and time + BinaryPrimitives.WriteUInt32LittleEndian(intBuf, Crc); + outputStream.Write(intBuf.Slice(0, 4)); // file CRC + BinaryPrimitives.WriteUInt32LittleEndian(intBuf, compressedvalue); + outputStream.Write(intBuf.Slice(0, 4)); // compressed file size + BinaryPrimitives.WriteUInt32LittleEndian(intBuf, decompressedvalue); + outputStream.Write(intBuf.Slice(0, 4)); // uncompressed file size + BinaryPrimitives.WriteUInt16LittleEndian(intBuf, (ushort)encodedFilename.Length); + outputStream.Write(intBuf.Slice(0, 2)); // Filename in zip + BinaryPrimitives.WriteUInt16LittleEndian(intBuf, (ushort)extralength); + outputStream.Write(intBuf.Slice(0, 2)); // extra length + BinaryPrimitives.WriteUInt16LittleEndian(intBuf, (ushort)encodedComment.Length); + outputStream.Write(intBuf.Slice(0, 2)); - // We check that streams are not written too large in the ZipWritingStream, - // so this extra guard is not required, but kept to simplify changing the code - // once the zip64 post-data issue is resolved - if (!zip64_stream) - { - flags |= HeaderFlags.UsePostDataDescriptor; - } + BinaryPrimitives.WriteUInt16LittleEndian(intBuf, 0); + outputStream.Write(intBuf.Slice(0, 2)); // disk=0 - if (usedCompression == ZipCompressionMethod.LZMA) - { - flags |= HeaderFlags.Bit1; // eos marker - } - } + // Internal file attributes: + // Bit 0: apparent ASCII/ text file + // Bit 1: reserved + // Bit 2: control field records precede logical records + // Bits 3 - 16: unused + BinaryPrimitives.WriteUInt16LittleEndian(intBuf, 0); + outputStream.Write(intBuf.Slice(0, 2)); // file type: binary, Internal file attributes - // Support for zero byte files - if (Decompressed == 0 && Compressed == 0) - { - usedCompression = ZipCompressionMethod.None; - } + // External flags are host-dependent, this might match DOS + // Bit 0: Read-Only + // Bit 1: Hidden + // Bit 2: System + // Bit 3: Label + // Bit 4: Directory + // Bit 5: Archive + BinaryPrimitives.WriteUInt16LittleEndian(intBuf, 0); + outputStream.Write(intBuf.Slice(0, 2)); // External file attributes + BinaryPrimitives.WriteUInt16LittleEndian(intBuf, 0x8100); + outputStream.Write(intBuf.Slice(0, 2)); - Span intBuf = stackalloc byte[] { 80, 75, 1, 2, version, 0, version, 0 }; - //constant sig, then version made by, then version to extract + // External file attributes (normal/readable) + BinaryPrimitives.WriteUInt32LittleEndian(intBuf, headeroffsetvalue); + outputStream.Write(intBuf.Slice(0, 4)); // Offset of header + + outputStream.Write(encodedFilename, 0, encodedFilename.Length); + if (zip64) + { + BinaryPrimitives.WriteUInt16LittleEndian(intBuf, 0x0001); + outputStream.Write(intBuf.Slice(0, 2)); + BinaryPrimitives.WriteUInt16LittleEndian(intBuf, (ushort)(extralength - 4)); + outputStream.Write(intBuf.Slice(0, 2)); + + BinaryPrimitives.WriteUInt64LittleEndian(intBuf, Decompressed); outputStream.Write(intBuf); - - BinaryPrimitives.WriteUInt16LittleEndian(intBuf, (ushort)flags); - outputStream.Write(intBuf.Slice(0, 2)); - BinaryPrimitives.WriteUInt16LittleEndian(intBuf, (ushort)usedCompression); - outputStream.Write(intBuf.Slice(0, 2)); // zipping method - BinaryPrimitives.WriteUInt32LittleEndian(intBuf, ModificationTime.DateTimeToDosTime()); - outputStream.Write(intBuf.Slice(0, 4)); - - // zipping date and time - BinaryPrimitives.WriteUInt32LittleEndian(intBuf, Crc); - outputStream.Write(intBuf.Slice(0, 4)); // file CRC - BinaryPrimitives.WriteUInt32LittleEndian(intBuf, compressedvalue); - outputStream.Write(intBuf.Slice(0, 4)); // compressed file size - BinaryPrimitives.WriteUInt32LittleEndian(intBuf, decompressedvalue); - outputStream.Write(intBuf.Slice(0, 4)); // uncompressed file size - BinaryPrimitives.WriteUInt16LittleEndian(intBuf, (ushort)encodedFilename.Length); - outputStream.Write(intBuf.Slice(0, 2)); // Filename in zip - BinaryPrimitives.WriteUInt16LittleEndian(intBuf, (ushort)extralength); - outputStream.Write(intBuf.Slice(0, 2)); // extra length - BinaryPrimitives.WriteUInt16LittleEndian(intBuf, (ushort)encodedComment.Length); - outputStream.Write(intBuf.Slice(0, 2)); - - BinaryPrimitives.WriteUInt16LittleEndian(intBuf, 0); - outputStream.Write(intBuf.Slice(0, 2)); // disk=0 - - // Internal file attributes: - // Bit 0: apparent ASCII/ text file - // Bit 1: reserved - // Bit 2: control field records precede logical records - // Bits 3 - 16: unused - BinaryPrimitives.WriteUInt16LittleEndian(intBuf, 0); - outputStream.Write(intBuf.Slice(0, 2)); // file type: binary, Internal file attributes - - // External flags are host-dependent, this might match DOS - // Bit 0: Read-Only - // Bit 1: Hidden - // Bit 2: System - // Bit 3: Label - // Bit 4: Directory - // Bit 5: Archive - BinaryPrimitives.WriteUInt16LittleEndian(intBuf, 0); - outputStream.Write(intBuf.Slice(0, 2)); // External file attributes - BinaryPrimitives.WriteUInt16LittleEndian(intBuf, 0x8100); - outputStream.Write(intBuf.Slice(0, 2)); - - // External file attributes (normal/readable) - BinaryPrimitives.WriteUInt32LittleEndian(intBuf, headeroffsetvalue); - outputStream.Write(intBuf.Slice(0, 4)); // Offset of header - - outputStream.Write(encodedFilename, 0, encodedFilename.Length); - if (zip64) - { - BinaryPrimitives.WriteUInt16LittleEndian(intBuf, 0x0001); - outputStream.Write(intBuf.Slice(0, 2)); - BinaryPrimitives.WriteUInt16LittleEndian(intBuf, (ushort)(extralength - 4)); - outputStream.Write(intBuf.Slice(0, 2)); - - BinaryPrimitives.WriteUInt64LittleEndian(intBuf, Decompressed); - outputStream.Write(intBuf); - BinaryPrimitives.WriteUInt64LittleEndian(intBuf, Compressed); - outputStream.Write(intBuf); - BinaryPrimitives.WriteUInt64LittleEndian(intBuf, HeaderOffset); - outputStream.Write(intBuf); - BinaryPrimitives.WriteUInt32LittleEndian(intBuf, 0); - outputStream.Write(intBuf.Slice(0, 4)); // VolumeNumber = 0 - } - - outputStream.Write(encodedComment, 0, encodedComment.Length); - - return (uint)( - 8 - + 2 - + 2 - + 4 - + 4 - + 4 - + 4 - + 2 - + 2 - + 2 - + 2 - + 2 - + 2 - + 2 - + 4 - + encodedFilename.Length - + extralength - + encodedComment.Length - ); + BinaryPrimitives.WriteUInt64LittleEndian(intBuf, Compressed); + outputStream.Write(intBuf); + BinaryPrimitives.WriteUInt64LittleEndian(intBuf, HeaderOffset); + outputStream.Write(intBuf); + BinaryPrimitives.WriteUInt32LittleEndian(intBuf, 0); + outputStream.Write(intBuf.Slice(0, 4)); // VolumeNumber = 0 } + + outputStream.Write(encodedComment, 0, encodedComment.Length); + + return (uint)( + 8 + + 2 + + 2 + + 4 + + 4 + + 4 + + 4 + + 2 + + 2 + + 2 + + 2 + + 2 + + 2 + + 2 + + 4 + + encodedFilename.Length + + extralength + + encodedComment.Length + ); } } diff --git a/src/SharpCompress/Writers/Zip/ZipWriter.cs b/src/SharpCompress/Writers/Zip/ZipWriter.cs index fb04e7a4..afc34800 100644 --- a/src/SharpCompress/Writers/Zip/ZipWriter.cs +++ b/src/SharpCompress/Writers/Zip/ZipWriter.cs @@ -13,595 +13,592 @@ using SharpCompress.Compressors.LZMA; using SharpCompress.Compressors.PPMd; using SharpCompress.IO; -namespace SharpCompress.Writers.Zip +namespace SharpCompress.Writers.Zip; + +public class ZipWriter : AbstractWriter { - public class ZipWriter : AbstractWriter + private readonly CompressionType compressionType; + private readonly CompressionLevel compressionLevel; + private readonly List entries = + new List(); + private readonly string zipComment; + private long streamPosition; + private PpmdProperties? ppmdProps; + private readonly bool isZip64; + + public ZipWriter(Stream destination, ZipWriterOptions zipWriterOptions) + : base(ArchiveType.Zip, zipWriterOptions) { - private readonly CompressionType compressionType; - private readonly CompressionLevel compressionLevel; - private readonly List entries = - new List(); - private readonly string zipComment; - private long streamPosition; - private PpmdProperties? ppmdProps; - private readonly bool isZip64; - - public ZipWriter(Stream destination, ZipWriterOptions zipWriterOptions) - : base(ArchiveType.Zip, zipWriterOptions) + zipComment = zipWriterOptions.ArchiveComment ?? string.Empty; + isZip64 = zipWriterOptions.UseZip64; + if (destination.CanSeek) { - zipComment = zipWriterOptions.ArchiveComment ?? string.Empty; - isZip64 = zipWriterOptions.UseZip64; - if (destination.CanSeek) + streamPosition = destination.Position; + } + + compressionType = zipWriterOptions.CompressionType; + compressionLevel = zipWriterOptions.DeflateCompressionLevel; + + if (WriterOptions.LeaveStreamOpen) + { + destination = NonDisposingStream.Create(destination); + } + InitalizeStream(destination); + } + + private PpmdProperties PpmdProperties + { + get { return ppmdProps ??= new PpmdProperties(); } + } + + protected override void Dispose(bool isDisposing) + { + if (isDisposing) + { + ulong size = 0; + foreach (var entry in entries) { - streamPosition = destination.Position; + size += entry.Write(OutputStream); } + WriteEndRecord(size); + } + base.Dispose(isDisposing); + } - compressionType = zipWriterOptions.CompressionType; - compressionLevel = zipWriterOptions.DeflateCompressionLevel; - - if (WriterOptions.LeaveStreamOpen) + private static ZipCompressionMethod ToZipCompressionMethod(CompressionType compressionType) + { + switch (compressionType) + { + case CompressionType.None: { - destination = NonDisposingStream.Create(destination); + return ZipCompressionMethod.None; } - InitalizeStream(destination); - } - - private PpmdProperties PpmdProperties - { - get { return ppmdProps ??= new PpmdProperties(); } - } - - protected override void Dispose(bool isDisposing) - { - if (isDisposing) + case CompressionType.Deflate: { - ulong size = 0; - foreach (ZipCentralDirectoryEntry entry in entries) - { - size += entry.Write(OutputStream); - } - WriteEndRecord(size); + return ZipCompressionMethod.Deflate; } - base.Dispose(isDisposing); - } - - private static ZipCompressionMethod ToZipCompressionMethod(CompressionType compressionType) - { - switch (compressionType) + case CompressionType.BZip2: { - case CompressionType.None: - { - return ZipCompressionMethod.None; - } - case CompressionType.Deflate: - { - return ZipCompressionMethod.Deflate; - } - case CompressionType.BZip2: - { - return ZipCompressionMethod.BZip2; - } - case CompressionType.LZMA: - { - return ZipCompressionMethod.LZMA; - } - case CompressionType.PPMd: - { - return ZipCompressionMethod.PPMd; - } - default: - throw new InvalidFormatException( - "Invalid compression method: " + compressionType - ); + return ZipCompressionMethod.BZip2; } - } - - public override void Write(string entryPath, Stream source, DateTime? modificationTime) - { - Write( - entryPath, - source, - new ZipWriterEntryOptions() { ModificationDateTime = modificationTime } - ); - } - - public void Write( - string entryPath, - Stream source, - ZipWriterEntryOptions zipWriterEntryOptions - ) - { - using (Stream output = WriteToStream(entryPath, zipWriterEntryOptions)) + case CompressionType.LZMA: { - source.TransferTo(output); + return ZipCompressionMethod.LZMA; } - } - - public Stream WriteToStream(string entryPath, ZipWriterEntryOptions options) - { - var compression = ToZipCompressionMethod(options.CompressionType ?? compressionType); - - entryPath = NormalizeFilename(entryPath); - options.ModificationDateTime ??= DateTime.Now; - options.EntryComment ??= string.Empty; - var entry = new ZipCentralDirectoryEntry( - compression, - entryPath, - (ulong)streamPosition, - WriterOptions.ArchiveEncoding - ) + case CompressionType.PPMd: { - Comment = options.EntryComment, - ModificationTime = options.ModificationDateTime - }; - - // Use the archive default setting for zip64 and allow overrides - var useZip64 = isZip64; - if (options.EnableZip64.HasValue) - { - useZip64 = options.EnableZip64.Value; + return ZipCompressionMethod.PPMd; } - - var headersize = (uint)WriteHeader(entryPath, options, entry, useZip64); - streamPosition += headersize; - return new ZipWritingStream( - this, - OutputStream, - entry, - compression, - options.DeflateCompressionLevel ?? compressionLevel - ); - } - - private string NormalizeFilename(string filename) - { - filename = filename.Replace('\\', '/'); - - int pos = filename.IndexOf(':'); - if (pos >= 0) - { - filename = filename.Remove(0, pos + 1); - } - - return filename.Trim('/'); - } - - private int WriteHeader( - string filename, - ZipWriterEntryOptions zipWriterEntryOptions, - ZipCentralDirectoryEntry entry, - bool useZip64 - ) - { - // We err on the side of caution until the zip specification clarifies how to support this - if (!OutputStream.CanSeek && useZip64) - { - throw new NotSupportedException( - "Zip64 extensions are not supported on non-seekable streams" + default: + throw new InvalidFormatException( + "Invalid compression method: " + compressionType ); - } + } + } - var explicitZipCompressionInfo = ToZipCompressionMethod( - zipWriterEntryOptions.CompressionType ?? compressionType + public override void Write(string entryPath, Stream source, DateTime? modificationTime) + { + Write( + entryPath, + source, + new ZipWriterEntryOptions() { ModificationDateTime = modificationTime } + ); + } + + public void Write( + string entryPath, + Stream source, + ZipWriterEntryOptions zipWriterEntryOptions + ) + { + using var output = WriteToStream(entryPath, zipWriterEntryOptions); + source.TransferTo(output); + } + + public Stream WriteToStream(string entryPath, ZipWriterEntryOptions options) + { + var compression = ToZipCompressionMethod(options.CompressionType ?? compressionType); + + entryPath = NormalizeFilename(entryPath); + options.ModificationDateTime ??= DateTime.Now; + options.EntryComment ??= string.Empty; + var entry = new ZipCentralDirectoryEntry( + compression, + entryPath, + (ulong)streamPosition, + WriterOptions.ArchiveEncoding + ) + { + Comment = options.EntryComment, + ModificationTime = options.ModificationDateTime + }; + + // Use the archive default setting for zip64 and allow overrides + var useZip64 = isZip64; + if (options.EnableZip64.HasValue) + { + useZip64 = options.EnableZip64.Value; + } + + var headersize = (uint)WriteHeader(entryPath, options, entry, useZip64); + streamPosition += headersize; + return new ZipWritingStream( + this, + OutputStream, + entry, + compression, + options.DeflateCompressionLevel ?? compressionLevel + ); + } + + private string NormalizeFilename(string filename) + { + filename = filename.Replace('\\', '/'); + + var pos = filename.IndexOf(':'); + if (pos >= 0) + { + filename = filename.Remove(0, pos + 1); + } + + return filename.Trim('/'); + } + + private int WriteHeader( + string filename, + ZipWriterEntryOptions zipWriterEntryOptions, + ZipCentralDirectoryEntry entry, + bool useZip64 + ) + { + // We err on the side of caution until the zip specification clarifies how to support this + if (!OutputStream.CanSeek && useZip64) + { + throw new NotSupportedException( + "Zip64 extensions are not supported on non-seekable streams" ); - byte[] encodedFilename = WriterOptions.ArchiveEncoding.Encode(filename); + } - Span intBuf = stackalloc byte[4]; - BinaryPrimitives.WriteUInt32LittleEndian(intBuf, ZipHeaderFactory.ENTRY_HEADER_BYTES); - OutputStream.Write(intBuf); - if (explicitZipCompressionInfo == ZipCompressionMethod.Deflate) + var explicitZipCompressionInfo = ToZipCompressionMethod( + zipWriterEntryOptions.CompressionType ?? compressionType + ); + var encodedFilename = WriterOptions.ArchiveEncoding.Encode(filename); + + Span intBuf = stackalloc byte[4]; + BinaryPrimitives.WriteUInt32LittleEndian(intBuf, ZipHeaderFactory.ENTRY_HEADER_BYTES); + OutputStream.Write(intBuf); + if (explicitZipCompressionInfo == ZipCompressionMethod.Deflate) + { + if (OutputStream.CanSeek && useZip64) { - if (OutputStream.CanSeek && useZip64) - { - OutputStream.Write(stackalloc byte[] { 45, 0 }); //smallest allowed version for zip64 - } - else - { - OutputStream.Write(stackalloc byte[] { 20, 0 }); //older version which is more compatible - } + OutputStream.Write(stackalloc byte[] { 45, 0 }); //smallest allowed version for zip64 } else { - OutputStream.Write(stackalloc byte[] { 63, 0 }); //version says we used PPMd or LZMA + OutputStream.Write(stackalloc byte[] { 20, 0 }); //older version which is more compatible } - HeaderFlags flags = Equals(WriterOptions.ArchiveEncoding.GetEncoding(), Encoding.UTF8) - ? HeaderFlags.Efs - : 0; - if (!OutputStream.CanSeek) + } + else + { + OutputStream.Write(stackalloc byte[] { 63, 0 }); //version says we used PPMd or LZMA + } + var flags = Equals(WriterOptions.ArchiveEncoding.GetEncoding(), Encoding.UTF8) + ? HeaderFlags.Efs + : 0; + if (!OutputStream.CanSeek) + { + flags |= HeaderFlags.UsePostDataDescriptor; + + if (explicitZipCompressionInfo == ZipCompressionMethod.LZMA) { - flags |= HeaderFlags.UsePostDataDescriptor; - - if (explicitZipCompressionInfo == ZipCompressionMethod.LZMA) - { - flags |= HeaderFlags.Bit1; // eos marker - } + flags |= HeaderFlags.Bit1; // eos marker } + } - BinaryPrimitives.WriteUInt16LittleEndian(intBuf, (ushort)flags); - OutputStream.Write(intBuf.Slice(0, 2)); - BinaryPrimitives.WriteUInt16LittleEndian(intBuf, (ushort)explicitZipCompressionInfo); - OutputStream.Write(intBuf.Slice(0, 2)); // zipping method - BinaryPrimitives.WriteUInt32LittleEndian( - intBuf, - zipWriterEntryOptions.ModificationDateTime.DateTimeToDosTime() + BinaryPrimitives.WriteUInt16LittleEndian(intBuf, (ushort)flags); + OutputStream.Write(intBuf.Slice(0, 2)); + BinaryPrimitives.WriteUInt16LittleEndian(intBuf, (ushort)explicitZipCompressionInfo); + OutputStream.Write(intBuf.Slice(0, 2)); // zipping method + BinaryPrimitives.WriteUInt32LittleEndian( + intBuf, + zipWriterEntryOptions.ModificationDateTime.DateTimeToDosTime() + ); + OutputStream.Write(intBuf); + + // zipping date and time + OutputStream.Write(stackalloc byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }); + + // unused CRC, un/compressed size, updated later + BinaryPrimitives.WriteUInt16LittleEndian(intBuf, (ushort)encodedFilename.Length); + OutputStream.Write(intBuf.Slice(0, 2)); // filename length + + var extralength = 0; + if (OutputStream.CanSeek && useZip64) + { + extralength = 2 + 2 + 8 + 8; + } + + BinaryPrimitives.WriteUInt16LittleEndian(intBuf, (ushort)extralength); + OutputStream.Write(intBuf.Slice(0, 2)); // extra length + OutputStream.Write(encodedFilename, 0, encodedFilename.Length); + + if (extralength != 0) + { + OutputStream.Write(new byte[extralength], 0, extralength); // reserve space for zip64 data + entry.Zip64HeaderOffset = (ushort)( + 6 + 2 + 2 + 4 + 12 + 2 + 2 + encodedFilename.Length ); - OutputStream.Write(intBuf); - - // zipping date and time - OutputStream.Write(stackalloc byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }); - - // unused CRC, un/compressed size, updated later - BinaryPrimitives.WriteUInt16LittleEndian(intBuf, (ushort)encodedFilename.Length); - OutputStream.Write(intBuf.Slice(0, 2)); // filename length - - var extralength = 0; - if (OutputStream.CanSeek && useZip64) - { - extralength = 2 + 2 + 8 + 8; - } - - BinaryPrimitives.WriteUInt16LittleEndian(intBuf, (ushort)extralength); - OutputStream.Write(intBuf.Slice(0, 2)); // extra length - OutputStream.Write(encodedFilename, 0, encodedFilename.Length); - - if (extralength != 0) - { - OutputStream.Write(new byte[extralength], 0, extralength); // reserve space for zip64 data - entry.Zip64HeaderOffset = (ushort)( - 6 + 2 + 2 + 4 + 12 + 2 + 2 + encodedFilename.Length - ); - } - - return 6 + 2 + 2 + 4 + 12 + 2 + 2 + encodedFilename.Length + extralength; } - private void WriteFooter(uint crc, uint compressed, uint uncompressed) + return 6 + 2 + 2 + 4 + 12 + 2 + 2 + encodedFilename.Length + extralength; + } + + private void WriteFooter(uint crc, uint compressed, uint uncompressed) + { + Span intBuf = stackalloc byte[4]; + BinaryPrimitives.WriteUInt32LittleEndian(intBuf, crc); + OutputStream.Write(intBuf); + BinaryPrimitives.WriteUInt32LittleEndian(intBuf, compressed); + OutputStream.Write(intBuf); + BinaryPrimitives.WriteUInt32LittleEndian(intBuf, uncompressed); + OutputStream.Write(intBuf); + } + + private void WriteEndRecord(ulong size) + { + var zip64EndOfCentralDirectoryNeeded = + entries.Count > ushort.MaxValue + || streamPosition >= uint.MaxValue + || size >= uint.MaxValue; + + var sizevalue = size >= uint.MaxValue ? uint.MaxValue : (uint)size; + var streampositionvalue = + streamPosition >= uint.MaxValue ? uint.MaxValue : (uint)streamPosition; + + Span intBuf = stackalloc byte[8]; + if (zip64EndOfCentralDirectoryNeeded) { - Span intBuf = stackalloc byte[4]; - BinaryPrimitives.WriteUInt32LittleEndian(intBuf, crc); - OutputStream.Write(intBuf); - BinaryPrimitives.WriteUInt32LittleEndian(intBuf, compressed); - OutputStream.Write(intBuf); - BinaryPrimitives.WriteUInt32LittleEndian(intBuf, uncompressed); - OutputStream.Write(intBuf); + var recordlen = 2 + 2 + 4 + 4 + 8 + 8 + 8 + 8; + + // Write zip64 end of central directory record + OutputStream.Write(stackalloc byte[] { 80, 75, 6, 6 }); + + BinaryPrimitives.WriteUInt64LittleEndian(intBuf, (ulong)recordlen); + OutputStream.Write(intBuf); // Size of zip64 end of central directory record + BinaryPrimitives.WriteUInt16LittleEndian(intBuf, 45); + OutputStream.Write(intBuf.Slice(0, 2)); // Made by + BinaryPrimitives.WriteUInt16LittleEndian(intBuf, 45); + OutputStream.Write(intBuf.Slice(0, 2)); // Version needed + + BinaryPrimitives.WriteUInt32LittleEndian(intBuf, 0); + OutputStream.Write(intBuf.Slice(0, 4)); // Disk number + OutputStream.Write(intBuf.Slice(0, 4)); // Central dir disk + + // TODO: entries.Count is int, so max 2^31 files + BinaryPrimitives.WriteUInt64LittleEndian(intBuf, (ulong)entries.Count); + OutputStream.Write(intBuf); // Entries in this disk + OutputStream.Write(intBuf); // Total entries + BinaryPrimitives.WriteUInt64LittleEndian(intBuf, size); + OutputStream.Write(intBuf); // Central Directory size + BinaryPrimitives.WriteUInt64LittleEndian(intBuf, (ulong)streamPosition); + OutputStream.Write(intBuf); // Disk offset + + // Write zip64 end of central directory locator + OutputStream.Write(stackalloc byte[] { 80, 75, 6, 7 }); + + BinaryPrimitives.WriteUInt32LittleEndian(intBuf, 0); + OutputStream.Write(intBuf.Slice(0, 4)); // Entry disk + BinaryPrimitives.WriteUInt64LittleEndian(intBuf, (ulong)streamPosition + size); + OutputStream.Write(intBuf); // Offset to the zip64 central directory + BinaryPrimitives.WriteUInt32LittleEndian(intBuf, 1); + OutputStream.Write(intBuf.Slice(0, 4)); // Number of disks + + streamPosition += 4 + 8 + recordlen + (4 + 4 + 8 + 4); } - private void WriteEndRecord(ulong size) + // Write normal end of central directory record + OutputStream.Write(stackalloc byte[] { 80, 75, 5, 6, 0, 0, 0, 0 }); + BinaryPrimitives.WriteUInt16LittleEndian(intBuf, (ushort)entries.Count); + OutputStream.Write(intBuf.Slice(0, 2)); + OutputStream.Write(intBuf.Slice(0, 2)); + BinaryPrimitives.WriteUInt32LittleEndian(intBuf, sizevalue); + OutputStream.Write(intBuf.Slice(0, 4)); + BinaryPrimitives.WriteUInt32LittleEndian(intBuf, streampositionvalue); + OutputStream.Write(intBuf.Slice(0, 4)); + var encodedComment = WriterOptions.ArchiveEncoding.Encode(zipComment); + BinaryPrimitives.WriteUInt16LittleEndian(intBuf, (ushort)encodedComment.Length); + OutputStream.Write(intBuf.Slice(0, 2)); + OutputStream.Write(encodedComment, 0, encodedComment.Length); + } + + #region Nested type: ZipWritingStream + + internal class ZipWritingStream : Stream + { + private readonly CRC32 crc = new CRC32(); + private readonly ZipCentralDirectoryEntry entry; + private readonly Stream originalStream; + private readonly Stream writeStream; + private readonly ZipWriter writer; + private readonly ZipCompressionMethod zipCompressionMethod; + private readonly CompressionLevel compressionLevel; + private CountingWritableSubStream? counting; + private ulong decompressed; + + // Flag to prevent throwing exceptions on Dispose + private bool limitsExceeded; + private bool isDisposed; + + internal ZipWritingStream( + ZipWriter writer, + Stream originalStream, + ZipCentralDirectoryEntry entry, + ZipCompressionMethod zipCompressionMethod, + CompressionLevel compressionLevel + ) { - var zip64EndOfCentralDirectoryNeeded = - entries.Count > ushort.MaxValue - || streamPosition >= uint.MaxValue - || size >= uint.MaxValue; - - var sizevalue = size >= uint.MaxValue ? uint.MaxValue : (uint)size; - var streampositionvalue = - streamPosition >= uint.MaxValue ? uint.MaxValue : (uint)streamPosition; - - Span intBuf = stackalloc byte[8]; - if (zip64EndOfCentralDirectoryNeeded) - { - var recordlen = 2 + 2 + 4 + 4 + 8 + 8 + 8 + 8; - - // Write zip64 end of central directory record - OutputStream.Write(stackalloc byte[] { 80, 75, 6, 6 }); - - BinaryPrimitives.WriteUInt64LittleEndian(intBuf, (ulong)recordlen); - OutputStream.Write(intBuf); // Size of zip64 end of central directory record - BinaryPrimitives.WriteUInt16LittleEndian(intBuf, 45); - OutputStream.Write(intBuf.Slice(0, 2)); // Made by - BinaryPrimitives.WriteUInt16LittleEndian(intBuf, 45); - OutputStream.Write(intBuf.Slice(0, 2)); // Version needed - - BinaryPrimitives.WriteUInt32LittleEndian(intBuf, 0); - OutputStream.Write(intBuf.Slice(0, 4)); // Disk number - OutputStream.Write(intBuf.Slice(0, 4)); // Central dir disk - - // TODO: entries.Count is int, so max 2^31 files - BinaryPrimitives.WriteUInt64LittleEndian(intBuf, (ulong)entries.Count); - OutputStream.Write(intBuf); // Entries in this disk - OutputStream.Write(intBuf); // Total entries - BinaryPrimitives.WriteUInt64LittleEndian(intBuf, size); - OutputStream.Write(intBuf); // Central Directory size - BinaryPrimitives.WriteUInt64LittleEndian(intBuf, (ulong)streamPosition); - OutputStream.Write(intBuf); // Disk offset - - // Write zip64 end of central directory locator - OutputStream.Write(stackalloc byte[] { 80, 75, 6, 7 }); - - BinaryPrimitives.WriteUInt32LittleEndian(intBuf, 0); - OutputStream.Write(intBuf.Slice(0, 4)); // Entry disk - BinaryPrimitives.WriteUInt64LittleEndian(intBuf, (ulong)streamPosition + size); - OutputStream.Write(intBuf); // Offset to the zip64 central directory - BinaryPrimitives.WriteUInt32LittleEndian(intBuf, 1); - OutputStream.Write(intBuf.Slice(0, 4)); // Number of disks - - streamPosition += 4 + 8 + recordlen + (4 + 4 + 8 + 4); - } - - // Write normal end of central directory record - OutputStream.Write(stackalloc byte[] { 80, 75, 5, 6, 0, 0, 0, 0 }); - BinaryPrimitives.WriteUInt16LittleEndian(intBuf, (ushort)entries.Count); - OutputStream.Write(intBuf.Slice(0, 2)); - OutputStream.Write(intBuf.Slice(0, 2)); - BinaryPrimitives.WriteUInt32LittleEndian(intBuf, sizevalue); - OutputStream.Write(intBuf.Slice(0, 4)); - BinaryPrimitives.WriteUInt32LittleEndian(intBuf, streampositionvalue); - OutputStream.Write(intBuf.Slice(0, 4)); - byte[] encodedComment = WriterOptions.ArchiveEncoding.Encode(zipComment); - BinaryPrimitives.WriteUInt16LittleEndian(intBuf, (ushort)encodedComment.Length); - OutputStream.Write(intBuf.Slice(0, 2)); - OutputStream.Write(encodedComment, 0, encodedComment.Length); + this.writer = writer; + this.originalStream = originalStream; + this.writer = writer; + this.entry = entry; + this.zipCompressionMethod = zipCompressionMethod; + this.compressionLevel = compressionLevel; + writeStream = GetWriteStream(originalStream); } - #region Nested type: ZipWritingStream + public override bool CanRead => false; - internal class ZipWritingStream : Stream + public override bool CanSeek => false; + + public override bool CanWrite => true; + + public override long Length => throw new NotSupportedException(); + + public override long Position { - private readonly CRC32 crc = new CRC32(); - private readonly ZipCentralDirectoryEntry entry; - private readonly Stream originalStream; - private readonly Stream writeStream; - private readonly ZipWriter writer; - private readonly ZipCompressionMethod zipCompressionMethod; - private readonly CompressionLevel compressionLevel; - private CountingWritableSubStream? counting; - private ulong decompressed; + get => throw new NotSupportedException(); + set => throw new NotSupportedException(); + } - // Flag to prevent throwing exceptions on Dispose - private bool limitsExceeded; - private bool isDisposed; - - internal ZipWritingStream( - ZipWriter writer, - Stream originalStream, - ZipCentralDirectoryEntry entry, - ZipCompressionMethod zipCompressionMethod, - CompressionLevel compressionLevel - ) + private Stream GetWriteStream(Stream writeStream) + { + counting = new CountingWritableSubStream(writeStream); + Stream output = counting; + switch (zipCompressionMethod) { - this.writer = writer; - this.originalStream = originalStream; - this.writer = writer; - this.entry = entry; - this.zipCompressionMethod = zipCompressionMethod; - this.compressionLevel = compressionLevel; - writeStream = GetWriteStream(originalStream); - } - - public override bool CanRead => false; - - public override bool CanSeek => false; - - public override bool CanWrite => true; - - public override long Length => throw new NotSupportedException(); - - public override long Position - { - get => throw new NotSupportedException(); - set => throw new NotSupportedException(); - } - - private Stream GetWriteStream(Stream writeStream) - { - counting = new CountingWritableSubStream(writeStream); - Stream output = counting; - switch (zipCompressionMethod) + case ZipCompressionMethod.None: { - case ZipCompressionMethod.None: - { - return output; - } - case ZipCompressionMethod.Deflate: - { - return new DeflateStream( - counting, - CompressionMode.Compress, - compressionLevel - ); - } - case ZipCompressionMethod.BZip2: - { - return new BZip2Stream(counting, CompressionMode.Compress, false); - } - case ZipCompressionMethod.LZMA: - { - counting.WriteByte(9); - counting.WriteByte(20); - counting.WriteByte(5); - counting.WriteByte(0); + return output; + } + case ZipCompressionMethod.Deflate: + { + return new DeflateStream( + counting, + CompressionMode.Compress, + compressionLevel + ); + } + case ZipCompressionMethod.BZip2: + { + return new BZip2Stream(counting, CompressionMode.Compress, false); + } + case ZipCompressionMethod.LZMA: + { + counting.WriteByte(9); + counting.WriteByte(20); + counting.WriteByte(5); + counting.WriteByte(0); - LzmaStream lzmaStream = new LzmaStream( - new LzmaEncoderProperties(!originalStream.CanSeek), - false, - counting - ); - counting.Write(lzmaStream.Properties, 0, lzmaStream.Properties.Length); - return lzmaStream; - } - case ZipCompressionMethod.PPMd: - { - counting.Write(writer.PpmdProperties.Properties, 0, 2); - return new PpmdStream(writer.PpmdProperties, counting, true); - } - default: - { - throw new NotSupportedException( - "CompressionMethod: " + zipCompressionMethod - ); - } + var lzmaStream = new LzmaStream( + new LzmaEncoderProperties(!originalStream.CanSeek), + false, + counting + ); + counting.Write(lzmaStream.Properties, 0, lzmaStream.Properties.Length); + return lzmaStream; + } + case ZipCompressionMethod.PPMd: + { + counting.Write(writer.PpmdProperties.Properties, 0, 2); + return new PpmdStream(writer.PpmdProperties, counting, true); + } + default: + { + throw new NotSupportedException( + "CompressionMethod: " + zipCompressionMethod + ); } } + } - protected override void Dispose(bool disposing) + protected override void Dispose(bool disposing) + { + if (isDisposed) { - if (isDisposed) + return; + } + + isDisposed = true; + + base.Dispose(disposing); + if (disposing) + { + writeStream.Dispose(); + + if (limitsExceeded) { + // We have written invalid data into the archive, + // so we destroy it now, instead of allowing the user to continue + // with a defunct archive + originalStream.Dispose(); return; } - isDisposed = true; + entry.Crc = (uint)crc.Crc32Result; + entry.Compressed = counting!.Count; + entry.Decompressed = decompressed; - base.Dispose(disposing); - if (disposing) + var zip64 = + entry.Compressed >= uint.MaxValue || entry.Decompressed >= uint.MaxValue; + var compressedvalue = zip64 ? uint.MaxValue : (uint)counting.Count; + var decompressedvalue = zip64 ? uint.MaxValue : (uint)entry.Decompressed; + + if (originalStream.CanSeek) { - writeStream.Dispose(); + originalStream.Position = (long)(entry.HeaderOffset + 6); + originalStream.WriteByte(0); - if (limitsExceeded) + if (counting.Count == 0 && entry.Decompressed == 0) { - // We have written invalid data into the archive, - // so we destroy it now, instead of allowing the user to continue - // with a defunct archive - originalStream.Dispose(); - return; - } - - entry.Crc = (uint)crc.Crc32Result; - entry.Compressed = counting!.Count; - entry.Decompressed = decompressed; - - var zip64 = - entry.Compressed >= uint.MaxValue || entry.Decompressed >= uint.MaxValue; - var compressedvalue = zip64 ? uint.MaxValue : (uint)counting.Count; - var decompressedvalue = zip64 ? uint.MaxValue : (uint)entry.Decompressed; - - if (originalStream.CanSeek) - { - originalStream.Position = (long)(entry.HeaderOffset + 6); + // set compression to STORED for zero byte files (no compression data) + originalStream.Position = (long)(entry.HeaderOffset + 8); + originalStream.WriteByte(0); originalStream.WriteByte(0); - - if (counting.Count == 0 && entry.Decompressed == 0) - { - // set compression to STORED for zero byte files (no compression data) - originalStream.Position = (long)(entry.HeaderOffset + 8); - originalStream.WriteByte(0); - originalStream.WriteByte(0); - } - - originalStream.Position = (long)(entry.HeaderOffset + 14); - - writer.WriteFooter(entry.Crc, compressedvalue, decompressedvalue); - - // Ideally, we should not throw from Dispose() - // We should not get here as the Write call checks the limits - if (zip64 && entry.Zip64HeaderOffset == 0) - { - throw new NotSupportedException( - "Attempted to write a stream that is larger than 4GiB without setting the zip64 option" - ); - } - - // If we have pre-allocated space for zip64 data, - // fill it out, even if it is not required - if (entry.Zip64HeaderOffset != 0) - { - originalStream.Position = (long)( - entry.HeaderOffset + entry.Zip64HeaderOffset - ); - Span intBuf = stackalloc byte[8]; - BinaryPrimitives.WriteUInt16LittleEndian(intBuf, 0x0001); - originalStream.Write(intBuf.Slice(0, 2)); - BinaryPrimitives.WriteUInt16LittleEndian(intBuf, 8 + 8); - originalStream.Write(intBuf.Slice(0, 2)); - - BinaryPrimitives.WriteUInt64LittleEndian(intBuf, entry.Decompressed); - originalStream.Write(intBuf); - BinaryPrimitives.WriteUInt64LittleEndian(intBuf, entry.Compressed); - originalStream.Write(intBuf); - } - - originalStream.Position = writer.streamPosition + (long)entry.Compressed; - writer.streamPosition += (long)entry.Compressed; } - else + + originalStream.Position = (long)(entry.HeaderOffset + 14); + + writer.WriteFooter(entry.Crc, compressedvalue, decompressedvalue); + + // Ideally, we should not throw from Dispose() + // We should not get here as the Write call checks the limits + if (zip64 && entry.Zip64HeaderOffset == 0) { - // We have a streaming archive, so we should add a post-data-descriptor, - // but we cannot as it does not hold the zip64 values - // Throwing an exception until the zip specification is clarified - - // Ideally, we should not throw from Dispose() - // We should not get here as the Write call checks the limits - if (zip64) - { - throw new NotSupportedException( - "Streams larger than 4GiB are not supported for non-seekable streams" - ); - } - - Span intBuf = stackalloc byte[4]; - BinaryPrimitives.WriteUInt32LittleEndian( - intBuf, - ZipHeaderFactory.POST_DATA_DESCRIPTOR + throw new NotSupportedException( + "Attempted to write a stream that is larger than 4GiB without setting the zip64 option" ); + } + + // If we have pre-allocated space for zip64 data, + // fill it out, even if it is not required + if (entry.Zip64HeaderOffset != 0) + { + originalStream.Position = (long)( + entry.HeaderOffset + entry.Zip64HeaderOffset + ); + Span intBuf = stackalloc byte[8]; + BinaryPrimitives.WriteUInt16LittleEndian(intBuf, 0x0001); + originalStream.Write(intBuf.Slice(0, 2)); + BinaryPrimitives.WriteUInt16LittleEndian(intBuf, 8 + 8); + originalStream.Write(intBuf.Slice(0, 2)); + + BinaryPrimitives.WriteUInt64LittleEndian(intBuf, entry.Decompressed); + originalStream.Write(intBuf); + BinaryPrimitives.WriteUInt64LittleEndian(intBuf, entry.Compressed); originalStream.Write(intBuf); - writer.WriteFooter(entry.Crc, compressedvalue, decompressedvalue); - writer.streamPosition += (long)entry.Compressed + 16; } - writer.entries.Add(entry); + + originalStream.Position = writer.streamPosition + (long)entry.Compressed; + writer.streamPosition += (long)entry.Compressed; } - } - - public override void Flush() - { - writeStream.Flush(); - } - - public override int Read(byte[] buffer, int offset, int count) - { - throw new NotSupportedException(); - } - - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } - - public override void SetLength(long value) - { - throw new NotSupportedException(); - } - - public override void Write(byte[] buffer, int offset, int count) - { - // We check the limits first, because we can keep the archive consistent - // if we can prevent the writes from happening - if (entry.Zip64HeaderOffset == 0) + else { - // Pre-check, the counting.Count is not exact, as we do not know the size before having actually compressed it - if ( - limitsExceeded - || ((decompressed + (uint)count) > uint.MaxValue) - || (counting!.Count + (uint)count) > uint.MaxValue - ) + // We have a streaming archive, so we should add a post-data-descriptor, + // but we cannot as it does not hold the zip64 values + // Throwing an exception until the zip specification is clarified + + // Ideally, we should not throw from Dispose() + // We should not get here as the Write call checks the limits + if (zip64) { throw new NotSupportedException( - "Attempted to write a stream that is larger than 4GiB without setting the zip64 option" + "Streams larger than 4GiB are not supported for non-seekable streams" ); } - } - decompressed += (uint)count; - crc.SlurpBlock(buffer, offset, count); - writeStream.Write(buffer, offset, count); - - if (entry.Zip64HeaderOffset == 0) - { - // Post-check, this is accurate - if ((decompressed > uint.MaxValue) || counting!.Count > uint.MaxValue) - { - // We have written the data, so the archive is now broken - // Throwing the exception here, allows us to avoid - // throwing an exception in Dispose() which is discouraged - // as it can mask other errors - limitsExceeded = true; - throw new NotSupportedException( - "Attempted to write a stream that is larger than 4GiB without setting the zip64 option" - ); - } + Span intBuf = stackalloc byte[4]; + BinaryPrimitives.WriteUInt32LittleEndian( + intBuf, + ZipHeaderFactory.POST_DATA_DESCRIPTOR + ); + originalStream.Write(intBuf); + writer.WriteFooter(entry.Crc, compressedvalue, decompressedvalue); + writer.streamPosition += (long)entry.Compressed + 16; } + writer.entries.Add(entry); } } - #endregion Nested type: ZipWritingStream + public override void Flush() + { + writeStream.Flush(); + } + + public override int Read(byte[] buffer, int offset, int count) + { + throw new NotSupportedException(); + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } + + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + public override void Write(byte[] buffer, int offset, int count) + { + // We check the limits first, because we can keep the archive consistent + // if we can prevent the writes from happening + if (entry.Zip64HeaderOffset == 0) + { + // Pre-check, the counting.Count is not exact, as we do not know the size before having actually compressed it + if ( + limitsExceeded + || ((decompressed + (uint)count) > uint.MaxValue) + || (counting!.Count + (uint)count) > uint.MaxValue + ) + { + throw new NotSupportedException( + "Attempted to write a stream that is larger than 4GiB without setting the zip64 option" + ); + } + } + + decompressed += (uint)count; + crc.SlurpBlock(buffer, offset, count); + writeStream.Write(buffer, offset, count); + + if (entry.Zip64HeaderOffset == 0) + { + // Post-check, this is accurate + if ((decompressed > uint.MaxValue) || counting!.Count > uint.MaxValue) + { + // We have written the data, so the archive is now broken + // Throwing the exception here, allows us to avoid + // throwing an exception in Dispose() which is discouraged + // as it can mask other errors + limitsExceeded = true; + throw new NotSupportedException( + "Attempted to write a stream that is larger than 4GiB without setting the zip64 option" + ); + } + } + } } + + #endregion Nested type: ZipWritingStream } diff --git a/src/SharpCompress/Writers/Zip/ZipWriterEntryOptions.cs b/src/SharpCompress/Writers/Zip/ZipWriterEntryOptions.cs index 0f4e8886..a718f3b5 100644 --- a/src/SharpCompress/Writers/Zip/ZipWriterEntryOptions.cs +++ b/src/SharpCompress/Writers/Zip/ZipWriterEntryOptions.cs @@ -1,28 +1,27 @@ -using System; +using System; using SharpCompress.Common; using SharpCompress.Compressors.Deflate; -namespace SharpCompress.Writers.Zip +namespace SharpCompress.Writers.Zip; + +public class ZipWriterEntryOptions { - public class ZipWriterEntryOptions - { - public CompressionType? CompressionType { get; set; } + public CompressionType? CompressionType { get; set; } - /// - /// When CompressionType.Deflate is used, this property is referenced. Defaults to CompressionLevel.Default. - /// - public CompressionLevel? DeflateCompressionLevel { get; set; } + /// + /// When CompressionType.Deflate is used, this property is referenced. Defaults to CompressionLevel.Default. + /// + public CompressionLevel? DeflateCompressionLevel { get; set; } - public string? EntryComment { get; set; } + public string? EntryComment { get; set; } - public DateTime? ModificationDateTime { get; set; } + public DateTime? ModificationDateTime { get; set; } - /// - /// Allocate an extra 20 bytes for this entry to store, - /// 64 bit length values, thus enabling streams - /// larger than 4GiB. - /// This option is not supported with non-seekable streams. - /// - public bool? EnableZip64 { get; set; } - } + /// + /// Allocate an extra 20 bytes for this entry to store, + /// 64 bit length values, thus enabling streams + /// larger than 4GiB. + /// This option is not supported with non-seekable streams. + /// + public bool? EnableZip64 { get; set; } } diff --git a/src/SharpCompress/Writers/Zip/ZipWriterOptions.cs b/src/SharpCompress/Writers/Zip/ZipWriterOptions.cs index e1758896..fc11ffbf 100644 --- a/src/SharpCompress/Writers/Zip/ZipWriterOptions.cs +++ b/src/SharpCompress/Writers/Zip/ZipWriterOptions.cs @@ -1,40 +1,38 @@ -using SharpCompress.Common; +using SharpCompress.Common; using SharpCompress.Compressors.Deflate; -namespace SharpCompress.Writers.Zip +namespace SharpCompress.Writers.Zip; + +public class ZipWriterOptions : WriterOptions { - public class ZipWriterOptions : WriterOptions + public ZipWriterOptions(CompressionType compressionType) : base(compressionType) { } + + internal ZipWriterOptions(WriterOptions options) : base(options.CompressionType) { - public ZipWriterOptions(CompressionType compressionType) : base(compressionType) { } + LeaveStreamOpen = options.LeaveStreamOpen; + ArchiveEncoding = options.ArchiveEncoding; - internal ZipWriterOptions(WriterOptions options) : base(options.CompressionType) + if (options is ZipWriterOptions writerOptions) { - LeaveStreamOpen = options.LeaveStreamOpen; - ArchiveEncoding = options.ArchiveEncoding; - - var writerOptions = options as ZipWriterOptions; - if (writerOptions != null) - { - UseZip64 = writerOptions.UseZip64; - DeflateCompressionLevel = writerOptions.DeflateCompressionLevel; - ArchiveComment = writerOptions.ArchiveComment; - } + UseZip64 = writerOptions.UseZip64; + DeflateCompressionLevel = writerOptions.DeflateCompressionLevel; + ArchiveComment = writerOptions.ArchiveComment; } - - /// - /// When CompressionType.Deflate is used, this property is referenced. Defaults to CompressionLevel.Default. - /// - public CompressionLevel DeflateCompressionLevel { get; set; } = CompressionLevel.Default; - - public string? ArchiveComment { get; set; } - - /// - /// Sets a value indicating if zip64 support is enabled. - /// If this is not set, individual stream lengths cannot exceed 4 GiB. - /// This option is not supported for non-seekable streams. - /// Archives larger than 4GiB are supported as long as all streams - /// are less than 4GiB in length. - /// - public bool UseZip64 { get; set; } } + + /// + /// When CompressionType.Deflate is used, this property is referenced. Defaults to CompressionLevel.Default. + /// + public CompressionLevel DeflateCompressionLevel { get; set; } = CompressionLevel.Default; + + public string? ArchiveComment { get; set; } + + /// + /// Sets a value indicating if zip64 support is enabled. + /// If this is not set, individual stream lengths cannot exceed 4 GiB. + /// This option is not supported for non-seekable streams. + /// Archives larger than 4GiB are supported as long as all streams + /// are less than 4GiB in length. + /// + public bool UseZip64 { get; set; } } diff --git a/tests/SharpCompress.Test/ADCTest.cs b/tests/SharpCompress.Test/ADCTest.cs index 4be158d1..ae131ceb 100644 --- a/tests/SharpCompress.Test/ADCTest.cs +++ b/tests/SharpCompress.Test/ADCTest.cs @@ -1,4 +1,4 @@ -// +// // ADC.cs // // Author: @@ -30,155 +30,112 @@ using SharpCompress.Compressors.Deflate; using SharpCompress.Crypto; using Xunit; -namespace SharpCompress.Test +namespace SharpCompress.Test; + +public class ADCTest : TestBase { - public class ADCTest : TestBase + [Fact] + public void TestBuffer() { - [Fact] - public void TestBuffer() + using var decFs = File.OpenRead( + Path.Combine(TEST_ARCHIVES_PATH, "adc_decompressed.bin") + ); + var decompressed = new byte[decFs.Length]; + decFs.Read(decompressed, 0, decompressed.Length); + + using var cmpFs = File.OpenRead( + Path.Combine(TEST_ARCHIVES_PATH, "adc_compressed.bin") + ); + var compressed = new byte[cmpFs.Length]; + cmpFs.Read(compressed, 0, compressed.Length); + + ADCBase.Decompress(compressed, out var test); + + Assert.Equal(decompressed, test); + } + + [Fact] + public void TestBaseStream() + { + using var decFs = File.OpenRead( + Path.Combine(TEST_ARCHIVES_PATH, "adc_decompressed.bin") + ); + var decompressed = new byte[decFs.Length]; + decFs.Read(decompressed, 0, decompressed.Length); + + using var cmpFs = File.OpenRead( + Path.Combine(TEST_ARCHIVES_PATH, "adc_compressed.bin") + ); + + ADCBase.Decompress(cmpFs, out var test); + + Assert.Equal(decompressed, test); + } + + [Fact] + public void TestADCStreamWholeChunk() + { + using var decFs = File.OpenRead( + Path.Combine(TEST_ARCHIVES_PATH, "adc_decompressed.bin") + ); + var decompressed = new byte[decFs.Length]; + decFs.Read(decompressed, 0, decompressed.Length); + + using var cmpFs = File.OpenRead( + Path.Combine(TEST_ARCHIVES_PATH, "adc_compressed.bin") + ); + using var decStream = new ADCStream(cmpFs, CompressionMode.Decompress); + var test = new byte[262144]; + + decStream.Read(test, 0, test.Length); + + Assert.Equal(decompressed, test); + } + + [Fact] + public void TestADCStream() + { + using var decFs = File.OpenRead( + Path.Combine(TEST_ARCHIVES_PATH, "adc_decompressed.bin") + ); + var decompressed = new byte[decFs.Length]; + decFs.Read(decompressed, 0, decompressed.Length); + + using var cmpFs = File.OpenRead( + Path.Combine(TEST_ARCHIVES_PATH, "adc_compressed.bin") + ); + using var decStream = new ADCStream(cmpFs, CompressionMode.Decompress); + using var decMs = new MemoryStream(); + var test = new byte[512]; + var count = 0; + + do { - using ( - FileStream decFs = File.OpenRead( - Path.Combine(TEST_ARCHIVES_PATH, "adc_decompressed.bin") - ) - ) - { - byte[] decompressed = new byte[decFs.Length]; - decFs.Read(decompressed, 0, decompressed.Length); + count = decStream.Read(test, 0, test.Length); + decMs.Write(test, 0, count); + } while (count > 0); - using ( - FileStream cmpFs = File.OpenRead( - Path.Combine(TEST_ARCHIVES_PATH, "adc_compressed.bin") - ) - ) - { - byte[] compressed = new byte[cmpFs.Length]; - cmpFs.Read(compressed, 0, compressed.Length); - byte[]? test; + Assert.Equal(decompressed, decMs.ToArray()); + } - ADCBase.Decompress(compressed, out test); + [Fact] + public void TestCrc32Stream() + { + using var decFs = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar")); + var crc32 = new CRC32().GetCrc32(decFs); + decFs.Seek(0, SeekOrigin.Begin); - Assert.Equal(decompressed, test); - } - } - } + var memory = new MemoryStream(); + var crcStream = new Crc32Stream(memory, 0xEDB88320, 0xFFFFFFFF); + decFs.CopyTo(crcStream); - [Fact] - public void TestBaseStream() - { - using ( - FileStream decFs = File.OpenRead( - Path.Combine(TEST_ARCHIVES_PATH, "adc_decompressed.bin") - ) - ) - { - byte[] decompressed = new byte[decFs.Length]; - decFs.Read(decompressed, 0, decompressed.Length); + decFs.Seek(0, SeekOrigin.Begin); - using ( - FileStream cmpFs = File.OpenRead( - Path.Combine(TEST_ARCHIVES_PATH, "adc_compressed.bin") - ) - ) - { - byte[]? test; + var crc32a = crcStream.Crc; - ADCBase.Decompress(cmpFs, out test); + var crc32b = Crc32Stream.Compute(memory.ToArray()); - Assert.Equal(decompressed, test); - } - } - } - - [Fact] - public void TestADCStreamWholeChunk() - { - using ( - FileStream decFs = File.OpenRead( - Path.Combine(TEST_ARCHIVES_PATH, "adc_decompressed.bin") - ) - ) - { - byte[] decompressed = new byte[decFs.Length]; - decFs.Read(decompressed, 0, decompressed.Length); - - using ( - FileStream cmpFs = File.OpenRead( - Path.Combine(TEST_ARCHIVES_PATH, "adc_compressed.bin") - ) - ) - { - using (ADCStream decStream = new ADCStream(cmpFs, CompressionMode.Decompress)) - { - byte[] test = new byte[262144]; - - decStream.Read(test, 0, test.Length); - - Assert.Equal(decompressed, test); - } - } - } - } - - [Fact] - public void TestADCStream() - { - using ( - FileStream decFs = File.OpenRead( - Path.Combine(TEST_ARCHIVES_PATH, "adc_decompressed.bin") - ) - ) - { - byte[] decompressed = new byte[decFs.Length]; - decFs.Read(decompressed, 0, decompressed.Length); - - using ( - FileStream cmpFs = File.OpenRead( - Path.Combine(TEST_ARCHIVES_PATH, "adc_compressed.bin") - ) - ) - { - using (ADCStream decStream = new ADCStream(cmpFs, CompressionMode.Decompress)) - { - using (MemoryStream decMs = new MemoryStream()) - { - byte[] test = new byte[512]; - int count = 0; - - do - { - count = decStream.Read(test, 0, test.Length); - decMs.Write(test, 0, count); - } while (count > 0); - - Assert.Equal(decompressed, decMs.ToArray()); - } - } - } - } - } - - [Fact] - public void TestCrc32Stream() - { - using (FileStream decFs = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar"))) - { - var crc32 = new CRC32().GetCrc32(decFs); - decFs.Seek(0, SeekOrigin.Begin); - - var memory = new MemoryStream(); - var crcStream = new Crc32Stream(memory, 0xEDB88320, 0xFFFFFFFF); - decFs.CopyTo(crcStream); - - decFs.Seek(0, SeekOrigin.Begin); - - var crc32a = crcStream.Crc; - - var crc32b = Crc32Stream.Compute(memory.ToArray()); - - Assert.Equal(crc32, crc32a); - Assert.Equal(crc32, crc32b); - } - } + Assert.Equal(crc32, crc32a); + Assert.Equal(crc32, crc32b); } } diff --git a/tests/SharpCompress.Test/ArchiveTests.cs b/tests/SharpCompress.Test/ArchiveTests.cs index dcf033ca..8b9a4c2d 100644 --- a/tests/SharpCompress.Test/ArchiveTests.cs +++ b/tests/SharpCompress.Test/ArchiveTests.cs @@ -8,148 +8,103 @@ using SharpCompress.IO; using SharpCompress.Readers; using Xunit; -namespace SharpCompress.Test +namespace SharpCompress.Test; + +public class ArchiveTests : ReaderTests { - public class ArchiveTests : ReaderTests + protected void ArchiveGetParts(IEnumerable testArchives) { - protected void ArchiveGetParts(IEnumerable testArchives) + var arcs = testArchives.Select(a => Path.Combine(TEST_ARCHIVES_PATH, a)).ToArray(); + var found = ArchiveFactory.GetFileParts(arcs[0]).ToArray(); + Assert.Equal(arcs.Length, found.Length); + for (var i = 0; i < arcs.Length; i++) { - string[] arcs = testArchives.Select(a => Path.Combine(TEST_ARCHIVES_PATH, a)).ToArray(); - string[] found = ArchiveFactory.GetFileParts(arcs[0]).ToArray(); - Assert.Equal(arcs.Length, found.Length); - for (int i = 0; i < arcs.Length; i++) - Assert.Equal(arcs[i], found[i]); + Assert.Equal(arcs[i], found[i]); } + } - protected void ArchiveStreamReadExtractAll(string testArchive, CompressionType compression) - { - testArchive = Path.Combine(TEST_ARCHIVES_PATH, testArchive); - ArchiveStreamReadExtractAll(new[] { testArchive }, compression); - } + protected void ArchiveStreamReadExtractAll(string testArchive, CompressionType compression) + { + testArchive = Path.Combine(TEST_ARCHIVES_PATH, testArchive); + ArchiveStreamReadExtractAll(new[] { testArchive }, compression); + } - protected void ArchiveStreamReadExtractAll( - IEnumerable testArchives, - CompressionType compression - ) + protected void ArchiveStreamReadExtractAll( + IEnumerable testArchives, + CompressionType compression + ) + { + foreach (var path in testArchives) { - foreach (var path in testArchives) + using (var stream = NonDisposingStream.Create(File.OpenRead(path), true)) { - using (var stream = NonDisposingStream.Create(File.OpenRead(path), true)) + try { - try + using var archive = ArchiveFactory.Open(stream); + Assert.True(archive.IsSolid); + using (var reader = archive.ExtractAllEntries()) { - using (var archive = ArchiveFactory.Open(stream)) - { - Assert.True(archive.IsSolid); - using (var reader = archive.ExtractAllEntries()) - { - UseReader(reader, compression); - } - VerifyFiles(); - - if (archive.Entries.First().CompressionType == CompressionType.Rar) - { - stream.ThrowOnDispose = false; - return; - } - foreach ( - var entry in archive.Entries.Where(entry => !entry.IsDirectory) - ) - { - entry.WriteToDirectory( - SCRATCH_FILES_PATH, - new ExtractionOptions - { - ExtractFullPath = true, - Overwrite = true - } - ); - } - stream.ThrowOnDispose = false; - } + UseReader(reader, compression); } - catch (Exception) + VerifyFiles(); + + if (archive.Entries.First().CompressionType == CompressionType.Rar) { - // Otherwise this will hide the original exception. stream.ThrowOnDispose = false; - throw; + return; } - } - VerifyFiles(); - } - } - - protected void ArchiveStreamRead(string testArchive, ReaderOptions? readerOptions = null) - { - testArchive = Path.Combine(TEST_ARCHIVES_PATH, testArchive); - ArchiveStreamRead(readerOptions, testArchive); - } - - protected void ArchiveStreamRead( - ReaderOptions? readerOptions = null, - params string[] testArchives - ) - { - ArchiveStreamRead( - readerOptions, - testArchives.Select(x => Path.Combine(TEST_ARCHIVES_PATH, x)) - ); - } - - protected void ArchiveStreamRead( - ReaderOptions? readerOptions, - IEnumerable testArchives - ) - { - foreach (var path in testArchives) - { - using (var stream = NonDisposingStream.Create(File.OpenRead(path), true)) - using (var archive = ArchiveFactory.Open(stream, readerOptions)) - { - try + foreach ( + var entry in archive.Entries.Where(entry => !entry.IsDirectory) + ) { - foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) - { - entry.WriteToDirectory( - SCRATCH_FILES_PATH, - new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } - ); - } - } - catch (IndexOutOfRangeException) - { - //SevenZipArchive_BZip2_Split test needs this - stream.ThrowOnDispose = false; - throw; + entry.WriteToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions + { + ExtractFullPath = true, + Overwrite = true + } + ); } stream.ThrowOnDispose = false; } - VerifyFiles(); + catch (Exception) + { + // Otherwise this will hide the original exception. + stream.ThrowOnDispose = false; + throw; + } } + VerifyFiles(); } + } - protected void ArchiveStreamMultiRead( - ReaderOptions? readerOptions = null, - params string[] testArchives - ) - { - ArchiveStreamMultiRead( - readerOptions, - testArchives.Select(x => Path.Combine(TEST_ARCHIVES_PATH, x)) - ); - } + protected void ArchiveStreamRead(string testArchive, ReaderOptions? readerOptions = null) + { + testArchive = Path.Combine(TEST_ARCHIVES_PATH, testArchive); + ArchiveStreamRead(readerOptions, testArchive); + } - protected void ArchiveStreamMultiRead( - ReaderOptions? readerOptions, - IEnumerable testArchives - ) + protected void ArchiveStreamRead( + ReaderOptions? readerOptions = null, + params string[] testArchives + ) + { + ArchiveStreamRead( + readerOptions, + testArchives.Select(x => Path.Combine(TEST_ARCHIVES_PATH, x)) + ); + } + + protected void ArchiveStreamRead( + ReaderOptions? readerOptions, + IEnumerable testArchives + ) + { + foreach (var path in testArchives) { - using ( - var archive = ArchiveFactory.Open( - testArchives.Select(a => new FileInfo(a)), - readerOptions - ) - ) + using (var stream = NonDisposingStream.Create(File.OpenRead(path), true)) + using (var archive = ArchiveFactory.Open(stream, readerOptions)) { try { @@ -163,110 +118,40 @@ namespace SharpCompress.Test } catch (IndexOutOfRangeException) { + //SevenZipArchive_BZip2_Split test needs this + stream.ThrowOnDispose = false; throw; } + stream.ThrowOnDispose = false; } VerifyFiles(); } + } - protected void ArchiveOpenStreamRead( - ReaderOptions? readerOptions = null, - params string[] testArchives - ) - { - ArchiveOpenStreamRead( - readerOptions, - testArchives.Select(x => Path.Combine(TEST_ARCHIVES_PATH, x)) - ); - } + protected void ArchiveStreamMultiRead( + ReaderOptions? readerOptions = null, + params string[] testArchives + ) + { + ArchiveStreamMultiRead( + readerOptions, + testArchives.Select(x => Path.Combine(TEST_ARCHIVES_PATH, x)) + ); + } - protected void ArchiveOpenStreamRead( - ReaderOptions? readerOptions, - IEnumerable testArchives - ) - { - using ( - var archive = ArchiveFactory.Open( - testArchives.Select(f => new FileInfo(f)), - readerOptions - ) + protected void ArchiveStreamMultiRead( + ReaderOptions? readerOptions, + IEnumerable testArchives + ) + { + using ( + var archive = ArchiveFactory.Open( + testArchives.Select(a => new FileInfo(a)), + readerOptions ) - { - try - { - foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) - { - entry.WriteToDirectory( - SCRATCH_FILES_PATH, - new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } - ); - } - } - catch (IndexOutOfRangeException) - { - throw; - } - } - VerifyFiles(); - } - - protected void ArchiveOpenEntryVolumeIndexTest( - int[][] results, - ReaderOptions? readerOptions = null, - params string[] testArchives ) { - ArchiveOpenEntryVolumeIndexTest( - results, - readerOptions, - testArchives.Select(x => Path.Combine(TEST_ARCHIVES_PATH, x)) - ); - } - - protected void ArchiveOpenEntryVolumeIndexTest( - int[][] results, - ReaderOptions? readerOptions, - IEnumerable testArchives - ) - { - string[] src = testArchives.ToArray(); - using ( - var archive = ArchiveFactory.Open( - testArchives.Select(f => new FileInfo(f)), - readerOptions - ) - ) - { - try - { - int idx = 0; - foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) - { - Assert.Equal(entry.VolumeIndexFirst, results[idx][0]); - Assert.Equal(entry.VolumeIndexLast, results[idx][1]); - Assert.Equal( - src[entry.VolumeIndexFirst], - archive.Volumes.First(a => a.Index == entry.VolumeIndexFirst).FileName - ); - Assert.Equal( - src[entry.VolumeIndexLast], - archive.Volumes.First(a => a.Index == entry.VolumeIndexLast).FileName - ); - - idx++; - } - } - catch (IndexOutOfRangeException) - { - throw; - } - } - } - - protected void ArchiveFileRead(string testArchive, ReaderOptions? readerOptions = null) - { - testArchive = Path.Combine(TEST_ARCHIVES_PATH, testArchive); - using (var archive = ArchiveFactory.Open(testArchive, readerOptions)) + try { foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) { @@ -276,32 +161,142 @@ namespace SharpCompress.Test ); } } - VerifyFiles(); + catch (IndexOutOfRangeException) + { + throw; + } } + VerifyFiles(); + } - /// - /// Demonstrate the ExtractionOptions.PreserveFileTime and ExtractionOptions.PreserveAttributes extract options - /// - protected void ArchiveFileReadEx(string testArchive) + protected void ArchiveOpenStreamRead( + ReaderOptions? readerOptions = null, + params string[] testArchives + ) + { + ArchiveOpenStreamRead( + readerOptions, + testArchives.Select(x => Path.Combine(TEST_ARCHIVES_PATH, x)) + ); + } + + protected void ArchiveOpenStreamRead( + ReaderOptions? readerOptions, + IEnumerable testArchives + ) + { + using ( + var archive = ArchiveFactory.Open( + testArchives.Select(f => new FileInfo(f)), + readerOptions + ) + ) { - testArchive = Path.Combine(TEST_ARCHIVES_PATH, testArchive); - using (var archive = ArchiveFactory.Open(testArchive)) + try { foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) { entry.WriteToDirectory( SCRATCH_FILES_PATH, - new ExtractionOptions() - { - ExtractFullPath = true, - Overwrite = true, - PreserveAttributes = true, - PreserveFileTime = true - } + new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } ); } } - VerifyFilesEx(); + catch (IndexOutOfRangeException) + { + throw; + } + } + VerifyFiles(); + } + + protected void ArchiveOpenEntryVolumeIndexTest( + int[][] results, + ReaderOptions? readerOptions = null, + params string[] testArchives + ) + { + ArchiveOpenEntryVolumeIndexTest( + results, + readerOptions, + testArchives.Select(x => Path.Combine(TEST_ARCHIVES_PATH, x)) + ); + } + + protected void ArchiveOpenEntryVolumeIndexTest( + int[][] results, + ReaderOptions? readerOptions, + IEnumerable testArchives + ) + { + var src = testArchives.ToArray(); + using var archive = ArchiveFactory.Open( + testArchives.Select(f => new FileInfo(f)), + readerOptions + ); + try + { + var idx = 0; + foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) + { + Assert.Equal(entry.VolumeIndexFirst, results[idx][0]); + Assert.Equal(entry.VolumeIndexLast, results[idx][1]); + Assert.Equal( + src[entry.VolumeIndexFirst], + archive.Volumes.First(a => a.Index == entry.VolumeIndexFirst).FileName + ); + Assert.Equal( + src[entry.VolumeIndexLast], + archive.Volumes.First(a => a.Index == entry.VolumeIndexLast).FileName + ); + + idx++; + } + } + catch (IndexOutOfRangeException) + { + throw; } } + + protected void ArchiveFileRead(string testArchive, ReaderOptions? readerOptions = null) + { + testArchive = Path.Combine(TEST_ARCHIVES_PATH, testArchive); + using (var archive = ArchiveFactory.Open(testArchive, readerOptions)) + { + foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) + { + entry.WriteToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } + ); + } + } + VerifyFiles(); + } + + /// + /// Demonstrate the ExtractionOptions.PreserveFileTime and ExtractionOptions.PreserveAttributes extract options + /// + protected void ArchiveFileReadEx(string testArchive) + { + testArchive = Path.Combine(TEST_ARCHIVES_PATH, testArchive); + using (var archive = ArchiveFactory.Open(testArchive)) + { + foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) + { + entry.WriteToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() + { + ExtractFullPath = true, + Overwrite = true, + PreserveAttributes = true, + PreserveFileTime = true + } + ); + } + } + VerifyFilesEx(); + } } diff --git a/tests/SharpCompress.Test/Filters/BranchExecTests.cs b/tests/SharpCompress.Test/Filters/BranchExecTests.cs index 138012c0..e979d537 100644 --- a/tests/SharpCompress.Test/Filters/BranchExecTests.cs +++ b/tests/SharpCompress.Test/Filters/BranchExecTests.cs @@ -8,1240 +8,1239 @@ using SharpCompress.Compressors.Filters; using Xunit; -namespace SharpCompress.Test.Filters +namespace SharpCompress.Test.Filters; + +public class BranchExecTests { - public class BranchExecTests + private static byte[] x86resultData { get; } = + new byte[] + { + 0x12, + 0x00, + 0x00, + 0x00, + 0x02, + 0x0B, + 0x00, + 0x00, + 0xE8, + 0xBD, + 0x00, + 0x00, + 0x00, + 0x07, + 0x00, + 0x00, + 0x12, + 0x00, + 0x00, + 0x00, + 0x6D, + 0x01, + 0x00, + 0x00, + 0xF0, + 0xCA, + 0x00, + 0x00, + 0x1C, + 0x00, + 0x00, + 0x00, + 0x12, + 0x00, + 0x00, + 0x00, + 0xBC, + 0x09, + 0x00, + 0x00, + 0x14, + 0xC2, + 0x00, + 0x00, + 0xE0, + 0x01, + 0x00, + 0x00, + 0x12, + 0x00, + 0x00, + 0x00, + 0x98, + 0x0B, + 0x00, + 0x00, + 0x60, + 0x75, + 0x0A, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x10, + 0x00, + 0xF1, + 0xFF, + 0x42, + 0x01, + 0x00, + 0x00, + 0x08, + 0xC8, + 0x00, + 0x00, + 0x1C, + 0x00, + }; + + private static byte[] x86Data { get; } = + new byte[] + { + 0x12, + 0x00, + 0x00, + 0x00, + 0x02, + 0x0B, + 0x00, + 0x00, + 0xE8, + 0xCA, + 0x20, + 0x00, + 0x00, + 0x07, + 0x00, + 0x00, + 0x12, + 0x00, + 0x00, + 0x00, + 0x6D, + 0x01, + 0x00, + 0x00, + 0xF0, + 0xCA, + 0x00, + 0x00, + 0x1C, + 0x00, + 0x00, + 0x00, + 0x12, + 0x00, + 0x00, + 0x00, + 0xBC, + 0x09, + 0x00, + 0x00, + 0x14, + 0xC2, + 0x00, + 0x00, + 0xE0, + 0x01, + 0x00, + 0x00, + 0x12, + 0x00, + 0x00, + 0x00, + 0x98, + 0x0B, + 0x00, + 0x00, + 0x60, + 0x75, + 0x0A, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x10, + 0x00, + 0xF1, + 0xFF, + 0x42, + 0x01, + 0x00, + 0x00, + 0x08, + 0xC8, + 0x00, + 0x00, + 0x1C, + 0x00, + }; + + private static byte[] ppcResultData { get; } = + new byte[] + { + 0xF8, + 0x6B, + 0x2E, + 0x8C, + 0x95, + 0xC5, + 0x4B, + 0x1B, + 0x94, + 0x78, + 0x9E, + 0x7C, + 0xBD, + 0x8B, + 0xA8, + 0xAF, + 0x31, + 0x20, + 0xFE, + 0x0F, + 0xB3, + 0x15, + 0x9A, + 0x7C, + 0xD5, + 0x5C, + 0xC2, + 0xC0, + 0xEC, + 0xE9, + 0x43, + 0x2B, + 0xD0, + 0x9F, + 0x2C, + 0xFC, + 0xB8, + 0x2B, + 0x6B, + 0x15, + 0xCD, + 0x3F, + 0x0C, + 0xAF, + 0x8F, + 0x68, + 0xB0, + 0x6E, + 0x6B, + 0x30, + 0x2E, + 0x8C, + 0x3F, + 0x7E, + 0x96, + 0x7C, + 0x93, + 0xB2, + 0xA4, + 0x0E, + 0x43, + 0xEA, + 0x20, + 0x10, + 0x38, + 0x6D, + 0x37, + 0xF8, + 0x87, + 0xFE, + 0xA9, + 0x63, + 0x75, + 0xF5, + 0x56, + 0x34, + 0x4A, + 0xE3, + 0xCF, + 0x89, + 0x18, + 0x08, + 0xC2, + 0x76, + 0x74, + 0x12, + 0xEC, + 0xA7, + 0x6D, + 0xC2, + 0xB7, + 0x1B, + 0x7A, + 0xB2, + 0xD4, + 0xED + }; + + private static byte[] ppcData { get; } = + new byte[] + { + 0xF8, + 0x6B, + 0x2E, + 0x8C, + 0x95, + 0xC5, + 0x4B, + 0x1B, + 0x94, + 0x78, + 0x9E, + 0x7C, + 0xBD, + 0x8B, + 0xA8, + 0xAF, + 0x31, + 0x20, + 0xFE, + 0x0F, + 0xB3, + 0x15, + 0x9A, + 0x7C, + 0xD5, + 0x5C, + 0xC2, + 0xC0, + 0xEC, + 0xE9, + 0x43, + 0x2B, + 0xD0, + 0x9F, + 0x2C, + 0xFC, + 0xB8, + 0x2B, + 0x6B, + 0x15, + 0xCD, + 0x3F, + 0x0C, + 0xAF, + 0x8F, + 0x68, + 0xB0, + 0x6E, + 0x6B, + 0x30, + 0x2E, + 0x8C, + 0x3F, + 0x7E, + 0x96, + 0x7C, + 0x93, + 0xB2, + 0xA4, + 0x0E, + 0x43, + 0xEA, + 0x20, + 0x10, + 0x38, + 0x6D, + 0x37, + 0xF8, + 0x87, + 0xFE, + 0xA9, + 0x63, + 0x75, + 0xF5, + 0x56, + 0x34, + 0x4A, + 0xE3, + 0xD6, + 0x75, + 0x18, + 0x08, + 0xC2, + 0x76, + 0x74, + 0x12, + 0xEC, + 0xA7, + 0x6D, + 0xC2, + 0xB7, + 0x1B, + 0x7A, + 0xB2, + 0xD4, + 0xED + }; + + private static byte[] armResultData { get; } = + new byte[] + { + 0x7C, + 0xFC, + 0x0A, + 0x00, + 0x16, + 0x42, + 0x01, + 0x00, + 0x80, + 0xFC, + 0x0A, + 0x00, + 0x16, + 0xB8, + 0x00, + 0x00, + 0x84, + 0xFC, + 0x0A, + 0x00, + 0x16, + 0x3A, + 0x00, + 0x00, + 0x04, + 0xE0, + 0x2D, + 0xE5, + 0x04, + 0xD0, + 0x4D, + 0xE2, + 0x0E, + 0x04, + 0x00, + 0xEB, + 0x04, + 0xD0, + 0x8D, + 0xE2, + 0x04, + 0xE0, + 0x9D, + 0xE4, + 0x1E, + 0xFF, + 0x2F, + 0xE1, + 0x04, + 0xE0, + 0x2D, + 0xE5, + 0x04, + 0xE0, + 0x9F, + 0xE5, + 0x0E, + 0xE0, + 0x8F, + 0xE0, + 0x08, + 0xF0, + 0xBE, + 0xE5, + 0xF0, + 0x3A, + 0x0A, + 0x00, + 0x00, + 0xC6, + 0x8F, + 0xE2, + 0xA3, + 0xCA, + 0x8C, + 0xE2, + 0xF0, + 0xFA, + 0xBC, + 0xE5, + 0x00, + 0xC6, + 0x8F, + 0xE2, + 0xA3, + 0xCA, + 0x8C, + 0xE2, + 0xE8, + 0xFA, + 0xBC, + 0xE5, + 0x00, + 0xC6, + 0x8F, + 0xE2 + }; + + private static byte[] armData { get; } = + new byte[] + { + 0x7C, + 0xFC, + 0x0A, + 0x00, + 0x16, + 0x42, + 0x01, + 0x00, + 0x80, + 0xFC, + 0x0A, + 0x00, + 0x16, + 0xB8, + 0x00, + 0x00, + 0x84, + 0xFC, + 0x0A, + 0x00, + 0x16, + 0x3A, + 0x00, + 0x00, + 0x04, + 0xE0, + 0x2D, + 0xE5, + 0x04, + 0xD0, + 0x4D, + 0xE2, + 0x18, + 0x13, + 0x00, + 0xEB, + 0x04, + 0xD0, + 0x8D, + 0xE2, + 0x04, + 0xE0, + 0x9D, + 0xE4, + 0x1E, + 0xFF, + 0x2F, + 0xE1, + 0x04, + 0xE0, + 0x2D, + 0xE5, + 0x04, + 0xE0, + 0x9F, + 0xE5, + 0x0E, + 0xE0, + 0x8F, + 0xE0, + 0x08, + 0xF0, + 0xBE, + 0xE5, + 0xF0, + 0x3A, + 0x0A, + 0x00, + 0x00, + 0xC6, + 0x8F, + 0xE2, + 0xA3, + 0xCA, + 0x8C, + 0xE2, + 0xF0, + 0xFA, + 0xBC, + 0xE5, + 0x00, + 0xC6, + 0x8F, + 0xE2, + 0xA3, + 0xCA, + 0x8C, + 0xE2, + 0xE8, + 0xFA, + 0xBC, + 0xE5, + 0x00, + 0xC6, + 0x8F, + 0xE2 + }; + + private static byte[] armtResultData { get; } = + new byte[] + { + 0x95, + 0x23, + 0xB6, + 0xB1, + 0xBE, + 0x60, + 0x79, + 0xF0, + 0xF6, + 0x01, + 0xD9, + 0x7F, + 0x2E, + 0x03, + 0x31, + 0x1C, + 0xFD, + 0xD3, + 0x40, + 0x0F, + 0x21, + 0x3C, + 0x06, + 0x97, + 0xE5, + 0xC3, + 0x57, + 0x11, + 0x76, + 0x6F, + 0xE3, + 0x70, + 0xED, + 0x49, + 0xCB, + 0xB5, + 0xC9, + 0x42, + 0x59, + 0x10, + 0x2F, + 0xBD, + 0xAE, + 0xB1, + 0x40, + 0x4D, + 0x9D, + 0x7C, + 0xE9, + 0xFC, + 0x48, + 0x3E, + 0xBC, + 0x7F, + 0x0B, + 0x23, + 0xB0, + 0x8A, + 0x4D, + 0x02, + 0x39, + 0xC4, + 0xFB, + 0x66, + 0x83, + 0x7F, + 0xA7, + 0xBD, + 0x12, + 0xAC, + 0xED, + 0x31, + 0x34, + 0x93, + 0x4D, + 0x8D, + 0xD7, + 0x94, + 0x93, + 0x1C, + 0x0A, + 0x50, + 0x54, + 0x4B, + 0x03, + 0x55, + 0x27, + 0xFE, + 0xCE, + 0x29, + 0x66, + 0x52, + 0x81, + 0xAE, + 0x69, + 0xA0, + 0x69, + 0xF2, + 0x3D, + 0xFF, + 0xA1, + 0x8A, + 0x5D, + 0x61, + 0x7D, + 0xC5, + 0x94, + 0x0A, + 0x7D, + 0xED, + 0x11, + 0x0F + }; + + private static byte[] armtData { get; } = + new byte[] + { + 0x95, + 0x23, + 0xB6, + 0xB1, + 0xBE, + 0x60, + 0x79, + 0xF0, + 0xF6, + 0x01, + 0xD9, + 0x7F, + 0x2E, + 0x03, + 0x31, + 0x1C, + 0xFD, + 0xD3, + 0x40, + 0x0F, + 0x21, + 0x3C, + 0x06, + 0x97, + 0xE5, + 0xC3, + 0x57, + 0x11, + 0x76, + 0x6F, + 0xE3, + 0x70, + 0xED, + 0x49, + 0xCB, + 0xB5, + 0xC9, + 0x42, + 0x59, + 0x10, + 0x2F, + 0xBD, + 0xAE, + 0xB1, + 0x40, + 0x4D, + 0x9D, + 0x7C, + 0xE9, + 0xFC, + 0x48, + 0x3E, + 0xBC, + 0x7F, + 0x0B, + 0x23, + 0xB0, + 0x8A, + 0x4D, + 0x02, + 0x39, + 0xC4, + 0xFB, + 0x66, + 0x83, + 0x7F, + 0xA7, + 0xBD, + 0x12, + 0xAC, + 0xED, + 0x31, + 0x34, + 0x93, + 0x4D, + 0x8D, + 0xD7, + 0x94, + 0x93, + 0x1C, + 0x0A, + 0x50, + 0x54, + 0x4B, + 0x03, + 0x55, + 0x27, + 0xFE, + 0xCE, + 0x29, + 0x66, + 0x52, + 0x81, + 0xAE, + 0x69, + 0xA0, + 0x6A, + 0xF2, + 0x6F, + 0xFC, + 0xA1, + 0x8A, + 0x5D, + 0x61, + 0x7D, + 0xC5, + 0x94, + 0x0A, + 0x7D, + 0xED, + 0x11, + 0x0F + }; + + private static byte[] ia64ResultData { get; } = + new byte[] + { + 0x4D, + 0xF8, + 0xF2, + 0x0D, + 0x06, + 0x2F, + 0x74, + 0x0F, + 0xF0, + 0x91, + 0x06, + 0x0B, + 0x19, + 0x22, + 0x91, + 0x5A, + 0x66, + 0x56, + 0xA7, + 0x15, + 0x77, + 0x1E, + 0x2F, + 0xA3, + 0xE4, + 0xDE, + 0x93, + 0x1C, + 0xD5, + 0xCE, + 0x6E, + 0x45, + 0x36, + 0x15, + 0x15, + 0x65, + 0x4E, + 0xC5, + 0xA3, + 0x8C, + 0x5A, + 0x8B, + 0x8A, + 0x1C, + 0x12, + 0x5B, + 0x39, + 0x1F, + 0xA0, + 0xF2, + 0x93, + 0x7C, + 0x7F, + 0x5D, + 0xD9, + 0x30, + 0x1F, + 0xF6, + 0x5C, + 0x10, + 0x62, + 0x3E, + 0xB4, + 0x64, + 0x56, + 0x48, + 0xB2, + 0x20, + 0x39, + 0xE8, + 0x44, + 0x10, + 0x87, + 0x9E, + 0x2C, + 0xFC, + 0x29, + 0x0E, + 0x20, + 0x76, + 0xCE, + 0xDA, + 0x93, + 0x1C, + 0xED, + 0x54, + 0x0D, + 0xAF, + 0xEC, + 0xDE, + 0x93, + 0x1C, + 0x2B, + 0x72, + 0xD5, + 0x0D + }; + + private static byte[] ia64Data { get; } = + new byte[] + { + 0x4D, + 0xF8, + 0xF2, + 0x0D, + 0x06, + 0x2F, + 0x74, + 0x0F, + 0xF0, + 0x91, + 0x06, + 0x0B, + 0x19, + 0x22, + 0x91, + 0x5A, + 0x66, + 0x56, + 0xA7, + 0x15, + 0x77, + 0x1E, + 0x2F, + 0xA3, + 0xE4, + 0xDE, + 0x93, + 0x1C, + 0xD5, + 0xCE, + 0x6E, + 0x45, + 0x36, + 0x15, + 0x15, + 0x65, + 0x4E, + 0xC5, + 0xA3, + 0x8C, + 0x5A, + 0x8B, + 0x8A, + 0x1C, + 0x12, + 0x5B, + 0x39, + 0x1F, + 0xA0, + 0xF2, + 0x93, + 0x7C, + 0x7F, + 0x5D, + 0xD9, + 0x30, + 0x1F, + 0xF6, + 0x5C, + 0x10, + 0x62, + 0x3E, + 0xB4, + 0x64, + 0x56, + 0x48, + 0xB2, + 0x20, + 0x39, + 0xE8, + 0x44, + 0x80, + 0x8C, + 0x9E, + 0x2C, + 0xFC, + 0x29, + 0x0E, + 0x20, + 0x76, + 0xCE, + 0xDA, + 0x93, + 0x1C, + 0xED, + 0x54, + 0x0D, + 0xAF, + 0xEC, + 0xDE, + 0x93, + 0x1C, + 0x2B, + 0x72, + 0xD5, + 0x0D + }; + + private static byte[] sparcResultData { get; } = + new byte[] + { + 0x78, + 0x2E, + 0x73, + 0x6F, + 0x2E, + 0x33, + 0x00, + 0x00, + 0x07, + 0x01, + 0x00, + 0x00, + 0x09, + 0x00, + 0x00, + 0x00, + 0x40, + 0x00, + 0x00, + 0x00, + 0x0B, + 0x00, + 0x00, + 0x00, + 0xA2, + 0x0D, + 0x10, + 0x12, + 0x30, + 0x03, + 0xC9, + 0x37, + 0x40, + 0x1A, + 0x85, + 0xD9, + 0x44, + 0x34, + 0x40, + 0x32, + 0x85, + 0xA0, + 0x30, + 0x40, + 0x00, + 0x70, + 0x00, + 0x40, + 0x84, + 0x80, + 0x04, + 0x00, + 0xE4, + 0xAC, + 0x07, + 0x04, + 0x21, + 0x44, + 0x02, + 0x20, + 0x10, + 0x00, + 0x40, + 0xC2, + 0x89, + 0x98, + 0x85, + 0x00, + 0x58, + 0x6A, + 0x41, + 0x8E, + 0x18, + 0xA1, + 0x91, + 0x00, + 0x10, + 0x00, + }; + + private static byte[] sparcData { get; } = + new byte[] + { + 0x78, + 0x2E, + 0x73, + 0x6F, + 0x2E, + 0x33, + 0x00, + 0x00, + 0x07, + 0x01, + 0x00, + 0x00, + 0x09, + 0x00, + 0x00, + 0x00, + 0x40, + 0x00, + 0x00, + 0x44, + 0x0B, + 0x00, + 0x00, + 0x00, + 0xA2, + 0x0D, + 0x10, + 0x12, + 0x30, + 0x03, + 0xC9, + 0x37, + 0x40, + 0x1A, + 0x86, + 0x21, + 0x44, + 0x34, + 0x40, + 0x32, + 0x85, + 0xA0, + 0x30, + 0x40, + 0x00, + 0x70, + 0x00, + 0x40, + 0x84, + 0x80, + 0x04, + 0x00, + 0xE4, + 0xAC, + 0x07, + 0x04, + 0x21, + 0x44, + 0x02, + 0x20, + 0x10, + 0x00, + 0x40, + 0xC2, + 0x89, + 0x98, + 0x85, + 0x00, + 0x58, + 0x6A, + 0x41, + 0x8E, + 0x18, + 0xA1, + 0x91, + 0x00, + 0x10, + 0x00, + }; + + private void CompareBuffer(byte[] testBuffer, byte[] targetBuffer) { - private static byte[] x86resultData { get; } = - new byte[] - { - 0x12, - 0x00, - 0x00, - 0x00, - 0x02, - 0x0B, - 0x00, - 0x00, - 0xE8, - 0xBD, - 0x00, - 0x00, - 0x00, - 0x07, - 0x00, - 0x00, - 0x12, - 0x00, - 0x00, - 0x00, - 0x6D, - 0x01, - 0x00, - 0x00, - 0xF0, - 0xCA, - 0x00, - 0x00, - 0x1C, - 0x00, - 0x00, - 0x00, - 0x12, - 0x00, - 0x00, - 0x00, - 0xBC, - 0x09, - 0x00, - 0x00, - 0x14, - 0xC2, - 0x00, - 0x00, - 0xE0, - 0x01, - 0x00, - 0x00, - 0x12, - 0x00, - 0x00, - 0x00, - 0x98, - 0x0B, - 0x00, - 0x00, - 0x60, - 0x75, - 0x0A, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x10, - 0x00, - 0xF1, - 0xFF, - 0x42, - 0x01, - 0x00, - 0x00, - 0x08, - 0xC8, - 0x00, - 0x00, - 0x1C, - 0x00, - }; + Assert.Equal(testBuffer, targetBuffer); + } - private static byte[] x86Data { get; } = - new byte[] - { - 0x12, - 0x00, - 0x00, - 0x00, - 0x02, - 0x0B, - 0x00, - 0x00, - 0xE8, - 0xCA, - 0x20, - 0x00, - 0x00, - 0x07, - 0x00, - 0x00, - 0x12, - 0x00, - 0x00, - 0x00, - 0x6D, - 0x01, - 0x00, - 0x00, - 0xF0, - 0xCA, - 0x00, - 0x00, - 0x1C, - 0x00, - 0x00, - 0x00, - 0x12, - 0x00, - 0x00, - 0x00, - 0xBC, - 0x09, - 0x00, - 0x00, - 0x14, - 0xC2, - 0x00, - 0x00, - 0xE0, - 0x01, - 0x00, - 0x00, - 0x12, - 0x00, - 0x00, - 0x00, - 0x98, - 0x0B, - 0x00, - 0x00, - 0x60, - 0x75, - 0x0A, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x10, - 0x00, - 0xF1, - 0xFF, - 0x42, - 0x01, - 0x00, - 0x00, - 0x08, - 0xC8, - 0x00, - 0x00, - 0x1C, - 0x00, - }; + [Fact] + public void X86ConverterDecodeTest() + { + uint state = 0; + uint ip = 0x2000; + var testData = x86Data; + BranchExecFilter.X86Converter(testData, ip, ref state); + CompareBuffer(testData, x86resultData); + } - private static byte[] ppcResultData { get; } = - new byte[] - { - 0xF8, - 0x6B, - 0x2E, - 0x8C, - 0x95, - 0xC5, - 0x4B, - 0x1B, - 0x94, - 0x78, - 0x9E, - 0x7C, - 0xBD, - 0x8B, - 0xA8, - 0xAF, - 0x31, - 0x20, - 0xFE, - 0x0F, - 0xB3, - 0x15, - 0x9A, - 0x7C, - 0xD5, - 0x5C, - 0xC2, - 0xC0, - 0xEC, - 0xE9, - 0x43, - 0x2B, - 0xD0, - 0x9F, - 0x2C, - 0xFC, - 0xB8, - 0x2B, - 0x6B, - 0x15, - 0xCD, - 0x3F, - 0x0C, - 0xAF, - 0x8F, - 0x68, - 0xB0, - 0x6E, - 0x6B, - 0x30, - 0x2E, - 0x8C, - 0x3F, - 0x7E, - 0x96, - 0x7C, - 0x93, - 0xB2, - 0xA4, - 0x0E, - 0x43, - 0xEA, - 0x20, - 0x10, - 0x38, - 0x6D, - 0x37, - 0xF8, - 0x87, - 0xFE, - 0xA9, - 0x63, - 0x75, - 0xF5, - 0x56, - 0x34, - 0x4A, - 0xE3, - 0xCF, - 0x89, - 0x18, - 0x08, - 0xC2, - 0x76, - 0x74, - 0x12, - 0xEC, - 0xA7, - 0x6D, - 0xC2, - 0xB7, - 0x1B, - 0x7A, - 0xB2, - 0xD4, - 0xED - }; + [Fact] + public void PowerPCConverterDecodeTest() + { + uint ip = 0x6A0; + var testData = ppcData; + BranchExecFilter.PowerPCConverter(testData, ip); + CompareBuffer(testData, ppcResultData); + } - private static byte[] ppcData { get; } = - new byte[] - { - 0xF8, - 0x6B, - 0x2E, - 0x8C, - 0x95, - 0xC5, - 0x4B, - 0x1B, - 0x94, - 0x78, - 0x9E, - 0x7C, - 0xBD, - 0x8B, - 0xA8, - 0xAF, - 0x31, - 0x20, - 0xFE, - 0x0F, - 0xB3, - 0x15, - 0x9A, - 0x7C, - 0xD5, - 0x5C, - 0xC2, - 0xC0, - 0xEC, - 0xE9, - 0x43, - 0x2B, - 0xD0, - 0x9F, - 0x2C, - 0xFC, - 0xB8, - 0x2B, - 0x6B, - 0x15, - 0xCD, - 0x3F, - 0x0C, - 0xAF, - 0x8F, - 0x68, - 0xB0, - 0x6E, - 0x6B, - 0x30, - 0x2E, - 0x8C, - 0x3F, - 0x7E, - 0x96, - 0x7C, - 0x93, - 0xB2, - 0xA4, - 0x0E, - 0x43, - 0xEA, - 0x20, - 0x10, - 0x38, - 0x6D, - 0x37, - 0xF8, - 0x87, - 0xFE, - 0xA9, - 0x63, - 0x75, - 0xF5, - 0x56, - 0x34, - 0x4A, - 0xE3, - 0xD6, - 0x75, - 0x18, - 0x08, - 0xC2, - 0x76, - 0x74, - 0x12, - 0xEC, - 0xA7, - 0x6D, - 0xC2, - 0xB7, - 0x1B, - 0x7A, - 0xB2, - 0xD4, - 0xED - }; + [Fact] + public void ARMConverteDecoderTest() + { + uint ip = 0x3C00; + var testData = armData; + BranchExecFilter.ARMConverter(testData, ip); + CompareBuffer(testData, armResultData); + } - private static byte[] armResultData { get; } = - new byte[] - { - 0x7C, - 0xFC, - 0x0A, - 0x00, - 0x16, - 0x42, - 0x01, - 0x00, - 0x80, - 0xFC, - 0x0A, - 0x00, - 0x16, - 0xB8, - 0x00, - 0x00, - 0x84, - 0xFC, - 0x0A, - 0x00, - 0x16, - 0x3A, - 0x00, - 0x00, - 0x04, - 0xE0, - 0x2D, - 0xE5, - 0x04, - 0xD0, - 0x4D, - 0xE2, - 0x0E, - 0x04, - 0x00, - 0xEB, - 0x04, - 0xD0, - 0x8D, - 0xE2, - 0x04, - 0xE0, - 0x9D, - 0xE4, - 0x1E, - 0xFF, - 0x2F, - 0xE1, - 0x04, - 0xE0, - 0x2D, - 0xE5, - 0x04, - 0xE0, - 0x9F, - 0xE5, - 0x0E, - 0xE0, - 0x8F, - 0xE0, - 0x08, - 0xF0, - 0xBE, - 0xE5, - 0xF0, - 0x3A, - 0x0A, - 0x00, - 0x00, - 0xC6, - 0x8F, - 0xE2, - 0xA3, - 0xCA, - 0x8C, - 0xE2, - 0xF0, - 0xFA, - 0xBC, - 0xE5, - 0x00, - 0xC6, - 0x8F, - 0xE2, - 0xA3, - 0xCA, - 0x8C, - 0xE2, - 0xE8, - 0xFA, - 0xBC, - 0xE5, - 0x00, - 0xC6, - 0x8F, - 0xE2 - }; + [Fact] + public void ARMTConverterDecodeTest() + { + uint ip = 0xA00; + var testData = armtData; + BranchExecFilter.ARMTConverter(testData, ip); + CompareBuffer(testData, armtResultData); + } - private static byte[] armData { get; } = - new byte[] - { - 0x7C, - 0xFC, - 0x0A, - 0x00, - 0x16, - 0x42, - 0x01, - 0x00, - 0x80, - 0xFC, - 0x0A, - 0x00, - 0x16, - 0xB8, - 0x00, - 0x00, - 0x84, - 0xFC, - 0x0A, - 0x00, - 0x16, - 0x3A, - 0x00, - 0x00, - 0x04, - 0xE0, - 0x2D, - 0xE5, - 0x04, - 0xD0, - 0x4D, - 0xE2, - 0x18, - 0x13, - 0x00, - 0xEB, - 0x04, - 0xD0, - 0x8D, - 0xE2, - 0x04, - 0xE0, - 0x9D, - 0xE4, - 0x1E, - 0xFF, - 0x2F, - 0xE1, - 0x04, - 0xE0, - 0x2D, - 0xE5, - 0x04, - 0xE0, - 0x9F, - 0xE5, - 0x0E, - 0xE0, - 0x8F, - 0xE0, - 0x08, - 0xF0, - 0xBE, - 0xE5, - 0xF0, - 0x3A, - 0x0A, - 0x00, - 0x00, - 0xC6, - 0x8F, - 0xE2, - 0xA3, - 0xCA, - 0x8C, - 0xE2, - 0xF0, - 0xFA, - 0xBC, - 0xE5, - 0x00, - 0xC6, - 0x8F, - 0xE2, - 0xA3, - 0xCA, - 0x8C, - 0xE2, - 0xE8, - 0xFA, - 0xBC, - 0xE5, - 0x00, - 0xC6, - 0x8F, - 0xE2 - }; + [Fact] + public void IA64ConverterDecodeTest() + { + uint ip = 0xAA0; + var testData = ia64Data; + BranchExecFilter.IA64Converter(testData, ip); + CompareBuffer(testData, ia64ResultData); + } - private static byte[] armtResultData { get; } = - new byte[] - { - 0x95, - 0x23, - 0xB6, - 0xB1, - 0xBE, - 0x60, - 0x79, - 0xF0, - 0xF6, - 0x01, - 0xD9, - 0x7F, - 0x2E, - 0x03, - 0x31, - 0x1C, - 0xFD, - 0xD3, - 0x40, - 0x0F, - 0x21, - 0x3C, - 0x06, - 0x97, - 0xE5, - 0xC3, - 0x57, - 0x11, - 0x76, - 0x6F, - 0xE3, - 0x70, - 0xED, - 0x49, - 0xCB, - 0xB5, - 0xC9, - 0x42, - 0x59, - 0x10, - 0x2F, - 0xBD, - 0xAE, - 0xB1, - 0x40, - 0x4D, - 0x9D, - 0x7C, - 0xE9, - 0xFC, - 0x48, - 0x3E, - 0xBC, - 0x7F, - 0x0B, - 0x23, - 0xB0, - 0x8A, - 0x4D, - 0x02, - 0x39, - 0xC4, - 0xFB, - 0x66, - 0x83, - 0x7F, - 0xA7, - 0xBD, - 0x12, - 0xAC, - 0xED, - 0x31, - 0x34, - 0x93, - 0x4D, - 0x8D, - 0xD7, - 0x94, - 0x93, - 0x1C, - 0x0A, - 0x50, - 0x54, - 0x4B, - 0x03, - 0x55, - 0x27, - 0xFE, - 0xCE, - 0x29, - 0x66, - 0x52, - 0x81, - 0xAE, - 0x69, - 0xA0, - 0x69, - 0xF2, - 0x3D, - 0xFF, - 0xA1, - 0x8A, - 0x5D, - 0x61, - 0x7D, - 0xC5, - 0x94, - 0x0A, - 0x7D, - 0xED, - 0x11, - 0x0F - }; - - private static byte[] armtData { get; } = - new byte[] - { - 0x95, - 0x23, - 0xB6, - 0xB1, - 0xBE, - 0x60, - 0x79, - 0xF0, - 0xF6, - 0x01, - 0xD9, - 0x7F, - 0x2E, - 0x03, - 0x31, - 0x1C, - 0xFD, - 0xD3, - 0x40, - 0x0F, - 0x21, - 0x3C, - 0x06, - 0x97, - 0xE5, - 0xC3, - 0x57, - 0x11, - 0x76, - 0x6F, - 0xE3, - 0x70, - 0xED, - 0x49, - 0xCB, - 0xB5, - 0xC9, - 0x42, - 0x59, - 0x10, - 0x2F, - 0xBD, - 0xAE, - 0xB1, - 0x40, - 0x4D, - 0x9D, - 0x7C, - 0xE9, - 0xFC, - 0x48, - 0x3E, - 0xBC, - 0x7F, - 0x0B, - 0x23, - 0xB0, - 0x8A, - 0x4D, - 0x02, - 0x39, - 0xC4, - 0xFB, - 0x66, - 0x83, - 0x7F, - 0xA7, - 0xBD, - 0x12, - 0xAC, - 0xED, - 0x31, - 0x34, - 0x93, - 0x4D, - 0x8D, - 0xD7, - 0x94, - 0x93, - 0x1C, - 0x0A, - 0x50, - 0x54, - 0x4B, - 0x03, - 0x55, - 0x27, - 0xFE, - 0xCE, - 0x29, - 0x66, - 0x52, - 0x81, - 0xAE, - 0x69, - 0xA0, - 0x6A, - 0xF2, - 0x6F, - 0xFC, - 0xA1, - 0x8A, - 0x5D, - 0x61, - 0x7D, - 0xC5, - 0x94, - 0x0A, - 0x7D, - 0xED, - 0x11, - 0x0F - }; - - private static byte[] ia64ResultData { get; } = - new byte[] - { - 0x4D, - 0xF8, - 0xF2, - 0x0D, - 0x06, - 0x2F, - 0x74, - 0x0F, - 0xF0, - 0x91, - 0x06, - 0x0B, - 0x19, - 0x22, - 0x91, - 0x5A, - 0x66, - 0x56, - 0xA7, - 0x15, - 0x77, - 0x1E, - 0x2F, - 0xA3, - 0xE4, - 0xDE, - 0x93, - 0x1C, - 0xD5, - 0xCE, - 0x6E, - 0x45, - 0x36, - 0x15, - 0x15, - 0x65, - 0x4E, - 0xC5, - 0xA3, - 0x8C, - 0x5A, - 0x8B, - 0x8A, - 0x1C, - 0x12, - 0x5B, - 0x39, - 0x1F, - 0xA0, - 0xF2, - 0x93, - 0x7C, - 0x7F, - 0x5D, - 0xD9, - 0x30, - 0x1F, - 0xF6, - 0x5C, - 0x10, - 0x62, - 0x3E, - 0xB4, - 0x64, - 0x56, - 0x48, - 0xB2, - 0x20, - 0x39, - 0xE8, - 0x44, - 0x10, - 0x87, - 0x9E, - 0x2C, - 0xFC, - 0x29, - 0x0E, - 0x20, - 0x76, - 0xCE, - 0xDA, - 0x93, - 0x1C, - 0xED, - 0x54, - 0x0D, - 0xAF, - 0xEC, - 0xDE, - 0x93, - 0x1C, - 0x2B, - 0x72, - 0xD5, - 0x0D - }; - - private static byte[] ia64Data { get; } = - new byte[] - { - 0x4D, - 0xF8, - 0xF2, - 0x0D, - 0x06, - 0x2F, - 0x74, - 0x0F, - 0xF0, - 0x91, - 0x06, - 0x0B, - 0x19, - 0x22, - 0x91, - 0x5A, - 0x66, - 0x56, - 0xA7, - 0x15, - 0x77, - 0x1E, - 0x2F, - 0xA3, - 0xE4, - 0xDE, - 0x93, - 0x1C, - 0xD5, - 0xCE, - 0x6E, - 0x45, - 0x36, - 0x15, - 0x15, - 0x65, - 0x4E, - 0xC5, - 0xA3, - 0x8C, - 0x5A, - 0x8B, - 0x8A, - 0x1C, - 0x12, - 0x5B, - 0x39, - 0x1F, - 0xA0, - 0xF2, - 0x93, - 0x7C, - 0x7F, - 0x5D, - 0xD9, - 0x30, - 0x1F, - 0xF6, - 0x5C, - 0x10, - 0x62, - 0x3E, - 0xB4, - 0x64, - 0x56, - 0x48, - 0xB2, - 0x20, - 0x39, - 0xE8, - 0x44, - 0x80, - 0x8C, - 0x9E, - 0x2C, - 0xFC, - 0x29, - 0x0E, - 0x20, - 0x76, - 0xCE, - 0xDA, - 0x93, - 0x1C, - 0xED, - 0x54, - 0x0D, - 0xAF, - 0xEC, - 0xDE, - 0x93, - 0x1C, - 0x2B, - 0x72, - 0xD5, - 0x0D - }; - - private static byte[] sparcResultData { get; } = - new byte[] - { - 0x78, - 0x2E, - 0x73, - 0x6F, - 0x2E, - 0x33, - 0x00, - 0x00, - 0x07, - 0x01, - 0x00, - 0x00, - 0x09, - 0x00, - 0x00, - 0x00, - 0x40, - 0x00, - 0x00, - 0x00, - 0x0B, - 0x00, - 0x00, - 0x00, - 0xA2, - 0x0D, - 0x10, - 0x12, - 0x30, - 0x03, - 0xC9, - 0x37, - 0x40, - 0x1A, - 0x85, - 0xD9, - 0x44, - 0x34, - 0x40, - 0x32, - 0x85, - 0xA0, - 0x30, - 0x40, - 0x00, - 0x70, - 0x00, - 0x40, - 0x84, - 0x80, - 0x04, - 0x00, - 0xE4, - 0xAC, - 0x07, - 0x04, - 0x21, - 0x44, - 0x02, - 0x20, - 0x10, - 0x00, - 0x40, - 0xC2, - 0x89, - 0x98, - 0x85, - 0x00, - 0x58, - 0x6A, - 0x41, - 0x8E, - 0x18, - 0xA1, - 0x91, - 0x00, - 0x10, - 0x00, - }; - - private static byte[] sparcData { get; } = - new byte[] - { - 0x78, - 0x2E, - 0x73, - 0x6F, - 0x2E, - 0x33, - 0x00, - 0x00, - 0x07, - 0x01, - 0x00, - 0x00, - 0x09, - 0x00, - 0x00, - 0x00, - 0x40, - 0x00, - 0x00, - 0x44, - 0x0B, - 0x00, - 0x00, - 0x00, - 0xA2, - 0x0D, - 0x10, - 0x12, - 0x30, - 0x03, - 0xC9, - 0x37, - 0x40, - 0x1A, - 0x86, - 0x21, - 0x44, - 0x34, - 0x40, - 0x32, - 0x85, - 0xA0, - 0x30, - 0x40, - 0x00, - 0x70, - 0x00, - 0x40, - 0x84, - 0x80, - 0x04, - 0x00, - 0xE4, - 0xAC, - 0x07, - 0x04, - 0x21, - 0x44, - 0x02, - 0x20, - 0x10, - 0x00, - 0x40, - 0xC2, - 0x89, - 0x98, - 0x85, - 0x00, - 0x58, - 0x6A, - 0x41, - 0x8E, - 0x18, - 0xA1, - 0x91, - 0x00, - 0x10, - 0x00, - }; - - private void CompareBuffer(byte[] testBuffer, byte[] targetBuffer) - { - Assert.Equal(testBuffer, targetBuffer); - } - - [Fact] - public void X86ConverterDecodeTest() - { - uint state = 0; - uint ip = 0x2000; - var testData = x86Data; - BranchExecFilter.X86Converter(testData, ip, ref state); - CompareBuffer(testData, x86resultData); - } - - [Fact] - public void PowerPCConverterDecodeTest() - { - uint ip = 0x6A0; - var testData = ppcData; - BranchExecFilter.PowerPCConverter(testData, ip); - CompareBuffer(testData, ppcResultData); - } - - [Fact] - public void ARMConverteDecoderTest() - { - uint ip = 0x3C00; - var testData = armData; - BranchExecFilter.ARMConverter(testData, ip); - CompareBuffer(testData, armResultData); - } - - [Fact] - public void ARMTConverterDecodeTest() - { - uint ip = 0xA00; - var testData = armtData; - BranchExecFilter.ARMTConverter(testData, ip); - CompareBuffer(testData, armtResultData); - } - - [Fact] - public void IA64ConverterDecodeTest() - { - uint ip = 0xAA0; - var testData = ia64Data; - BranchExecFilter.IA64Converter(testData, ip); - CompareBuffer(testData, ia64ResultData); - } - - [Fact] - public void SPARCConverterDecodeTest() - { - uint ip = 0x100; - var testData = sparcData; - BranchExecFilter.SPARCConverter(testData, ip); - CompareBuffer(testData, sparcResultData); - } + [Fact] + public void SPARCConverterDecodeTest() + { + uint ip = 0x100; + var testData = sparcData; + BranchExecFilter.SPARCConverter(testData, ip); + CompareBuffer(testData, sparcResultData); } } diff --git a/tests/SharpCompress.Test/GZip/GZipArchiveTests.cs b/tests/SharpCompress.Test/GZip/GZipArchiveTests.cs index cfe0bf51..51ffd019 100644 --- a/tests/SharpCompress.Test/GZip/GZipArchiveTests.cs +++ b/tests/SharpCompress.Test/GZip/GZipArchiveTests.cs @@ -5,127 +5,118 @@ using SharpCompress.Archives; using SharpCompress.Archives.GZip; using Xunit; -namespace SharpCompress.Test.GZip +namespace SharpCompress.Test.GZip; + +public class GZipArchiveTests : ArchiveTests { - public class GZipArchiveTests : ArchiveTests + public GZipArchiveTests() { - public GZipArchiveTests() + UseExtensionInsteadOfNameToVerify = true; + } + + [Fact] + public void GZip_Archive_Generic() + { + using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz"))) + using (var archive = ArchiveFactory.Open(stream)) { - UseExtensionInsteadOfNameToVerify = true; + var entry = archive.Entries.First(); + entry.WriteToFile(Path.Combine(SCRATCH_FILES_PATH, entry.Key)); + + var size = entry.Size; + var scratch = new FileInfo(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar")); + var test = new FileInfo(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar")); + + Assert.Equal(size, scratch.Length); + Assert.Equal(size, test.Length); } + CompareArchivesByPath( + Path.Combine(SCRATCH_FILES_PATH, "Tar.tar"), + Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar") + ); + } - [Fact] - public void GZip_Archive_Generic() + [Fact] + public void GZip_Archive() + { + using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz"))) + using (var archive = GZipArchive.Open(stream)) { - using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz"))) - using (var archive = ArchiveFactory.Open(stream)) - { - var entry = archive.Entries.First(); - entry.WriteToFile(Path.Combine(SCRATCH_FILES_PATH, entry.Key)); + var entry = archive.Entries.First(); + entry.WriteToFile(Path.Combine(SCRATCH_FILES_PATH, entry.Key)); - long size = entry.Size; - var scratch = new FileInfo(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar")); - var test = new FileInfo(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar")); + var size = entry.Size; + var scratch = new FileInfo(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar")); + var test = new FileInfo(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar")); - Assert.Equal(size, scratch.Length); - Assert.Equal(size, test.Length); - } - CompareArchivesByPath( - Path.Combine(SCRATCH_FILES_PATH, "Tar.tar"), - Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar") - ); + Assert.Equal(size, scratch.Length); + Assert.Equal(size, test.Length); } + CompareArchivesByPath( + Path.Combine(SCRATCH_FILES_PATH, "Tar.tar"), + Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar") + ); + } - [Fact] - public void GZip_Archive() + [Fact] + public void GZip_Archive_NoAdd() + { + var jpg = Path.Combine(ORIGINAL_FILES_PATH, "jpg", "test.jpg"); + using Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz")); + using var archive = GZipArchive.Open(stream); + Assert.Throws( + () => archive.AddEntry("jpg\\test.jpg", jpg) + ); + archive.SaveTo(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz")); + } + + [Fact] + public void GZip_Archive_Multiple_Reads() + { + var inputStream = new MemoryStream(); + using (var fileStream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz"))) { - using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz"))) - using (var archive = GZipArchive.Open(stream)) - { - var entry = archive.Entries.First(); - entry.WriteToFile(Path.Combine(SCRATCH_FILES_PATH, entry.Key)); - - long size = entry.Size; - var scratch = new FileInfo(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar")); - var test = new FileInfo(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar")); - - Assert.Equal(size, scratch.Length); - Assert.Equal(size, test.Length); - } - CompareArchivesByPath( - Path.Combine(SCRATCH_FILES_PATH, "Tar.tar"), - Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar") - ); + fileStream.CopyTo(inputStream); + inputStream.Position = 0; } + using var archive = GZipArchive.Open(inputStream); + var archiveEntry = archive.Entries.First(); - [Fact] - public void GZip_Archive_NoAdd() + MemoryStream tarStream; + using (var entryStream = archiveEntry.OpenEntryStream()) { - string jpg = Path.Combine(ORIGINAL_FILES_PATH, "jpg", "test.jpg"); - using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz"))) - using (var archive = GZipArchive.Open(stream)) - { - Assert.Throws( - () => archive.AddEntry("jpg\\test.jpg", jpg) - ); - archive.SaveTo(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz")); - } + tarStream = new MemoryStream(); + entryStream.CopyTo(tarStream); } - - [Fact] - public void GZip_Archive_Multiple_Reads() + var size = tarStream.Length; + using (var entryStream = archiveEntry.OpenEntryStream()) { - var inputStream = new MemoryStream(); - using (var fileStream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz"))) - { - fileStream.CopyTo(inputStream); - inputStream.Position = 0; - } - using (var archive = GZipArchive.Open(inputStream)) - { - var archiveEntry = archive.Entries.First(); - - MemoryStream tarStream; - using (var entryStream = archiveEntry.OpenEntryStream()) - { - tarStream = new MemoryStream(); - entryStream.CopyTo(tarStream); - } - var size = tarStream.Length; - using (var entryStream = archiveEntry.OpenEntryStream()) - { - tarStream = new MemoryStream(); - entryStream.CopyTo(tarStream); - } - Assert.Equal(size, tarStream.Length); - using (var entryStream = archiveEntry.OpenEntryStream()) - { - var result = Archives.Tar.TarArchive.IsTarFile(entryStream); - } - Assert.Equal(size, tarStream.Length); - using (var entryStream = archiveEntry.OpenEntryStream()) - { - tarStream = new MemoryStream(); - entryStream.CopyTo(tarStream); - } - Assert.Equal(size, tarStream.Length); - } + tarStream = new MemoryStream(); + entryStream.CopyTo(tarStream); } - - [Fact] - public void TestGzCrcWithMostSignificaltBitNotNegative() + Assert.Equal(size, tarStream.Length); + using (var entryStream = archiveEntry.OpenEntryStream()) { - using (var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz"))) - { - using (var archive = GZipArchive.Open(stream)) - { - //process all entries in solid archive until the one we want to test - foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) - { - Assert.InRange(entry.Crc, 0L, 0xFFFFFFFFL); - } - } - } + var result = Archives.Tar.TarArchive.IsTarFile(entryStream); + } + Assert.Equal(size, tarStream.Length); + using (var entryStream = archiveEntry.OpenEntryStream()) + { + tarStream = new MemoryStream(); + entryStream.CopyTo(tarStream); + } + Assert.Equal(size, tarStream.Length); + } + + [Fact] + public void TestGzCrcWithMostSignificaltBitNotNegative() + { + using var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz")); + using var archive = GZipArchive.Open(stream); + //process all entries in solid archive until the one we want to test + foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) + { + Assert.InRange(entry.Crc, 0L, 0xFFFFFFFFL); } } } diff --git a/tests/SharpCompress.Test/GZip/GZipReaderTests.cs b/tests/SharpCompress.Test/GZip/GZipReaderTests.cs index a2c8071d..ed65c2a7 100644 --- a/tests/SharpCompress.Test/GZip/GZipReaderTests.cs +++ b/tests/SharpCompress.Test/GZip/GZipReaderTests.cs @@ -1,40 +1,35 @@ -using System.IO; +using System.IO; using SharpCompress.Common; using SharpCompress.IO; using Xunit; -namespace SharpCompress.Test.GZip +namespace SharpCompress.Test.GZip; + +public class GZipReaderTests : ReaderTests { - public class GZipReaderTests : ReaderTests + public GZipReaderTests() { - public GZipReaderTests() - { - UseExtensionInsteadOfNameToVerify = true; - } + UseExtensionInsteadOfNameToVerify = true; + } - [Fact] - public void GZip_Reader_Generic() - { - Read("Tar.tar.gz", CompressionType.GZip); - } + [Fact] + public void GZip_Reader_Generic() + { + Read("Tar.tar.gz", CompressionType.GZip); + } - [Fact] - public void GZip_Reader_Generic2() + [Fact] + public void GZip_Reader_Generic2() + { + //read only as GZip itme + using Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz")); + using var reader = Readers.GZip.GZipReader.Open( + new RewindableStream(stream) + ); + while (reader.MoveToNextEntry()) // Crash here { - //read only as GZip itme - using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz"))) - using ( - var reader = SharpCompress.Readers.GZip.GZipReader.Open( - new RewindableStream(stream) - ) - ) - { - while (reader.MoveToNextEntry()) // Crash here - { - Assert.NotEqual(0, reader.Entry.Size); - Assert.NotEqual(0, reader.Entry.Crc); - } - } + Assert.NotEqual(0, reader.Entry.Size); + Assert.NotEqual(0, reader.Entry.Crc); } } } diff --git a/tests/SharpCompress.Test/GZip/GZipWriterTests.cs b/tests/SharpCompress.Test/GZip/GZipWriterTests.cs index 212e275e..360c5b65 100644 --- a/tests/SharpCompress.Test/GZip/GZipWriterTests.cs +++ b/tests/SharpCompress.Test/GZip/GZipWriterTests.cs @@ -1,91 +1,86 @@ -using System.IO; +using System.IO; using SharpCompress.Common; using SharpCompress.Writers; using SharpCompress.Writers.GZip; using Xunit; -namespace SharpCompress.Test.GZip +namespace SharpCompress.Test.GZip; + +public class GZipWriterTests : WriterTests { - public class GZipWriterTests : WriterTests + public GZipWriterTests() : base(ArchiveType.GZip) { - public GZipWriterTests() : base(ArchiveType.GZip) - { - UseExtensionInsteadOfNameToVerify = true; - } + UseExtensionInsteadOfNameToVerify = true; + } - [Fact] - public void GZip_Writer_Generic() - { - using ( - Stream stream = File.Open( - Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz"), - FileMode.OpenOrCreate, - FileAccess.Write - ) - ) - using (var writer = WriterFactory.Open(stream, ArchiveType.GZip, CompressionType.GZip)) - { - writer.Write("Tar.tar", Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar")); - } - CompareArchivesByPath( + [Fact] + public void GZip_Writer_Generic() + { + using ( + Stream stream = File.Open( Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz"), - Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz") - ); - } - - [Fact] - public void GZip_Writer() - { - using ( - Stream stream = File.Open( - Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz"), - FileMode.OpenOrCreate, - FileAccess.Write - ) + FileMode.OpenOrCreate, + FileAccess.Write ) - using (var writer = new GZipWriter(stream)) - { - writer.Write("Tar.tar", Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar")); - } - CompareArchivesByPath( + ) + using (var writer = WriterFactory.Open(stream, ArchiveType.GZip, CompressionType.GZip)) + { + writer.Write("Tar.tar", Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar")); + } + CompareArchivesByPath( + Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz"), + Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz") + ); + } + + [Fact] + public void GZip_Writer() + { + using ( + Stream stream = File.Open( Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz"), - Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz") - ); - } - - [Fact] - public void GZip_Writer_Generic_Bad_Compression() - { - Assert.Throws(() => - { - using ( - Stream stream = File.OpenWrite(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz")) - ) - using ( - var writer = WriterFactory.Open(stream, ArchiveType.GZip, CompressionType.BZip2) - ) { } - }); - } - - [Fact] - public void GZip_Writer_Entry_Path_With_Dir() - { - using ( - Stream stream = File.Open( - Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz"), - FileMode.OpenOrCreate, - FileAccess.Write - ) + FileMode.OpenOrCreate, + FileAccess.Write ) - using (var writer = new GZipWriter(stream)) - { - var path = Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar"); - writer.Write(path, path); //covers issue #532 - } - CompareArchivesByPath( - Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz"), - Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz") - ); + ) + using (var writer = new GZipWriter(stream)) + { + writer.Write("Tar.tar", Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar")); } + CompareArchivesByPath( + Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz"), + Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz") + ); + } + + [Fact] + public void GZip_Writer_Generic_Bad_Compression() + { + Assert.Throws(() => + { + using Stream stream = File.OpenWrite(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz")); + using var writer = WriterFactory.Open(stream, ArchiveType.GZip, CompressionType.BZip2); + }); + } + + [Fact] + public void GZip_Writer_Entry_Path_With_Dir() + { + using ( + Stream stream = File.Open( + Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz"), + FileMode.OpenOrCreate, + FileAccess.Write + ) + ) + using (var writer = new GZipWriter(stream)) + { + var path = Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar"); + writer.Write(path, path); //covers issue #532 + } + CompareArchivesByPath( + Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz"), + Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz") + ); } } diff --git a/tests/SharpCompress.Test/Mocks/FlushOnDisposeStream.cs b/tests/SharpCompress.Test/Mocks/FlushOnDisposeStream.cs index fb1106d5..5e2c4db2 100644 --- a/tests/SharpCompress.Test/Mocks/FlushOnDisposeStream.cs +++ b/tests/SharpCompress.Test/Mocks/FlushOnDisposeStream.cs @@ -1,69 +1,68 @@ -using System; +using System; using System.IO; -namespace SharpCompress.Test.Mocks +namespace SharpCompress.Test.Mocks; + +// This is a simplified version of CryptoStream that always flushes the inner stream on Dispose to trigger an error in EntryStream +// CryptoStream doesn't always trigger the Flush, so this class is used instead +// See https://referencesource.microsoft.com/#mscorlib/system/security/cryptography/cryptostream.cs,141 + +public class FlushOnDisposeStream : Stream, IDisposable { - // This is a simplified version of CryptoStream that always flushes the inner stream on Dispose to trigger an error in EntryStream - // CryptoStream doesn't always trigger the Flush, so this class is used instead - // See https://referencesource.microsoft.com/#mscorlib/system/security/cryptography/cryptostream.cs,141 + private Stream inner; - public class FlushOnDisposeStream : Stream, IDisposable + public FlushOnDisposeStream(Stream innerStream) { - private Stream inner; + inner = innerStream; + } - public FlushOnDisposeStream(Stream innerStream) + public override bool CanRead => inner.CanRead; + + public override bool CanSeek => false; + + public override bool CanWrite => false; + + public override long Length => inner.Length; + + public override long Position + { + get => inner.Position; + set => inner.Position = value; + } + + public override void Flush() + { + throw new NotImplementedException(); + } + + public override int Read(byte[] buffer, int offset, int count) + { + return inner.Read(buffer, offset, count); + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotImplementedException(); + } + + public override void SetLength(long value) + { + throw new NotImplementedException(); + } + + public override void Write(byte[] buffer, int offset, int count) + { + throw new NotImplementedException(); + } + + protected override void Dispose(bool disposing) + { + if (disposing) { - this.inner = innerStream; + inner.Flush(); + inner.Close(); } - public override bool CanRead => this.inner.CanRead; - - public override bool CanSeek => false; - - public override bool CanWrite => false; - - public override long Length => this.inner.Length; - - public override long Position - { - get => this.inner.Position; - set => this.inner.Position = value; - } - - public override void Flush() - { - throw new NotImplementedException(); - } - - public override int Read(byte[] buffer, int offset, int count) - { - return this.inner.Read(buffer, offset, count); - } - - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotImplementedException(); - } - - public override void SetLength(long value) - { - throw new NotImplementedException(); - } - - public override void Write(byte[] buffer, int offset, int count) - { - throw new NotImplementedException(); - } - - protected override void Dispose(bool disposing) - { - if (disposing) - { - this.inner.Flush(); - this.inner.Close(); - } - - base.Dispose(disposing); - } + base.Dispose(disposing); } } diff --git a/tests/SharpCompress.Test/Mocks/ForwardOnlyStream.cs b/tests/SharpCompress.Test/Mocks/ForwardOnlyStream.cs index 9c10941f..68301db1 100644 --- a/tests/SharpCompress.Test/Mocks/ForwardOnlyStream.cs +++ b/tests/SharpCompress.Test/Mocks/ForwardOnlyStream.cs @@ -1,68 +1,67 @@ -using System; +using System; using System.IO; -namespace SharpCompress.Test.Mocks +namespace SharpCompress.Test.Mocks; + +public class ForwardOnlyStream : Stream { - public class ForwardOnlyStream : Stream + private readonly Stream stream; + + public bool IsDisposed { get; private set; } + + public ForwardOnlyStream(Stream stream) { - private readonly Stream stream; + this.stream = stream; + } - public bool IsDisposed { get; private set; } - - public ForwardOnlyStream(Stream stream) + protected override void Dispose(bool disposing) + { + if (!IsDisposed) { - this.stream = stream; - } - - protected override void Dispose(bool disposing) - { - if (!IsDisposed) + if (disposing) { - if (disposing) - { - stream.Dispose(); - IsDisposed = true; - base.Dispose(disposing); - } + stream.Dispose(); + IsDisposed = true; + base.Dispose(disposing); } } + } - public override bool CanRead => true; + public override bool CanRead => true; - public override bool CanSeek => false; - public override bool CanWrite => false; + public override bool CanSeek => false; + public override bool CanWrite => false; - public override void Flush() - { - throw new NotSupportedException(); - } + public override void Flush() + { + throw new NotSupportedException(); + } - public override long Length => throw new NotSupportedException(); + public override long Length => throw new NotSupportedException(); - public override long Position - { - get => throw new NotSupportedException(); - set => throw new NotSupportedException(); - } + public override long Position + { + get => throw new NotSupportedException(); + set => throw new NotSupportedException(); + } - public override int Read(byte[] buffer, int offset, int count) - { - return stream.Read(buffer, offset, count); - } + public override int Read(byte[] buffer, int offset, int count) + { + return stream.Read(buffer, offset, count); + } - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } - public override void SetLength(long value) - { - throw new NotSupportedException(); - } + public override void SetLength(long value) + { + throw new NotSupportedException(); + } - public override void Write(byte[] buffer, int offset, int count) - { - throw new NotSupportedException(); - } + public override void Write(byte[] buffer, int offset, int count) + { + throw new NotSupportedException(); } } diff --git a/tests/SharpCompress.Test/Mocks/TestStream.cs b/tests/SharpCompress.Test/Mocks/TestStream.cs index 000cf408..3af53901 100644 --- a/tests/SharpCompress.Test/Mocks/TestStream.cs +++ b/tests/SharpCompress.Test/Mocks/TestStream.cs @@ -1,68 +1,67 @@ -using System.IO; +using System.IO; -namespace SharpCompress.Test.Mocks +namespace SharpCompress.Test.Mocks; + +public class TestStream : Stream { - public class TestStream : Stream + private readonly Stream stream; + + public TestStream(Stream stream) + : this(stream, stream.CanRead, stream.CanWrite, stream.CanSeek) { } + + public bool IsDisposed { get; private set; } + + public TestStream(Stream stream, bool read, bool write, bool seek) { - private readonly Stream stream; + this.stream = stream; + CanRead = read; + CanWrite = write; + CanSeek = seek; + } - public TestStream(Stream stream) - : this(stream, stream.CanRead, stream.CanWrite, stream.CanSeek) { } + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + stream.Dispose(); + IsDisposed = true; + } - public bool IsDisposed { get; private set; } + public override bool CanRead { get; } - public TestStream(Stream stream, bool read, bool write, bool seek) - { - this.stream = stream; - CanRead = read; - CanWrite = write; - CanSeek = seek; - } + public override bool CanSeek { get; } - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - stream.Dispose(); - IsDisposed = true; - } + public override bool CanWrite { get; } - public override bool CanRead { get; } + public override void Flush() + { + stream.Flush(); + } - public override bool CanSeek { get; } + public override long Length => stream.Length; - public override bool CanWrite { get; } + public override long Position + { + get => stream.Position; + set => stream.Position = value; + } - public override void Flush() - { - stream.Flush(); - } + public override int Read(byte[] buffer, int offset, int count) + { + return stream.Read(buffer, offset, count); + } - public override long Length => stream.Length; + public override long Seek(long offset, SeekOrigin origin) + { + return stream.Seek(offset, origin); + } - public override long Position - { - get => stream.Position; - set => stream.Position = value; - } + public override void SetLength(long value) + { + stream.SetLength(value); + } - public override int Read(byte[] buffer, int offset, int count) - { - return stream.Read(buffer, offset, count); - } - - public override long Seek(long offset, SeekOrigin origin) - { - return stream.Seek(offset, origin); - } - - public override void SetLength(long value) - { - stream.SetLength(value); - } - - public override void Write(byte[] buffer, int offset, int count) - { - stream.Write(buffer, offset, count); - } + public override void Write(byte[] buffer, int offset, int count) + { + stream.Write(buffer, offset, count); } } diff --git a/tests/SharpCompress.Test/Rar/RarArchiveTests.cs b/tests/SharpCompress.Test/Rar/RarArchiveTests.cs index 6c61215c..af184c77 100644 --- a/tests/SharpCompress.Test/Rar/RarArchiveTests.cs +++ b/tests/SharpCompress.Test/Rar/RarArchiveTests.cs @@ -1,329 +1,88 @@ +using System.Collections.Generic; using System.IO; using System.Linq; +using System.Text; using SharpCompress.Archives; using SharpCompress.Archives.Rar; using SharpCompress.Common; using SharpCompress.Compressors.LZMA.Utilites; +using SharpCompress.Factories; using SharpCompress.Readers; using Xunit; -namespace SharpCompress.Test.Rar +namespace SharpCompress.Test.Rar; + +public class RarArchiveTests : ArchiveTests { - public class RarArchiveTests : ArchiveTests + [Fact] + public void Rar_EncryptedFileAndHeader_Archive() { - [Fact] - public void Rar_EncryptedFileAndHeader_Archive() - { - ReadRarPassword("Rar.encrypted_filesAndHeader.rar", "test"); - } + ReadRarPassword("Rar.encrypted_filesAndHeader.rar", "test"); + } - [Fact] - public void Rar_EncryptedFileAndHeader_NoPasswordExceptionTest() - { - Assert.Throws( - typeof(CryptographicException), - () => ReadRarPassword("Rar.encrypted_filesAndHeader.rar", null) - ); - } + [Fact] + public void Rar_EncryptedFileAndHeader_NoPasswordExceptionTest() + { + Assert.Throws( + typeof(CryptographicException), + () => ReadRarPassword("Rar.encrypted_filesAndHeader.rar", null) + ); + } - /*[Fact] - public void Rar5_EncryptedFileAndHeader_Archive() - { - ReadRarPassword("Rar5.encrypted_filesAndHeader.rar", "test"); - }*/ + /*[Fact] + public void Rar5_EncryptedFileAndHeader_Archive() + { + ReadRarPassword("Rar5.encrypted_filesAndHeader.rar", "test"); + }*/ - [Fact] - public void Rar5_EncryptedFileAndHeader_NoPasswordExceptionTest() - { - Assert.Throws( - typeof(CryptographicException), - () => ReadRarPassword("Rar5.encrypted_filesAndHeader.rar", null) - ); - } + [Fact] + public void Rar5_EncryptedFileAndHeader_NoPasswordExceptionTest() + { + Assert.Throws( + typeof(CryptographicException), + () => ReadRarPassword("Rar5.encrypted_filesAndHeader.rar", null) + ); + } - [Fact] - public void Rar_EncryptedFileOnly_Archive() - { - ReadRarPassword("Rar.encrypted_filesOnly.rar", "test"); - } + [Fact] + public void Rar_EncryptedFileOnly_Archive() + { + ReadRarPassword("Rar.encrypted_filesOnly.rar", "test"); + } - /*[Fact] - public void Rar5_EncryptedFileOnly_Archive() - { - ReadRarPassword("Rar5.encrypted_filesOnly.rar", "test"); - }*/ + /*[Fact] + public void Rar5_EncryptedFileOnly_Archive() + { + ReadRarPassword("Rar5.encrypted_filesOnly.rar", "test"); + }*/ - [Fact] - public void Rar_Encrypted_Archive() - { - ReadRarPassword("Rar.Encrypted.rar", "test"); - } + [Fact] + public void Rar_Encrypted_Archive() + { + ReadRarPassword("Rar.Encrypted.rar", "test"); + } - /*[Fact] - public void Rar5_Encrypted_Archive() - { - ReadRarPassword("Rar5.encrypted_filesAndHeader.rar", "test"); - }*/ + /*[Fact] + public void Rar5_Encrypted_Archive() + { + ReadRarPassword("Rar5.encrypted_filesAndHeader.rar", "test"); + }*/ - private void ReadRarPassword(string testArchive, string? password) - { - using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, testArchive))) - using ( - var archive = RarArchive.Open( - stream, - new ReaderOptions() { Password = password, LeaveStreamOpen = true } - ) + private void ReadRarPassword(string testArchive, string? password) + { + using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, testArchive))) + using ( + var archive = RarArchive.Open( + stream, + new ReaderOptions() { Password = password, LeaveStreamOpen = true } ) + ) + { + foreach (var entry in archive.Entries) { - foreach (var entry in archive.Entries) - { - if (!entry.IsDirectory) - { - Assert.Equal(CompressionType.Rar, entry.CompressionType); - entry.WriteToDirectory( - SCRATCH_FILES_PATH, - new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } - ); - } - } - } - VerifyFiles(); - } - - [Fact] - public void Rar_Multi_Archive_Encrypted() - { - Assert.Throws( - () => ArchiveFileReadPassword("Rar.EncryptedParts.part01.rar", "test") - ); - } - - protected void ArchiveFileReadPassword(string archiveName, string password) - { - using ( - var archive = RarArchive.Open( - Path.Combine(TEST_ARCHIVES_PATH, archiveName), - new ReaderOptions() { Password = password, LeaveStreamOpen = true } - ) - ) - { - foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) - { - entry.WriteToDirectory( - SCRATCH_FILES_PATH, - new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } - ); - } - } - VerifyFiles(); - } - - [Fact] - public void Rar_None_ArchiveStreamRead() - { - ArchiveStreamRead("Rar.none.rar"); - } - - [Fact] - public void Rar5_None_ArchiveStreamRead() - { - ArchiveStreamRead("Rar5.none.rar"); - } - - [Fact] - public void Rar_ArchiveStreamRead() - { - ArchiveStreamRead("Rar.rar"); - } - - [Fact] - public void Rar5_ArchiveStreamRead() - { - ArchiveStreamRead("Rar5.rar"); - } - - [Fact] - public void Rar_test_invalid_exttime_ArchiveStreamRead() - { - DoRar_test_invalid_exttime_ArchiveStreamRead("Rar.test_invalid_exttime.rar"); - } - - private void DoRar_test_invalid_exttime_ArchiveStreamRead(string filename) - { - using (var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, filename))) - { - using (var archive = ArchiveFactory.Open(stream)) - { - foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) - { - entry.WriteToDirectory( - SCRATCH_FILES_PATH, - new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } - ); - } - } - } - } - - [Fact] - public void Rar_Jpg_ArchiveStreamRead() - { - using (var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Rar.jpeg.jpg"))) - { - using ( - var archive = RarArchive.Open( - stream, - new ReaderOptions() { LookForHeader = true } - ) - ) - { - foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) - { - entry.WriteToDirectory( - SCRATCH_FILES_PATH, - new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } - ); - } - } - VerifyFiles(); - } - } - - [Fact] - public void Rar_IsSolidArchiveCheck() - { - DoRar_IsSolidArchiveCheck("Rar.rar"); - } - - [Fact] - public void Rar5_IsSolidArchiveCheck() - { - DoRar_IsSolidArchiveCheck("Rar5.rar"); - } - - private void DoRar_IsSolidArchiveCheck(string filename) - { - using (var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, filename))) - { - using (var archive = RarArchive.Open(stream)) - { - Assert.False(archive.IsSolid); - foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) - { - entry.WriteToDirectory( - SCRATCH_FILES_PATH, - new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } - ); - } - } - } - VerifyFiles(); - } - - [Fact] - public void Rar_IsSolidEntryStreamCheck() - { - DoRar_IsSolidEntryStreamCheck("Rar.solid.rar"); - } - - //Extract the 2nd file in a solid archive to check that the first file is skipped properly - private void DoRar_IsSolidEntryStreamCheck(string filename) - { - using (var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, filename))) - { - using (var archive = RarArchive.Open(stream)) - { - Assert.True(archive.IsSolid); - IArchiveEntry[] entries = archive.Entries.Where(a => !a.IsDirectory).ToArray(); - Assert.NotInRange(entries.Length, 0, 1); - Assert.False(entries[0].IsSolid); //first item in a solid archive is not marked solid and is seekable - IArchiveEntry testEntry = entries[1]; - Assert.True(testEntry.IsSolid); //the target. The non seekable entry - - //process all entries in solid archive until the one we want to test - foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) - { - using (CrcCheckStream crcStream = new CrcCheckStream((uint)entry.Crc)) //use the 7zip CRC stream for convenience (required a bug fix) - { - using (Stream eStream = entry.OpenEntryStream()) //bug fix in RarStream to report the correct Position - eStream.CopyTo(crcStream); - } //throws if not valid - if (entry == testEntry) - break; - } - } - } - } - - [Fact] - public void Rar_Solid_ArchiveStreamRead() - { - ArchiveStreamRead("Rar.solid.rar"); - } - - [Fact] - public void Rar5_Solid_ArchiveStreamRead() - { - ArchiveStreamRead("Rar5.solid.rar"); - } - - [Fact] - public void Rar_Solid_StreamRead_Extract_All() - { - ArchiveStreamReadExtractAll("Rar.solid.rar", CompressionType.Rar); - } - - [Fact] - public void Rar5_Solid_StreamRead_Extract_All() - { - ArchiveStreamReadExtractAll("Rar5.solid.rar", CompressionType.Rar); - } - - [Fact] - public void Rar_Multi_ArchiveStreamRead() - { - DoRar_Multi_ArchiveStreamRead( - new string[] - { - "Rar.multi.part01.rar", - "Rar.multi.part02.rar", - "Rar.multi.part03.rar", - "Rar.multi.part04.rar", - "Rar.multi.part05.rar", - "Rar.multi.part06.rar" - }, - false - ); - } - - [Fact] - public void Rar5_Multi_ArchiveStreamRead() - { - DoRar_Multi_ArchiveStreamRead( - new string[] - { - "Rar5.multi.part01.rar", - "Rar5.multi.part02.rar", - "Rar5.multi.part03.rar", - "Rar5.multi.part04.rar", - "Rar5.multi.part05.rar", - "Rar5.multi.part06.rar" - }, - false - ); - } - - private void DoRar_Multi_ArchiveStreamRead(string[] archives, bool isSolid) - { - using ( - var archive = RarArchive.Open( - archives.Select(s => Path.Combine(TEST_ARCHIVES_PATH, s)).Select(File.OpenRead) - ) - ) - { - Assert.Equal(archive.IsSolid, isSolid); - foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) + if (!entry.IsDirectory) { + Assert.Equal(CompressionType.Rar, entry.CompressionType); entry.WriteToDirectory( SCRATCH_FILES_PATH, new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } @@ -331,336 +90,480 @@ namespace SharpCompress.Test.Rar } } } + VerifyFiles(); + } - [Fact] - public void Rar5_MultiSolid_ArchiveStreamRead() - { - DoRar_Multi_ArchiveStreamRead( - new string[] - { - "Rar.multi.solid.part01.rar", - "Rar.multi.solid.part02.rar", - "Rar.multi.solid.part03.rar", - "Rar.multi.solid.part04.rar", - "Rar.multi.solid.part05.rar", - "Rar.multi.solid.part06.rar" - }, - true - ); - } + [Fact] + public void Rar_Multi_Archive_Encrypted() + { + Assert.Throws( + () => ArchiveFileReadPassword("Rar.EncryptedParts.part01.rar", "test") + ); + } - [Fact] - public void RarNoneArchiveFileRead() - { - ArchiveFileRead("Rar.none.rar"); - } - - [Fact] - public void Rar5NoneArchiveFileRead() - { - ArchiveFileRead("Rar5.none.rar"); - } - - [Fact] - public void Rar_ArchiveFileRead() - { - ArchiveFileRead("Rar.rar"); - } - - [Fact] - public void Rar5_ArchiveFileRead() - { - ArchiveFileRead("Rar5.rar"); - } - - [Fact] - public void Rar_ArchiveFileRead_HasDirectories() - { - DoRar_ArchiveFileRead_HasDirectories("Rar.rar"); - } - - [Fact] - public void Rar5_ArchiveFileRead_HasDirectories() - { - DoRar_ArchiveFileRead_HasDirectories("Rar5.rar"); - } - - private void DoRar_ArchiveFileRead_HasDirectories(string filename) - { - using (var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, filename))) - { - using (var archive = RarArchive.Open(stream)) - { - Assert.False(archive.IsSolid); - Assert.Contains(true, archive.Entries.Select(entry => entry.IsDirectory)); - } - } - } - - [Fact] - public void Rar_Jpg_ArchiveFileRead() - { - using ( - var archive = RarArchive.Open( - Path.Combine(TEST_ARCHIVES_PATH, "Rar.jpeg.jpg"), - new ReaderOptions() { LookForHeader = true } - ) + protected void ArchiveFileReadPassword(string archiveName, string password) + { + using ( + var archive = RarArchive.Open( + Path.Combine(TEST_ARCHIVES_PATH, archiveName), + new ReaderOptions() { Password = password, LeaveStreamOpen = true } ) + ) + { + foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) { - foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) - { - entry.WriteToDirectory( - SCRATCH_FILES_PATH, - new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } - ); - } - } - VerifyFiles(); - } - - [Fact] - public void Rar_Solid_ArchiveFileRead() - { - ArchiveFileRead("Rar.solid.rar"); - } - - [Fact] - public void Rar5_Solid_ArchiveFileRead() - { - ArchiveFileRead("Rar5.solid.rar"); - } - - [Fact] - public void Rar2_Multi_ArchiveStreamRead() - { - DoRar_Multi_ArchiveStreamRead( - new string[] - { - "Rar2.multi.rar", - "Rar2.multi.r00", - "Rar2.multi.r01", - "Rar2.multi.r02", - "Rar2.multi.r03", - "Rar2.multi.r04", - "Rar2.multi.r05" - }, - false - ); - } - - [Fact] - public void Rar2_Multi_ArchiveFileRead() - { - ArchiveFileRead("Rar2.multi.rar"); //r00, r01... - } - - [Fact] - public void Rar2_ArchiveFileRead() - { - ArchiveFileRead("Rar2.rar"); - } - - [Fact] - public void Rar2_ArchiveVersionTest() - { - string testArchive = Path.Combine(TEST_ARCHIVES_PATH, "Rar2.rar"); - - using (var archive = RarArchive.Open(testArchive)) - { - Assert.Equal(2, archive.MinVersion); - Assert.Equal(2, archive.MaxVersion); + entry.WriteToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } + ); } } + VerifyFiles(); + } - [Fact] - public void Rar4_ArchiveVersionTest() + [Fact] + public void Rar_None_ArchiveStreamRead() + { + ArchiveStreamRead("Rar.none.rar"); + } + + [Fact] + public void Rar5_None_ArchiveStreamRead() + { + ArchiveStreamRead("Rar5.none.rar"); + } + + [Fact] + public void Rar_ArchiveStreamRead() + { + ArchiveStreamRead("Rar.rar"); + } + + [Fact] + public void Rar5_ArchiveStreamRead() + { + ArchiveStreamRead("Rar5.rar"); + } + + [Fact] + public void Rar_test_invalid_exttime_ArchiveStreamRead() + { + DoRar_test_invalid_exttime_ArchiveStreamRead("Rar.test_invalid_exttime.rar"); + } + + private void DoRar_test_invalid_exttime_ArchiveStreamRead(string filename) + { + using var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, filename)); + using var archive = ArchiveFactory.Open(stream); + foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) { - string testArchive = Path.Combine(TEST_ARCHIVES_PATH, "Rar4.multi.part01.rar"); + entry.WriteToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } + ); + } + } - using (var archive = RarArchive.Open(testArchive)) + [Fact] + public void Rar_Jpg_ArchiveStreamRead() + { + using var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Rar.jpeg.jpg")); + using ( + var archive = RarArchive.Open( + stream, + new ReaderOptions() { LookForHeader = true } + ) + ) + { + foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) { - Assert.Equal(3, archive.MinVersion); - Assert.Equal(4, archive.MaxVersion); + entry.WriteToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } + ); } } + VerifyFiles(); + } - [Fact] - public void Rar5_ArchiveVersionTest() + [Fact] + public void Rar_IsSolidArchiveCheck() + { + DoRar_IsSolidArchiveCheck("Rar.rar"); + } + + [Fact] + public void Rar5_IsSolidArchiveCheck() + { + DoRar_IsSolidArchiveCheck("Rar5.rar"); + } + + private void DoRar_IsSolidArchiveCheck(string filename) + { + using (var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, filename))) { - string testArchive = Path.Combine(TEST_ARCHIVES_PATH, "Rar5.solid.rar"); - - using (var archive = RarArchive.Open(testArchive)) + using var archive = RarArchive.Open(stream); + Assert.False(archive.IsSolid); + foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) { - Assert.Equal(5, archive.MinVersion); - Assert.Equal(6, archive.MaxVersion); + entry.WriteToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } + ); } } + VerifyFiles(); + } - [Fact] - public void Rar4_Multi_ArchiveFileRead() + [Fact] + public void QuickTest() + { + var textItems = new List(); + using var reader = new RarFactory().OpenReader(new FileInfo("/Users/adam/Downloads/Kuuki_Aether_chinesevcv_1.0.rar").OpenRead(), null); + textItems.Clear(); + while (reader.MoveToNextEntry()) { - ArchiveFileRead("Rar4.multi.part01.rar"); - } - - [Fact] - public void Rar4_ArchiveFileRead() - { - ArchiveFileRead("Rar4.rar"); - } - - [Fact] - public void Rar_GetPartsSplit() - { - //uses first part to search for all parts and compares against this array - ArchiveGetParts( - new string[] + var entry = reader.Entry; + if (!(entry.Key.EndsWith("character.txt") || entry.Key.EndsWith("oto.ini"))) + { + continue; + } + using var stream = reader.OpenEntryStream(); + // Crashes here + using var streamReader = new StreamReader(stream, Encoding.UTF8); + textItems.Add($"------ {entry.Key} ------"); + var count = 0; + while (count < 256 && !streamReader.EndOfStream) + { + var line = streamReader.ReadLine(); + if (!string.IsNullOrWhiteSpace(line)) { - "Rar4.split.001", - "Rar4.split.002", - "Rar4.split.003", - "Rar4.split.004", - "Rar4.split.005", - "Rar4.split.006" + textItems.Add(line); + count++; } + } + + if (!streamReader.EndOfStream) + { + textItems.Add($"..."); + } + } + } + + [Fact] + public void Rar_IsSolidEntryStreamCheck() + { + DoRar_IsSolidEntryStreamCheck("Rar.solid.rar"); + } + + //Extract the 2nd file in a solid archive to check that the first file is skipped properly + private void DoRar_IsSolidEntryStreamCheck(string filename) + { + using var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, filename)); + using var archive = RarArchive.Open(stream); + Assert.True(archive.IsSolid); + IArchiveEntry[] entries = archive.Entries.Where(a => !a.IsDirectory).ToArray(); + Assert.NotInRange(entries.Length, 0, 1); + Assert.False(entries[0].IsSolid); //first item in a solid archive is not marked solid and is seekable + var testEntry = entries[1]; + Assert.True(testEntry.IsSolid); //the target. The non seekable entry + + //process all entries in solid archive until the one we want to test + foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) + { + using (var crcStream = new CrcCheckStream((uint)entry.Crc)) //use the 7zip CRC stream for convenience (required a bug fix) + { + using var eStream = entry.OpenEntryStream(); //bug fix in RarStream to report the correct Position + eStream.CopyTo(crcStream); + } //throws if not valid + if (entry == testEntry) + { + break; + } + } + } + + [Fact] + public void Rar_Solid_ArchiveStreamRead() + { + ArchiveStreamRead("Rar.solid.rar"); + } + + [Fact] + public void Rar5_Solid_ArchiveStreamRead() + { + ArchiveStreamRead("Rar5.solid.rar"); + } + + [Fact] + public void Rar_Solid_StreamRead_Extract_All() + { + ArchiveStreamReadExtractAll("Rar.solid.rar", CompressionType.Rar); + } + + [Fact] + public void Rar5_Solid_StreamRead_Extract_All() + { + ArchiveStreamReadExtractAll("Rar5.solid.rar", CompressionType.Rar); + } + + [Fact] + public void Rar_Multi_ArchiveStreamRead() + { + DoRar_Multi_ArchiveStreamRead( + new string[] + { + "Rar.multi.part01.rar", + "Rar.multi.part02.rar", + "Rar.multi.part03.rar", + "Rar.multi.part04.rar", + "Rar.multi.part05.rar", + "Rar.multi.part06.rar" + }, + false + ); + } + + [Fact] + public void Rar5_Multi_ArchiveStreamRead() + { + DoRar_Multi_ArchiveStreamRead( + new string[] + { + "Rar5.multi.part01.rar", + "Rar5.multi.part02.rar", + "Rar5.multi.part03.rar", + "Rar5.multi.part04.rar", + "Rar5.multi.part05.rar", + "Rar5.multi.part06.rar" + }, + false + ); + } + + private void DoRar_Multi_ArchiveStreamRead(string[] archives, bool isSolid) + { + using var archive = RarArchive.Open( + archives.Select(s => Path.Combine(TEST_ARCHIVES_PATH, s)).Select(File.OpenRead) + ); + Assert.Equal(archive.IsSolid, isSolid); + foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) + { + entry.WriteToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } ); } + } - [Fact] - public void Rar_GetPartsOld() + [Fact] + public void Rar5_MultiSolid_ArchiveStreamRead() + { + DoRar_Multi_ArchiveStreamRead( + new string[] + { + "Rar.multi.solid.part01.rar", + "Rar.multi.solid.part02.rar", + "Rar.multi.solid.part03.rar", + "Rar.multi.solid.part04.rar", + "Rar.multi.solid.part05.rar", + "Rar.multi.solid.part06.rar" + }, + true + ); + } + + [Fact] + public void RarNoneArchiveFileRead() + { + ArchiveFileRead("Rar.none.rar"); + } + + [Fact] + public void Rar5NoneArchiveFileRead() + { + ArchiveFileRead("Rar5.none.rar"); + } + + [Fact] + public void Rar_ArchiveFileRead() + { + ArchiveFileRead("Rar.rar"); + } + + [Fact] + public void Rar5_ArchiveFileRead() + { + ArchiveFileRead("Rar5.rar"); + } + + [Fact] + public void Rar_ArchiveFileRead_HasDirectories() + { + DoRar_ArchiveFileRead_HasDirectories("Rar.rar"); + } + + [Fact] + public void Rar5_ArchiveFileRead_HasDirectories() + { + DoRar_ArchiveFileRead_HasDirectories("Rar5.rar"); + } + + private void DoRar_ArchiveFileRead_HasDirectories(string filename) + { + using var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, filename)); + using var archive = RarArchive.Open(stream); + Assert.False(archive.IsSolid); + Assert.Contains(true, archive.Entries.Select(entry => entry.IsDirectory)); + } + + [Fact] + public void Rar_Jpg_ArchiveFileRead() + { + using ( + var archive = RarArchive.Open( + Path.Combine(TEST_ARCHIVES_PATH, "Rar.jpeg.jpg"), + new ReaderOptions() { LookForHeader = true } + ) + ) { - //uses first part to search for all parts and compares against this array - ArchiveGetParts( - new string[] - { - "Rar2.multi.rar", - "Rar2.multi.r00", - "Rar2.multi.r01", - "Rar2.multi.r02", - "Rar2.multi.r03", - "Rar2.multi.r04", - "Rar2.multi.r05" - } - ); + foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) + { + entry.WriteToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } + ); + } } + VerifyFiles(); + } - [Fact] - public void Rar_GetPartsNew() - { - //uses first part to search for all parts and compares against this array - ArchiveGetParts( - new string[] - { - "Rar4.multi.part01.rar", - "Rar4.multi.part02.rar", - "Rar4.multi.part03.rar", - "Rar4.multi.part04.rar", - "Rar4.multi.part05.rar", - "Rar4.multi.part06.rar", - "Rar4.multi.part07.rar" - } - ); - } + [Fact] + public void Rar_Solid_ArchiveFileRead() + { + ArchiveFileRead("Rar.solid.rar"); + } - [Fact] - public void Rar4_Multi_ArchiveStreamRead() - { - DoRar_Multi_ArchiveStreamRead( - new string[] - { - "Rar4.multi.part01.rar", - "Rar4.multi.part02.rar", - "Rar4.multi.part03.rar", - "Rar4.multi.part04.rar", - "Rar4.multi.part05.rar", - "Rar4.multi.part06.rar", - "Rar4.multi.part07.rar" - }, - false - ); - } + [Fact] + public void Rar5_Solid_ArchiveFileRead() + { + ArchiveFileRead("Rar5.solid.rar"); + } - //no extension to test the lib identifies the archive by content not ext - [Fact] - public void Rar4_Split_ArchiveStreamRead() - { - ArchiveStreamMultiRead( - null, - new string[] - { - "Rar4.split.001", - "Rar4.split.002", - "Rar4.split.003", - "Rar4.split.004", - "Rar4.split.005", - "Rar4.split.006" - } - ); - } + [Fact] + public void Rar2_Multi_ArchiveStreamRead() + { + DoRar_Multi_ArchiveStreamRead( + new string[] + { + "Rar2.multi.rar", + "Rar2.multi.r00", + "Rar2.multi.r01", + "Rar2.multi.r02", + "Rar2.multi.r03", + "Rar2.multi.r04", + "Rar2.multi.r05" + }, + false + ); + } - //will detect and load other files - [Fact] - public void Rar4_Multi_ArchiveFirstFileRead() - { - ArchiveFileRead("Rar4.multi.part01.rar"); - //"Rar4.multi.part02.rar", - //"Rar4.multi.part03.rar", - //"Rar4.multi.part04.rar", - //"Rar4.multi.part05.rar", - //"Rar4.multi.part06.rar", - //"Rar4.multi.part07.rar" - } + [Fact] + public void Rar2_Multi_ArchiveFileRead() + { + ArchiveFileRead("Rar2.multi.rar"); //r00, r01... + } - //will detect and load other files - [Fact] - public void Rar4_Split_ArchiveFirstFileRead() - { - ArchiveFileRead("Rar4.split.001"); - //"Rar4.split.002", - //"Rar4.split.003", - //"Rar4.split.004", - //"Rar4.split.005", - //"Rar4.split.006" - } + [Fact] + public void Rar2_ArchiveFileRead() + { + ArchiveFileRead("Rar2.rar"); + } - //will detect and load other files - [Fact] - public void Rar4_Split_ArchiveStreamFirstFileRead() - { - ArchiveStreamMultiRead( - null, - new string[] - { - "Rar4.split.001", - //"Rar4.split.002", - //"Rar4.split.003", - //"Rar4.split.004", - //"Rar4.split.005", - //"Rar4.split.006" - } - ); - } + [Fact] + public void Rar2_ArchiveVersionTest() + { + var testArchive = Path.Combine(TEST_ARCHIVES_PATH, "Rar2.rar"); - //open with ArchiveFactory.Open and stream - [Fact] - public void Rar4_Split_ArchiveOpen() - { - ArchiveOpenStreamRead( - null, + using var archive = RarArchive.Open(testArchive); + Assert.Equal(2, archive.MinVersion); + Assert.Equal(2, archive.MaxVersion); + } + + [Fact] + public void Rar4_ArchiveVersionTest() + { + var testArchive = Path.Combine(TEST_ARCHIVES_PATH, "Rar4.multi.part01.rar"); + + using var archive = RarArchive.Open(testArchive); + Assert.Equal(3, archive.MinVersion); + Assert.Equal(4, archive.MaxVersion); + } + + [Fact] + public void Rar5_ArchiveVersionTest() + { + var testArchive = Path.Combine(TEST_ARCHIVES_PATH, "Rar5.solid.rar"); + + using var archive = RarArchive.Open(testArchive); + Assert.Equal(5, archive.MinVersion); + Assert.Equal(6, archive.MaxVersion); + } + + [Fact] + public void Rar4_Multi_ArchiveFileRead() + { + ArchiveFileRead("Rar4.multi.part01.rar"); + } + + [Fact] + public void Rar4_ArchiveFileRead() + { + ArchiveFileRead("Rar4.rar"); + } + + [Fact] + public void Rar_GetPartsSplit() + { + //uses first part to search for all parts and compares against this array + ArchiveGetParts( + new string[] + { "Rar4.split.001", "Rar4.split.002", "Rar4.split.003", "Rar4.split.004", "Rar4.split.005", "Rar4.split.006" - ); - } + } + ); + } - //open with ArchiveFactory.Open and stream - [Fact] - public void Rar4_Multi_ArchiveOpen() - { - ArchiveOpenStreamRead( - null, + [Fact] + public void Rar_GetPartsOld() + { + //uses first part to search for all parts and compares against this array + ArchiveGetParts( + new string[] + { + "Rar2.multi.rar", + "Rar2.multi.r00", + "Rar2.multi.r01", + "Rar2.multi.r02", + "Rar2.multi.r03", + "Rar2.multi.r04", + "Rar2.multi.r05" + } + ); + } + + [Fact] + public void Rar_GetPartsNew() + { + //uses first part to search for all parts and compares against this array + ArchiveGetParts( + new string[] + { "Rar4.multi.part01.rar", "Rar4.multi.part02.rar", "Rar4.multi.part03.rar", @@ -668,20 +571,16 @@ namespace SharpCompress.Test.Rar "Rar4.multi.part05.rar", "Rar4.multi.part06.rar", "Rar4.multi.part07.rar" - ); - } + } + ); + } - [Fact] - public void Rar4_Multi_ArchiveOpenEntryVolumeIndexTest() - { - ArchiveOpenEntryVolumeIndexTest( - new[] - { - new[] { 0, 1 }, //exe - Rar4.multi.part01.rar to Rar4.multi.part02.rar - new[] { 1, 5 }, //jpg - Rar4.multi.part02.rar to Rar4.multi.part06.rar - new[] { 5, 6 } //txt - Rar4.multi.part06.rar to Rar4.multi.part07.rar - }, - null, + [Fact] + public void Rar4_Multi_ArchiveStreamRead() + { + DoRar_Multi_ArchiveStreamRead( + new string[] + { "Rar4.multi.part01.rar", "Rar4.multi.part02.rar", "Rar4.multi.part03.rar", @@ -689,63 +588,171 @@ namespace SharpCompress.Test.Rar "Rar4.multi.part05.rar", "Rar4.multi.part06.rar", "Rar4.multi.part07.rar" - ); - } + }, + false + ); + } - [Fact] - public void Rar_Multi_ArchiveFileRead() - { - ArchiveFileRead("Rar.multi.part01.rar"); - } - - [Fact] - public void Rar5_Multi_ArchiveFileRead() - { - ArchiveFileRead("Rar5.multi.part01.rar"); - } - - [Fact] - public void Rar_IsFirstVolume_True() - { - DoRar_IsFirstVolume_True("Rar.multi.part01.rar"); - } - - [Fact] - public void Rar5_IsFirstVolume_True() - { - DoRar_IsFirstVolume_True("Rar5.multi.part01.rar"); - } - - private void DoRar_IsFirstVolume_True(string firstFilename) - { - using (var archive = RarArchive.Open(Path.Combine(TEST_ARCHIVES_PATH, firstFilename))) + //no extension to test the lib identifies the archive by content not ext + [Fact] + public void Rar4_Split_ArchiveStreamRead() + { + ArchiveStreamMultiRead( + null, + new string[] { - Assert.True(archive.IsMultipartVolume()); - Assert.True(archive.IsFirstVolume()); + "Rar4.split.001", + "Rar4.split.002", + "Rar4.split.003", + "Rar4.split.004", + "Rar4.split.005", + "Rar4.split.006" } - } + ); + } - [Fact] - public void Rar_IsFirstVolume_False() - { - DoRar_IsFirstVolume_False("Rar.multi.part03.rar"); - } + //will detect and load other files + [Fact] + public void Rar4_Multi_ArchiveFirstFileRead() + { + ArchiveFileRead("Rar4.multi.part01.rar"); + //"Rar4.multi.part02.rar", + //"Rar4.multi.part03.rar", + //"Rar4.multi.part04.rar", + //"Rar4.multi.part05.rar", + //"Rar4.multi.part06.rar", + //"Rar4.multi.part07.rar" + } - [Fact] - public void Rar5_IsFirstVolume_False() - { - DoRar_IsFirstVolume_False("Rar5.multi.part03.rar"); - } + //will detect and load other files + [Fact] + public void Rar4_Split_ArchiveFirstFileRead() + { + ArchiveFileRead("Rar4.split.001"); + //"Rar4.split.002", + //"Rar4.split.003", + //"Rar4.split.004", + //"Rar4.split.005", + //"Rar4.split.006" + } - private void DoRar_IsFirstVolume_False(string notFirstFilename) - { - using ( - var archive = RarArchive.Open(Path.Combine(TEST_ARCHIVES_PATH, notFirstFilename)) - ) + //will detect and load other files + [Fact] + public void Rar4_Split_ArchiveStreamFirstFileRead() + { + ArchiveStreamMultiRead( + null, + new string[] { - Assert.True(archive.IsMultipartVolume()); - Assert.False(archive.IsFirstVolume()); + "Rar4.split.001", + //"Rar4.split.002", + //"Rar4.split.003", + //"Rar4.split.004", + //"Rar4.split.005", + //"Rar4.split.006" } - } + ); + } + + //open with ArchiveFactory.Open and stream + [Fact] + public void Rar4_Split_ArchiveOpen() + { + ArchiveOpenStreamRead( + null, + "Rar4.split.001", + "Rar4.split.002", + "Rar4.split.003", + "Rar4.split.004", + "Rar4.split.005", + "Rar4.split.006" + ); + } + + //open with ArchiveFactory.Open and stream + [Fact] + public void Rar4_Multi_ArchiveOpen() + { + ArchiveOpenStreamRead( + null, + "Rar4.multi.part01.rar", + "Rar4.multi.part02.rar", + "Rar4.multi.part03.rar", + "Rar4.multi.part04.rar", + "Rar4.multi.part05.rar", + "Rar4.multi.part06.rar", + "Rar4.multi.part07.rar" + ); + } + + [Fact] + public void Rar4_Multi_ArchiveOpenEntryVolumeIndexTest() + { + ArchiveOpenEntryVolumeIndexTest( + new[] + { + new[] { 0, 1 }, //exe - Rar4.multi.part01.rar to Rar4.multi.part02.rar + new[] { 1, 5 }, //jpg - Rar4.multi.part02.rar to Rar4.multi.part06.rar + new[] { 5, 6 } //txt - Rar4.multi.part06.rar to Rar4.multi.part07.rar + }, + null, + "Rar4.multi.part01.rar", + "Rar4.multi.part02.rar", + "Rar4.multi.part03.rar", + "Rar4.multi.part04.rar", + "Rar4.multi.part05.rar", + "Rar4.multi.part06.rar", + "Rar4.multi.part07.rar" + ); + } + + [Fact] + public void Rar_Multi_ArchiveFileRead() + { + ArchiveFileRead("Rar.multi.part01.rar"); + } + + [Fact] + public void Rar5_Multi_ArchiveFileRead() + { + ArchiveFileRead("Rar5.multi.part01.rar"); + } + + [Fact] + public void Rar_IsFirstVolume_True() + { + DoRar_IsFirstVolume_True("Rar.multi.part01.rar"); + } + + [Fact] + public void Rar5_IsFirstVolume_True() + { + DoRar_IsFirstVolume_True("Rar5.multi.part01.rar"); + } + + private void DoRar_IsFirstVolume_True(string firstFilename) + { + using var archive = RarArchive.Open(Path.Combine(TEST_ARCHIVES_PATH, firstFilename)); + Assert.True(archive.IsMultipartVolume()); + Assert.True(archive.IsFirstVolume()); + } + + [Fact] + public void Rar_IsFirstVolume_False() + { + DoRar_IsFirstVolume_False("Rar.multi.part03.rar"); + } + + [Fact] + public void Rar5_IsFirstVolume_False() + { + DoRar_IsFirstVolume_False("Rar5.multi.part03.rar"); + } + + private void DoRar_IsFirstVolume_False(string notFirstFilename) + { + using var archive = RarArchive.Open(Path.Combine(TEST_ARCHIVES_PATH, notFirstFilename)); + Assert.True(archive.IsMultipartVolume()); + Assert.False(archive.IsFirstVolume()); } } diff --git a/tests/SharpCompress.Test/Rar/RarHeaderFactoryTest.cs b/tests/SharpCompress.Test/Rar/RarHeaderFactoryTest.cs index 745935d2..7e4f013a 100644 --- a/tests/SharpCompress.Test/Rar/RarHeaderFactoryTest.cs +++ b/tests/SharpCompress.Test/Rar/RarHeaderFactoryTest.cs @@ -1,71 +1,66 @@ -using System.IO; +using System.IO; using SharpCompress.Common.Rar.Headers; using SharpCompress.IO; using SharpCompress.Readers; using Xunit; -namespace SharpCompress.Test.Rar +namespace SharpCompress.Test.Rar; + +/// +/// Summary description for RarFactoryReaderTest +/// +public class RarHeaderFactoryTest : TestBase { - /// - /// Summary description for RarFactoryReaderTest - /// - public class RarHeaderFactoryTest : TestBase + private readonly RarHeaderFactory rarHeaderFactory; + + public RarHeaderFactoryTest() { - private readonly RarHeaderFactory rarHeaderFactory; + rarHeaderFactory = new RarHeaderFactory( + StreamingMode.Seekable, + new ReaderOptions { LeaveStreamOpen = true } + ); + } - public RarHeaderFactoryTest() - { - rarHeaderFactory = new RarHeaderFactory( - StreamingMode.Seekable, - new ReaderOptions { LeaveStreamOpen = true } + [Fact] + public void Rar_ReadHeaders_RecognizeEncryptedFlag() + { + ReadEncryptedFlag("Rar.encrypted_filesAndHeader.rar", true); + } + + [Fact] + public void Rar5_ReadHeaders_RecognizeEncryptedFlag() + { + ReadEncryptedFlag("Rar5.encrypted_filesAndHeader.rar", true); + } + + [Fact] + public void Rar_ReadHeaders_RecognizeNoEncryptedFlag() + { + ReadEncryptedFlag("Rar.rar", false); + } + + [Fact] + public void Rar5_ReadHeaders_RecognizeNoEncryptedFlag() + { + ReadEncryptedFlag("Rar5.rar", false); + } + + private void ReadEncryptedFlag(string testArchive, bool isEncrypted) + { + using var stream = new FileStream( + Path.Combine(TEST_ARCHIVES_PATH, testArchive), + FileMode.Open, + FileAccess.Read ); - } - - [Fact] - public void Rar_ReadHeaders_RecognizeEncryptedFlag() + foreach (var header in rarHeaderFactory.ReadHeaders(stream)) { - ReadEncryptedFlag("Rar.encrypted_filesAndHeader.rar", true); - } - - [Fact] - public void Rar5_ReadHeaders_RecognizeEncryptedFlag() - { - ReadEncryptedFlag("Rar5.encrypted_filesAndHeader.rar", true); - } - - [Fact] - public void Rar_ReadHeaders_RecognizeNoEncryptedFlag() - { - ReadEncryptedFlag("Rar.rar", false); - } - - [Fact] - public void Rar5_ReadHeaders_RecognizeNoEncryptedFlag() - { - ReadEncryptedFlag("Rar5.rar", false); - } - - private void ReadEncryptedFlag(string testArchive, bool isEncrypted) - { - using ( - var stream = new FileStream( - Path.Combine(TEST_ARCHIVES_PATH, testArchive), - FileMode.Open, - FileAccess.Read - ) + if ( + header.HeaderType == HeaderType.Archive + || header.HeaderType == HeaderType.Crypt ) { - foreach (var header in rarHeaderFactory.ReadHeaders(stream)) - { - if ( - header.HeaderType == HeaderType.Archive - || header.HeaderType == HeaderType.Crypt - ) - { - Assert.Equal(isEncrypted, rarHeaderFactory.IsEncrypted); - break; - } - } + Assert.Equal(isEncrypted, rarHeaderFactory.IsEncrypted); + break; } } } diff --git a/tests/SharpCompress.Test/Rar/RarReaderTests.cs b/tests/SharpCompress.Test/Rar/RarReaderTests.cs index bb841475..15266d6c 100644 --- a/tests/SharpCompress.Test/Rar/RarReaderTests.cs +++ b/tests/SharpCompress.Test/Rar/RarReaderTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; using System.Linq; using SharpCompress.Common; @@ -6,49 +6,89 @@ using SharpCompress.Readers; using SharpCompress.Readers.Rar; using Xunit; -namespace SharpCompress.Test.Rar +namespace SharpCompress.Test.Rar; + +public class RarReaderTests : ReaderTests { - public class RarReaderTests : ReaderTests + [Fact] + public void Rar_Multi_Reader() { - [Fact] - public void Rar_Multi_Reader() - { - DoRar_Multi_Reader( - new string[] - { - "Rar.multi.part01.rar", - "Rar.multi.part02.rar", - "Rar.multi.part03.rar", - "Rar.multi.part04.rar", - "Rar.multi.part05.rar", - "Rar.multi.part06.rar" - } - ); - } + DoRar_Multi_Reader( + new string[] + { + "Rar.multi.part01.rar", + "Rar.multi.part02.rar", + "Rar.multi.part03.rar", + "Rar.multi.part04.rar", + "Rar.multi.part05.rar", + "Rar.multi.part06.rar" + } + ); + } - [Fact] - public void Rar5_Multi_Reader() - { - DoRar_Multi_Reader( - new string[] - { - "Rar5.multi.part01.rar", - "Rar5.multi.part02.rar", - "Rar5.multi.part03.rar", - "Rar5.multi.part04.rar", - "Rar5.multi.part05.rar", - "Rar5.multi.part06.rar" - } - ); - } + [Fact] + public void Rar5_Multi_Reader() + { + DoRar_Multi_Reader( + new string[] + { + "Rar5.multi.part01.rar", + "Rar5.multi.part02.rar", + "Rar5.multi.part03.rar", + "Rar5.multi.part04.rar", + "Rar5.multi.part05.rar", + "Rar5.multi.part06.rar" + } + ); + } - private void DoRar_Multi_Reader(string[] archives) + private void DoRar_Multi_Reader(string[] archives) + { + using ( + var reader = RarReader.Open( + archives + .Select(s => Path.Combine(TEST_ARCHIVES_PATH, s)) + .Select(p => File.OpenRead(p)) + ) + ) + { + while (reader.MoveToNextEntry()) + { + reader.WriteEntryToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } + ); + } + } + VerifyFiles(); + } + + [Fact] + public void Rar_Multi_Reader_Encrypted() + { + DoRar_Multi_Reader_Encrypted( + new string[] + { + "Rar.EncryptedParts.part01.rar", + "Rar.EncryptedParts.part02.rar", + "Rar.EncryptedParts.part03.rar", + "Rar.EncryptedParts.part04.rar", + "Rar.EncryptedParts.part05.rar", + "Rar.EncryptedParts.part06.rar" + } + ); + } + + private void DoRar_Multi_Reader_Encrypted(string[] archives) + { + Assert.Throws(() => { using ( var reader = RarReader.Open( archives .Select(s => Path.Combine(TEST_ARCHIVES_PATH, s)) - .Select(p => File.OpenRead(p)) + .Select(p => File.OpenRead(p)), + new ReaderOptions() { Password = "test" } ) ) { @@ -61,358 +101,305 @@ namespace SharpCompress.Test.Rar } } VerifyFiles(); - } + }); + } - [Fact] - public void Rar_Multi_Reader_Encrypted() - { - DoRar_Multi_Reader_Encrypted( - new string[] - { - "Rar.EncryptedParts.part01.rar", - "Rar.EncryptedParts.part02.rar", - "Rar.EncryptedParts.part03.rar", - "Rar.EncryptedParts.part04.rar", - "Rar.EncryptedParts.part05.rar", - "Rar.EncryptedParts.part06.rar" - } - ); - } - - private void DoRar_Multi_Reader_Encrypted(string[] archives) - { - Assert.Throws(() => + [Fact] + public void Rar_Multi_Reader_Delete_Files() + { + DoRar_Multi_Reader_Delete_Files( + new string[] { - using ( - var reader = RarReader.Open( - archives - .Select(s => Path.Combine(TEST_ARCHIVES_PATH, s)) - .Select(p => File.OpenRead(p)), - new ReaderOptions() { Password = "test" } - ) - ) - { - while (reader.MoveToNextEntry()) - { - reader.WriteEntryToDirectory( - SCRATCH_FILES_PATH, - new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } - ); - } - } - VerifyFiles(); - }); - } + "Rar.multi.part01.rar", + "Rar.multi.part02.rar", + "Rar.multi.part03.rar", + "Rar.multi.part04.rar", + "Rar.multi.part05.rar", + "Rar.multi.part06.rar" + } + ); + } - [Fact] - public void Rar_Multi_Reader_Delete_Files() - { - DoRar_Multi_Reader_Delete_Files( - new string[] - { - "Rar.multi.part01.rar", - "Rar.multi.part02.rar", - "Rar.multi.part03.rar", - "Rar.multi.part04.rar", - "Rar.multi.part05.rar", - "Rar.multi.part06.rar" - } - ); - } - - [Fact] - public void Rar5_Multi_Reader_Delete_Files() - { - DoRar_Multi_Reader_Delete_Files( - new string[] - { - "Rar5.multi.part01.rar", - "Rar5.multi.part02.rar", - "Rar5.multi.part03.rar", - "Rar5.multi.part04.rar", - "Rar5.multi.part05.rar", - "Rar5.multi.part06.rar" - } - ); - } - - private void DoRar_Multi_Reader_Delete_Files(string[] archives) - { - foreach (var file in archives) + [Fact] + public void Rar5_Multi_Reader_Delete_Files() + { + DoRar_Multi_Reader_Delete_Files( + new string[] { - File.Copy( - Path.Combine(TEST_ARCHIVES_PATH, file), - Path.Combine(SCRATCH2_FILES_PATH, file) + "Rar5.multi.part01.rar", + "Rar5.multi.part02.rar", + "Rar5.multi.part03.rar", + "Rar5.multi.part04.rar", + "Rar5.multi.part05.rar", + "Rar5.multi.part06.rar" + } + ); + } + + private void DoRar_Multi_Reader_Delete_Files(string[] archives) + { + foreach (var file in archives) + { + File.Copy( + Path.Combine(TEST_ARCHIVES_PATH, file), + Path.Combine(SCRATCH2_FILES_PATH, file) + ); + } + var streams = archives + .Select(s => Path.Combine(SCRATCH2_FILES_PATH, s)) + .Select(File.OpenRead) + .ToList(); + using (var reader = RarReader.Open(streams)) + { + while (reader.MoveToNextEntry()) + { + reader.WriteEntryToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } ); } - var streams = archives - .Select(s => Path.Combine(SCRATCH2_FILES_PATH, s)) - .Select(File.OpenRead) - .ToList(); - using (var reader = RarReader.Open(streams)) + } + foreach (var stream in streams) + { + stream.Dispose(); + } + VerifyFiles(); + + foreach (var file in archives.Select(s => Path.Combine(SCRATCH2_FILES_PATH, s))) + { + File.Delete(file); + } + } + + [Fact] + public void Rar_None_Reader() + { + Read("Rar.none.rar", CompressionType.Rar); + } + + [Fact] + public void Rar5_None_Reader() + { + Read("Rar5.none.rar", CompressionType.Rar); + } + + [Fact] + public void Rar_Reader() + { + Read("Rar.rar", CompressionType.Rar); + } + + [Fact] + public void Rar5_Reader() + { + Read("Rar5.rar", CompressionType.Rar); + } + + [Fact] + public void Rar_EncryptedFileAndHeader_Reader() + { + ReadRar("Rar.encrypted_filesAndHeader.rar", "test"); + } + + /*[Fact] + public void Rar5_EncryptedFileAndHeader_Reader() + { + ReadRar("Rar5.encrypted_filesAndHeader.rar", "test"); + }*/ + + [Fact] + public void Rar_EncryptedFileOnly_Reader() + { + ReadRar("Rar.encrypted_filesOnly.rar", "test"); + } + + /*[Fact] + public void Rar5_EncryptedFileOnly_Reader() + { + ReadRar("Rar5.encrypted_filesOnly.rar", "test"); + }*/ + + [Fact] + public void Rar_Encrypted_Reader() + { + ReadRar("Rar.Encrypted.rar", "test"); + } + + /*[Fact] + public void Rar5_Encrypted_Reader() + { + ReadRar("Rar5.encrypted_filesOnly.rar", "test"); + }*/ + + private void ReadRar(string testArchive, string password) + { + Read(testArchive, CompressionType.Rar, new ReaderOptions { Password = password }); + } + + [Fact] + public void Rar_Entry_Stream() + { + DoRar_Entry_Stream("Rar.rar"); + } + + [Fact] + public void Rar5_Entry_Stream() + { + DoRar_Entry_Stream("Rar5.rar"); + } + + private void DoRar_Entry_Stream(string filename) + { + using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, filename))) + using (var reader = ReaderFactory.Open(stream)) + { + while (reader.MoveToNextEntry()) { - while (reader.MoveToNextEntry()) - { - reader.WriteEntryToDirectory( - SCRATCH_FILES_PATH, - new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } - ); - } - } - foreach (var stream in streams) - { - stream.Dispose(); - } - VerifyFiles(); - - foreach (var file in archives.Select(s => Path.Combine(SCRATCH2_FILES_PATH, s))) - { - File.Delete(file); - } - } - - [Fact] - public void Rar_None_Reader() - { - Read("Rar.none.rar", CompressionType.Rar); - } - - [Fact] - public void Rar5_None_Reader() - { - Read("Rar5.none.rar", CompressionType.Rar); - } - - [Fact] - public void Rar_Reader() - { - Read("Rar.rar", CompressionType.Rar); - } - - [Fact] - public void Rar5_Reader() - { - Read("Rar5.rar", CompressionType.Rar); - } - - [Fact] - public void Rar_EncryptedFileAndHeader_Reader() - { - ReadRar("Rar.encrypted_filesAndHeader.rar", "test"); - } - - /*[Fact] - public void Rar5_EncryptedFileAndHeader_Reader() - { - ReadRar("Rar5.encrypted_filesAndHeader.rar", "test"); - }*/ - - [Fact] - public void Rar_EncryptedFileOnly_Reader() - { - ReadRar("Rar.encrypted_filesOnly.rar", "test"); - } - - /*[Fact] - public void Rar5_EncryptedFileOnly_Reader() - { - ReadRar("Rar5.encrypted_filesOnly.rar", "test"); - }*/ - - [Fact] - public void Rar_Encrypted_Reader() - { - ReadRar("Rar.Encrypted.rar", "test"); - } - - /*[Fact] - public void Rar5_Encrypted_Reader() - { - ReadRar("Rar5.encrypted_filesOnly.rar", "test"); - }*/ - - private void ReadRar(string testArchive, string password) - { - Read(testArchive, CompressionType.Rar, new ReaderOptions { Password = password }); - } - - [Fact] - public void Rar_Entry_Stream() - { - DoRar_Entry_Stream("Rar.rar"); - } - - [Fact] - public void Rar5_Entry_Stream() - { - DoRar_Entry_Stream("Rar5.rar"); - } - - private void DoRar_Entry_Stream(string filename) - { - using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, filename))) - using (var reader = ReaderFactory.Open(stream)) - { - while (reader.MoveToNextEntry()) - { - if (!reader.Entry.IsDirectory) - { - Assert.Equal(CompressionType.Rar, reader.Entry.CompressionType); - using (var entryStream = reader.OpenEntryStream()) - { - string file = Path.GetFileName(reader.Entry.Key); - string folder = - Path.GetDirectoryName(reader.Entry.Key) - ?? throw new ArgumentNullException(); - string destdir = Path.Combine(SCRATCH_FILES_PATH, folder); - if (!Directory.Exists(destdir)) - { - Directory.CreateDirectory(destdir); - } - string destinationFileName = Path.Combine(destdir, file); - - using (FileStream fs = File.OpenWrite(destinationFileName)) - { - entryStream.TransferTo(fs); - } - } - } - } - } - VerifyFiles(); - } - - [Fact] - public void Rar_Reader_Audio_program() - { - using ( - var stream = File.OpenRead( - Path.Combine(TEST_ARCHIVES_PATH, "Rar.Audio_program.rar") - ) - ) - using ( - var reader = ReaderFactory.Open( - stream, - new ReaderOptions() { LookForHeader = true } - ) - ) - { - while (reader.MoveToNextEntry()) + if (!reader.Entry.IsDirectory) { Assert.Equal(CompressionType.Rar, reader.Entry.CompressionType); - reader.WriteEntryToDirectory( - SCRATCH_FILES_PATH, - new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } - ); + using var entryStream = reader.OpenEntryStream(); + var file = Path.GetFileName(reader.Entry.Key); + var folder = + Path.GetDirectoryName(reader.Entry.Key) + ?? throw new ArgumentNullException(); + var destdir = Path.Combine(SCRATCH_FILES_PATH, folder); + if (!Directory.Exists(destdir)) + { + Directory.CreateDirectory(destdir); + } + var destinationFileName = Path.Combine(destdir, file); + + using var fs = File.OpenWrite(destinationFileName); + entryStream.TransferTo(fs); } } - CompareFilesByPath( - Path.Combine(SCRATCH_FILES_PATH, "test.dat"), - Path.Combine(MISC_TEST_FILES_PATH, "test.dat") + } + VerifyFiles(); + } + + [Fact] + public void Rar_Reader_Audio_program() + { + using ( + var stream = File.OpenRead( + Path.Combine(TEST_ARCHIVES_PATH, "Rar.Audio_program.rar") + ) + ) + using ( + var reader = ReaderFactory.Open( + stream, + new ReaderOptions() { LookForHeader = true } + ) + ) + { + while (reader.MoveToNextEntry()) + { + Assert.Equal(CompressionType.Rar, reader.Entry.CompressionType); + reader.WriteEntryToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } + ); + } + } + CompareFilesByPath( + Path.Combine(SCRATCH_FILES_PATH, "test.dat"), + Path.Combine(MISC_TEST_FILES_PATH, "test.dat") + ); + } + + [Fact] + public void Rar_Jpg_Reader() + { + using (var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Rar.jpeg.jpg"))) + using ( + var reader = RarReader.Open(stream, new ReaderOptions() { LookForHeader = true }) + ) + { + while (reader.MoveToNextEntry()) + { + Assert.Equal(CompressionType.Rar, reader.Entry.CompressionType); + reader.WriteEntryToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } + ); + } + } + VerifyFiles(); + } + + [Fact] + public void Rar_Solid_Reader() + { + Read("Rar.solid.rar", CompressionType.Rar); + } + + [Fact] + public void Rar5_Solid_Reader() + { + Read("Rar5.solid.rar", CompressionType.Rar); + } + + [Fact] + public void Rar_Solid_Skip_Reader() + { + DoRar_Solid_Skip_Reader("Rar.solid.rar"); + } + + [Fact] + public void Rar5_Solid_Skip_Reader() + { + DoRar_Solid_Skip_Reader("Rar5.solid.rar"); + } + + private void DoRar_Solid_Skip_Reader(string filename) + { + using var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, filename)); + using var reader = ReaderFactory.Open( + stream, + new ReaderOptions() { LookForHeader = true } ); - } - - [Fact] - public void Rar_Jpg_Reader() + while (reader.MoveToNextEntry()) { - using (var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Rar.jpeg.jpg"))) - using ( - var reader = RarReader.Open(stream, new ReaderOptions() { LookForHeader = true }) - ) + if (reader.Entry.Key.Contains("jpg")) { - while (reader.MoveToNextEntry()) - { - Assert.Equal(CompressionType.Rar, reader.Entry.CompressionType); - reader.WriteEntryToDirectory( - SCRATCH_FILES_PATH, - new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } - ); - } - } - VerifyFiles(); - } - - [Fact] - public void Rar_Solid_Reader() - { - Read("Rar.solid.rar", CompressionType.Rar); - } - - [Fact] - public void Rar5_Solid_Reader() - { - Read("Rar5.solid.rar", CompressionType.Rar); - } - - [Fact] - public void Rar_Solid_Skip_Reader() - { - DoRar_Solid_Skip_Reader("Rar.solid.rar"); - } - - [Fact] - public void Rar5_Solid_Skip_Reader() - { - DoRar_Solid_Skip_Reader("Rar5.solid.rar"); - } - - private void DoRar_Solid_Skip_Reader(string filename) - { - using (var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, filename))) - using ( - var reader = ReaderFactory.Open( - stream, - new ReaderOptions() { LookForHeader = true } - ) - ) - { - while (reader.MoveToNextEntry()) - { - if (reader.Entry.Key.Contains("jpg")) - { - Assert.Equal(CompressionType.Rar, reader.Entry.CompressionType); - reader.WriteEntryToDirectory( - SCRATCH_FILES_PATH, - new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } - ); - } - } + Assert.Equal(CompressionType.Rar, reader.Entry.CompressionType); + reader.WriteEntryToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } + ); } } + } - [Fact] - public void Rar_Reader_Skip() - { - DoRar_Reader_Skip("Rar.rar"); - } + [Fact] + public void Rar_Reader_Skip() + { + DoRar_Reader_Skip("Rar.rar"); + } - [Fact] - public void Rar5_Reader_Skip() - { - DoRar_Reader_Skip("Rar5.rar"); - } + [Fact] + public void Rar5_Reader_Skip() + { + DoRar_Reader_Skip("Rar5.rar"); + } - private void DoRar_Reader_Skip(string filename) + private void DoRar_Reader_Skip(string filename) + { + using var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, filename)); + using var reader = ReaderFactory.Open( + stream, + new ReaderOptions() { LookForHeader = true } + ); + while (reader.MoveToNextEntry()) { - using (var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, filename))) - using ( - var reader = ReaderFactory.Open( - stream, - new ReaderOptions() { LookForHeader = true } - ) - ) + if (reader.Entry.Key.Contains("jpg")) { - while (reader.MoveToNextEntry()) - { - if (reader.Entry.Key.Contains("jpg")) - { - Assert.Equal(CompressionType.Rar, reader.Entry.CompressionType); - reader.WriteEntryToDirectory( - SCRATCH_FILES_PATH, - new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } - ); - } - } + Assert.Equal(CompressionType.Rar, reader.Entry.CompressionType); + reader.WriteEntryToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } + ); } } } diff --git a/tests/SharpCompress.Test/ReaderTests.cs b/tests/SharpCompress.Test/ReaderTests.cs index 8d02d1e6..eb0de103 100644 --- a/tests/SharpCompress.Test/ReaderTests.cs +++ b/tests/SharpCompress.Test/ReaderTests.cs @@ -5,77 +5,68 @@ using SharpCompress.Readers; using SharpCompress.Test.Mocks; using Xunit; -namespace SharpCompress.Test +namespace SharpCompress.Test; + +public abstract class ReaderTests : TestBase { - public abstract class ReaderTests : TestBase + protected void Read( + string testArchive, + CompressionType expectedCompression, + ReaderOptions? options = null + ) { - protected void Read( - string testArchive, - CompressionType expectedCompression, - ReaderOptions? options = null - ) + testArchive = Path.Combine(TEST_ARCHIVES_PATH, testArchive); + + options ??= new ReaderOptions(); + + options.LeaveStreamOpen = true; + ReadImpl(testArchive, expectedCompression, options); + + options.LeaveStreamOpen = false; + ReadImpl(testArchive, expectedCompression, options); + VerifyFiles(); + } + + private void ReadImpl( + string testArchive, + CompressionType expectedCompression, + ReaderOptions options + ) + { + using var file = File.OpenRead(testArchive); + using var protectedStream = NonDisposingStream.Create( + new ForwardOnlyStream(file), + throwOnDispose: true + ); + using var testStream = new TestStream(protectedStream); + using (var reader = ReaderFactory.Open(testStream, options)) { - testArchive = Path.Combine(TEST_ARCHIVES_PATH, testArchive); - - options = options ?? new ReaderOptions(); - - options.LeaveStreamOpen = true; - ReadImpl(testArchive, expectedCompression, options); - - options.LeaveStreamOpen = false; - ReadImpl(testArchive, expectedCompression, options); - VerifyFiles(); + UseReader(reader, expectedCompression); + protectedStream.ThrowOnDispose = false; + Assert.False( + testStream.IsDisposed, + "{nameof(testStream)} prematurely closed" + ); } - private void ReadImpl( - string testArchive, - CompressionType expectedCompression, - ReaderOptions options - ) - { - using (var file = File.OpenRead(testArchive)) - { - using ( - var protectedStream = NonDisposingStream.Create( - new ForwardOnlyStream(file), - throwOnDispose: true - ) - ) - { - using (var testStream = new TestStream(protectedStream)) - { - using (var reader = ReaderFactory.Open(testStream, options)) - { - UseReader(reader, expectedCompression); - protectedStream.ThrowOnDispose = false; - Assert.False( - testStream.IsDisposed, - "{nameof(testStream)} prematurely closed" - ); - } + // Boolean XOR -- If the stream should be left open (true), then the stream should not be diposed (false) + // and if the stream should be closed (false), then the stream should be disposed (true) + var message = + $"{nameof(options.LeaveStreamOpen)} is set to '{options.LeaveStreamOpen}', so {nameof(testStream.IsDisposed)} should be set to '{!testStream.IsDisposed}', but is set to {testStream.IsDisposed}"; + Assert.True(options.LeaveStreamOpen != testStream.IsDisposed, message); + } - // Boolean XOR -- If the stream should be left open (true), then the stream should not be diposed (false) - // and if the stream should be closed (false), then the stream should be disposed (true) - var message = - $"{nameof(options.LeaveStreamOpen)} is set to '{options.LeaveStreamOpen}', so {nameof(testStream.IsDisposed)} should be set to '{!testStream.IsDisposed}', but is set to {testStream.IsDisposed}"; - Assert.True(options.LeaveStreamOpen != testStream.IsDisposed, message); - } - } - } - } - - public void UseReader(IReader reader, CompressionType expectedCompression) + public void UseReader(IReader reader, CompressionType expectedCompression) + { + while (reader.MoveToNextEntry()) { - while (reader.MoveToNextEntry()) + if (!reader.Entry.IsDirectory) { - if (!reader.Entry.IsDirectory) - { - Assert.Equal(expectedCompression, reader.Entry.CompressionType); - reader.WriteEntryToDirectory( - SCRATCH_FILES_PATH, - new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } - ); - } + Assert.Equal(expectedCompression, reader.Entry.CompressionType); + reader.WriteEntryToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } + ); } } } diff --git a/tests/SharpCompress.Test/SevenZip/SevenZipArchiveTests.cs b/tests/SharpCompress.Test/SevenZip/SevenZipArchiveTests.cs index 4532a613..c988d1c2 100644 --- a/tests/SharpCompress.Test/SevenZip/SevenZipArchiveTests.cs +++ b/tests/SharpCompress.Test/SevenZip/SevenZipArchiveTests.cs @@ -3,163 +3,162 @@ using SharpCompress.Common; using SharpCompress.Readers; using Xunit; -namespace SharpCompress.Test.SevenZip +namespace SharpCompress.Test.SevenZip; + +public class SevenZipArchiveTests : ArchiveTests { - public class SevenZipArchiveTests : ArchiveTests + [Fact] + public void SevenZipArchive_Solid_StreamRead() { - [Fact] - public void SevenZipArchive_Solid_StreamRead() - { - ArchiveStreamRead("7Zip.solid.7z"); - } + ArchiveStreamRead("7Zip.solid.7z"); + } - [Fact] - public void SevenZipArchive_NonSolid_StreamRead() - { - ArchiveStreamRead("7Zip.nonsolid.7z"); - } + [Fact] + public void SevenZipArchive_NonSolid_StreamRead() + { + ArchiveStreamRead("7Zip.nonsolid.7z"); + } - [Fact] - public void SevenZipArchive_LZMA_StreamRead() - { - ArchiveStreamRead("7Zip.LZMA.7z"); - } + [Fact] + public void SevenZipArchive_LZMA_StreamRead() + { + ArchiveStreamRead("7Zip.LZMA.7z"); + } - [Fact] - public void SevenZipArchive_LZMA_PathRead() - { - ArchiveFileRead("7Zip.LZMA.7z"); - } + [Fact] + public void SevenZipArchive_LZMA_PathRead() + { + ArchiveFileRead("7Zip.LZMA.7z"); + } - [Fact] - public void SevenZipArchive_LZMAAES_StreamRead() - { - ArchiveStreamRead( - "7Zip.LZMA.Aes.7z", - new ReaderOptions() { Password = "testpassword" } - ); - } + [Fact] + public void SevenZipArchive_LZMAAES_StreamRead() + { + ArchiveStreamRead( + "7Zip.LZMA.Aes.7z", + new ReaderOptions() { Password = "testpassword" } + ); + } - [Fact] - public void SevenZipArchive_LZMAAES_PathRead() - { - ArchiveFileRead("7Zip.LZMA.Aes.7z", new ReaderOptions() { Password = "testpassword" }); - } + [Fact] + public void SevenZipArchive_LZMAAES_PathRead() + { + ArchiveFileRead("7Zip.LZMA.Aes.7z", new ReaderOptions() { Password = "testpassword" }); + } - [Fact] - public void SevenZipArchive_LZMAAES_NoPasswordExceptionTest() - { - Assert.Throws( - typeof(CryptographicException), - () => ArchiveFileRead("7Zip.LZMA.Aes.7z", new ReaderOptions() { Password = null }) - ); //was failing with ArgumentNullException not CryptographicException like rar - } + [Fact] + public void SevenZipArchive_LZMAAES_NoPasswordExceptionTest() + { + Assert.Throws( + typeof(CryptographicException), + () => ArchiveFileRead("7Zip.LZMA.Aes.7z", new ReaderOptions() { Password = null }) + ); //was failing with ArgumentNullException not CryptographicException like rar + } - [Fact] - public void SevenZipArchive_PPMd_StreamRead() - { - ArchiveStreamRead("7Zip.PPMd.7z"); - } + [Fact] + public void SevenZipArchive_PPMd_StreamRead() + { + ArchiveStreamRead("7Zip.PPMd.7z"); + } - [Fact] - public void SevenZipArchive_PPMd_StreamRead_Extract_All() - { - ArchiveStreamReadExtractAll("7Zip.PPMd.7z", CompressionType.PPMd); - } + [Fact] + public void SevenZipArchive_PPMd_StreamRead_Extract_All() + { + ArchiveStreamReadExtractAll("7Zip.PPMd.7z", CompressionType.PPMd); + } - [Fact] - public void SevenZipArchive_PPMd_PathRead() - { - ArchiveFileRead("7Zip.PPMd.7z"); - } + [Fact] + public void SevenZipArchive_PPMd_PathRead() + { + ArchiveFileRead("7Zip.PPMd.7z"); + } - [Fact] - public void SevenZipArchive_LZMA2_StreamRead() - { - ArchiveStreamRead("7Zip.LZMA2.7z"); - } + [Fact] + public void SevenZipArchive_LZMA2_StreamRead() + { + ArchiveStreamRead("7Zip.LZMA2.7z"); + } - [Fact] - public void SevenZipArchive_LZMA2_PathRead() - { - ArchiveFileRead("7Zip.LZMA2.7z"); - } + [Fact] + public void SevenZipArchive_LZMA2_PathRead() + { + ArchiveFileRead("7Zip.LZMA2.7z"); + } - [Fact] - public void SevenZipArchive_LZMA2AES_StreamRead() - { - ArchiveStreamRead("7Zip.LZMA2.Aes.7z", new ReaderOptions { Password = "testpassword" }); - } + [Fact] + public void SevenZipArchive_LZMA2AES_StreamRead() + { + ArchiveStreamRead("7Zip.LZMA2.Aes.7z", new ReaderOptions { Password = "testpassword" }); + } - [Fact] - public void SevenZipArchive_LZMA2AES_PathRead() - { - ArchiveFileRead("7Zip.LZMA2.Aes.7z", new ReaderOptions { Password = "testpassword" }); - } + [Fact] + public void SevenZipArchive_LZMA2AES_PathRead() + { + ArchiveFileRead("7Zip.LZMA2.Aes.7z", new ReaderOptions { Password = "testpassword" }); + } - [Fact] - public void SevenZipArchive_BZip2_StreamRead() - { - ArchiveStreamRead("7Zip.BZip2.7z"); - } + [Fact] + public void SevenZipArchive_BZip2_StreamRead() + { + ArchiveStreamRead("7Zip.BZip2.7z"); + } - [Fact] - public void SevenZipArchive_BZip2_PathRead() - { - ArchiveFileRead("7Zip.BZip2.7z"); - } + [Fact] + public void SevenZipArchive_BZip2_PathRead() + { + ArchiveFileRead("7Zip.BZip2.7z"); + } - [Fact] - public void SevenZipArchive_LZMA_Time_Attributes_PathRead() - { - ArchiveFileReadEx("7Zip.LZMA.7z"); - } + [Fact] + public void SevenZipArchive_LZMA_Time_Attributes_PathRead() + { + ArchiveFileReadEx("7Zip.LZMA.7z"); + } - [Fact] - public void SevenZipArchive_BZip2_Split() - { - Assert.Throws( - () => - ArchiveStreamRead( - null, - "Original.7z.001", - "Original.7z.002", - "Original.7z.003", - "Original.7z.004", - "Original.7z.005", - "Original.7z.006", - "Original.7z.007" - ) - ); - } + [Fact] + public void SevenZipArchive_BZip2_Split() + { + Assert.Throws( + () => + ArchiveStreamRead( + null, + "Original.7z.001", + "Original.7z.002", + "Original.7z.003", + "Original.7z.004", + "Original.7z.005", + "Original.7z.006", + "Original.7z.007" + ) + ); + } - //Same as archive as Original.7z.001 ... 007 files without the root directory 'Original\' in the archive - this caused the verify to fail - [Fact] - public void SevenZipArchive_BZip2_Split_Working() - { - ArchiveStreamMultiRead( - null, - "7Zip.BZip2.split.001", - "7Zip.BZip2.split.002", - "7Zip.BZip2.split.003", - "7Zip.BZip2.split.004", - "7Zip.BZip2.split.005", - "7Zip.BZip2.split.006", - "7Zip.BZip2.split.007" - ); - } + //Same as archive as Original.7z.001 ... 007 files without the root directory 'Original\' in the archive - this caused the verify to fail + [Fact] + public void SevenZipArchive_BZip2_Split_Working() + { + ArchiveStreamMultiRead( + null, + "7Zip.BZip2.split.001", + "7Zip.BZip2.split.002", + "7Zip.BZip2.split.003", + "7Zip.BZip2.split.004", + "7Zip.BZip2.split.005", + "7Zip.BZip2.split.006", + "7Zip.BZip2.split.007" + ); + } - //will detect and load other files - [Fact] - public void SevenZipArchive_BZip2_Split_FirstFileRead() - { - ArchiveFileRead("7Zip.BZip2.split.001"); - //"7Zip.BZip2.split.002", - //"7Zip.BZip2.split.003", - //"7Zip.BZip2.split.004", - //"7Zip.BZip2.split.005", - //"7Zip.BZip2.split.006", - //"7Zip.BZip2.split.007" - } + //will detect and load other files + [Fact] + public void SevenZipArchive_BZip2_Split_FirstFileRead() + { + ArchiveFileRead("7Zip.BZip2.split.001"); + //"7Zip.BZip2.split.002", + //"7Zip.BZip2.split.003", + //"7Zip.BZip2.split.004", + //"7Zip.BZip2.split.005", + //"7Zip.BZip2.split.006", + //"7Zip.BZip2.split.007" } } diff --git a/tests/SharpCompress.Test/Streams/LzmaStreamTests.cs b/tests/SharpCompress.Test/Streams/LzmaStreamTests.cs index 54ac757b..ad97cdd4 100644 --- a/tests/SharpCompress.Test/Streams/LzmaStreamTests.cs +++ b/tests/SharpCompress.Test/Streams/LzmaStreamTests.cs @@ -3,532 +3,529 @@ using System.IO; using SharpCompress.Compressors.LZMA; using Xunit; -namespace SharpCompress.Test.Streams +namespace SharpCompress.Test.Streams; + +public class LzmaStreamTests { - public class LzmaStreamTests + [Fact] + public void TestLzma2Decompress1Byte() { - [Fact] - public void TestLzma2Decompress1Byte() + var properties = new byte[] { 0x01 }; + var compressedData = new byte[] { 0x01, 0x00, 0x00, 0x58, 0x00 }; + var lzma2Stream = new MemoryStream(compressedData); + + var decompressor = new LzmaStream(properties, lzma2Stream, 5, 1); + Assert.Equal('X', decompressor.ReadByte()); + } + + private static byte[] lzmaData { get; } = + new byte[] { - var properties = new byte[] { 0x01 }; - var compressedData = new byte[] { 0x01, 0x00, 0x00, 0x58, 0x00 }; - var lzma2Stream = new MemoryStream(compressedData); + 0x5D, + 0x00, + 0x20, + 0x00, + 0x00, + 0x48, + 0x01, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x80, + 0x24, + 0x18, + 0x2F, + 0xEB, + 0x20, + 0x78, + 0xBA, + 0x78, + 0x70, + 0xDC, + 0x43, + 0x2C, + 0x32, + 0xC9, + 0xC3, + 0x97, + 0x4D, + 0x10, + 0x74, + 0xE2, + 0x20, + 0xBF, + 0x5A, + 0xB4, + 0xB3, + 0xC4, + 0x31, + 0x80, + 0x26, + 0x3E, + 0x6A, + 0xEA, + 0x51, + 0xFC, + 0xE4, + 0x8D, + 0x54, + 0x96, + 0x05, + 0xCC, + 0x78, + 0x59, + 0xAC, + 0xD4, + 0x21, + 0x65, + 0x8F, + 0xA9, + 0xC8, + 0x0D, + 0x9B, + 0xE2, + 0xC2, + 0xF9, + 0x7C, + 0x3C, + 0xDD, + 0x4D, + 0x38, + 0x04, + 0x0B, + 0xF8, + 0x0B, + 0x68, + 0xA5, + 0x93, + 0x6C, + 0x64, + 0xAC, + 0xCF, + 0x71, + 0x68, + 0xE8, + 0x69, + 0x25, + 0xC6, + 0x17, + 0x28, + 0xF1, + 0x7C, + 0xF1, + 0xDC, + 0x47, + 0x51, + 0x4D, + 0x1E, + 0x0E, + 0x0B, + 0x80, + 0x37, + 0x24, + 0x58, + 0x80, + 0xF7, + 0xB4, + 0xAC, + 0x54, + 0xF1, + 0x0F, + 0x7F, + 0x0F, + 0x0F, + 0xF5, + 0x9C, + 0xDE, + 0x54, + 0x4F, + 0xA3, + 0x7B, + 0x20, + 0xC5, + 0xA8, + 0x18, + 0x3B, + 0xED, + 0xDC, + 0x04, + 0xF6, + 0xFB, + 0x86, + 0xE0, + 0xAB, + 0xB6, + 0x87, + 0x99, + 0x92, + 0x43, + 0x7B, + 0x2C, + 0xCC, + 0x31, + 0x83, + 0x90, + 0xFF, + 0xF1, + 0x76, + 0x03, + 0x90 + }; - var decompressor = new LzmaStream(properties, lzma2Stream, 5, 1); - Assert.Equal('X', decompressor.ReadByte()); - } - - private static byte[] lzmaData { get; } = - new byte[] - { - 0x5D, - 0x00, - 0x20, - 0x00, - 0x00, - 0x48, - 0x01, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x80, - 0x24, - 0x18, - 0x2F, - 0xEB, - 0x20, - 0x78, - 0xBA, - 0x78, - 0x70, - 0xDC, - 0x43, - 0x2C, - 0x32, - 0xC9, - 0xC3, - 0x97, - 0x4D, - 0x10, - 0x74, - 0xE2, - 0x20, - 0xBF, - 0x5A, - 0xB4, - 0xB3, - 0xC4, - 0x31, - 0x80, - 0x26, - 0x3E, - 0x6A, - 0xEA, - 0x51, - 0xFC, - 0xE4, - 0x8D, - 0x54, - 0x96, - 0x05, - 0xCC, - 0x78, - 0x59, - 0xAC, - 0xD4, - 0x21, - 0x65, - 0x8F, - 0xA9, - 0xC8, - 0x0D, - 0x9B, - 0xE2, - 0xC2, - 0xF9, - 0x7C, - 0x3C, - 0xDD, - 0x4D, - 0x38, - 0x04, - 0x0B, - 0xF8, - 0x0B, - 0x68, - 0xA5, - 0x93, - 0x6C, - 0x64, - 0xAC, - 0xCF, - 0x71, - 0x68, - 0xE8, - 0x69, - 0x25, - 0xC6, - 0x17, - 0x28, - 0xF1, - 0x7C, - 0xF1, - 0xDC, - 0x47, - 0x51, - 0x4D, - 0x1E, - 0x0E, - 0x0B, - 0x80, - 0x37, - 0x24, - 0x58, - 0x80, - 0xF7, - 0xB4, - 0xAC, - 0x54, - 0xF1, - 0x0F, - 0x7F, - 0x0F, - 0x0F, - 0xF5, - 0x9C, - 0xDE, - 0x54, - 0x4F, - 0xA3, - 0x7B, - 0x20, - 0xC5, - 0xA8, - 0x18, - 0x3B, - 0xED, - 0xDC, - 0x04, - 0xF6, - 0xFB, - 0x86, - 0xE0, - 0xAB, - 0xB6, - 0x87, - 0x99, - 0x92, - 0x43, - 0x7B, - 0x2C, - 0xCC, - 0x31, - 0x83, - 0x90, - 0xFF, - 0xF1, - 0x76, - 0x03, - 0x90 - }; - - private static byte[] lzmaResultData { get; } = - new byte[] - { - 0x01, - 0x00, - 0xFD, - 0x01, - 0x00, - 0x00, - 0x00, - 0x00, - 0xFA, - 0x61, - 0x18, - 0x5F, - 0x02, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x02, - 0x00, - 0x00, - 0x00, - 0x03, - 0x00, - 0x00, - 0x00, - 0x01, - 0x00, - 0x00, - 0x00, - 0x02, - 0x00, - 0xB4, - 0x01, - 0x00, - 0x00, - 0x00, - 0x00, - 0x3D, - 0x61, - 0xE5, - 0x5E, - 0x03, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x12, - 0x00, - 0x00, - 0x00, - 0x02, - 0x00, - 0xB4, - 0x01, - 0x00, - 0x00, - 0x00, - 0x00, - 0xE2, - 0x61, - 0x18, - 0x5F, - 0x04, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x12, - 0x00, - 0x00, - 0x00, - 0x29, - 0x00, - 0x00, - 0x00, - 0x01, - 0x00, - 0xFD, - 0x01, - 0x00, - 0x00, - 0x00, - 0x00, - 0x14, - 0x62, - 0x18, - 0x5F, - 0x01, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x03, - 0x00, - 0x00, - 0x00, - 0x40, - 0x00, - 0x00, - 0x00, - 0x09, - 0x00, - 0x00, - 0x00, - 0x02, - 0x00, - 0xB4, - 0x01, - 0x00, - 0x00, - 0x00, - 0x00, - 0x7F, - 0x61, - 0xE5, - 0x5E, - 0x05, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x3B, - 0x00, - 0x00, - 0x00, - 0xCB, - 0x15, - 0x00, - 0x00, - 0x02, - 0x00, - 0xB4, - 0x01, - 0x00, - 0x00, - 0x00, - 0x00, - 0x7F, - 0x61, - 0xE5, - 0x5E, - 0x06, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x3B, - 0x00, - 0x00, - 0x00, - 0xCB, - 0x15, - 0x00, - 0x00, - 0x02, - 0x00, - 0xB4, - 0x01, - 0x00, - 0x00, - 0x00, - 0x00, - 0x3D, - 0x61, - 0xE5, - 0x5E, - 0x07, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x12, - 0x00, - 0x00, - 0x00, - 0x02, - 0x00, - 0xB4, - 0x01, - 0x00, - 0x00, - 0x00, - 0x00, - 0xFC, - 0x96, - 0x40, - 0x5C, - 0x08, - 0x00, - 0x00, - 0x00, - 0x60, - 0x00, - 0x00, - 0x00, - 0xFF, - 0xFF, - 0xFF, - 0xFF, - 0x00, - 0x00, - 0x00, - 0x00, - 0xF8, - 0x83, - 0x12, - 0x00, - 0xD4, - 0x99, - 0x00, - 0x00, - 0x43, - 0x95, - 0x00, - 0x00, - 0xEB, - 0x7A, - 0x00, - 0x00, - 0x40, - 0x6F, - 0x00, - 0x00, - 0xD2, - 0x6F, - 0x00, - 0x00, - 0x67, - 0x74, - 0x00, - 0x00, - 0x02, - 0x69, - 0x00, - 0x00, - 0x76, - 0x79, - 0x00, - 0x00, - 0x98, - 0x66, - 0x00, - 0x00, - 0x23, - 0x25, - 0x00, - 0x00, - 0x01, - 0x00, - 0xFD, - 0x01, - 0x00, - 0x00, - 0x00, - 0x00, - 0x3B, - 0x2F, - 0xC0, - 0x5F, - 0x09, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x03, - 0x00, - 0x00, - 0x00, - 0x69, - 0x00, - 0x3D, - 0x00, - 0x0A, - 0x00, - 0x00, - 0x00 - }; - - [Fact] - public void TestLzmaBuffer() + private static byte[] lzmaResultData { get; } = + new byte[] { - var input = new MemoryStream(lzmaData); - using (var output = new MemoryStream()) - { - var properties = new byte[5]; - input.Read(properties, 0, 5); + 0x01, + 0x00, + 0xFD, + 0x01, + 0x00, + 0x00, + 0x00, + 0x00, + 0xFA, + 0x61, + 0x18, + 0x5F, + 0x02, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x02, + 0x00, + 0x00, + 0x00, + 0x03, + 0x00, + 0x00, + 0x00, + 0x01, + 0x00, + 0x00, + 0x00, + 0x02, + 0x00, + 0xB4, + 0x01, + 0x00, + 0x00, + 0x00, + 0x00, + 0x3D, + 0x61, + 0xE5, + 0x5E, + 0x03, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x12, + 0x00, + 0x00, + 0x00, + 0x02, + 0x00, + 0xB4, + 0x01, + 0x00, + 0x00, + 0x00, + 0x00, + 0xE2, + 0x61, + 0x18, + 0x5F, + 0x04, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x12, + 0x00, + 0x00, + 0x00, + 0x29, + 0x00, + 0x00, + 0x00, + 0x01, + 0x00, + 0xFD, + 0x01, + 0x00, + 0x00, + 0x00, + 0x00, + 0x14, + 0x62, + 0x18, + 0x5F, + 0x01, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x03, + 0x00, + 0x00, + 0x00, + 0x40, + 0x00, + 0x00, + 0x00, + 0x09, + 0x00, + 0x00, + 0x00, + 0x02, + 0x00, + 0xB4, + 0x01, + 0x00, + 0x00, + 0x00, + 0x00, + 0x7F, + 0x61, + 0xE5, + 0x5E, + 0x05, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x3B, + 0x00, + 0x00, + 0x00, + 0xCB, + 0x15, + 0x00, + 0x00, + 0x02, + 0x00, + 0xB4, + 0x01, + 0x00, + 0x00, + 0x00, + 0x00, + 0x7F, + 0x61, + 0xE5, + 0x5E, + 0x06, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x3B, + 0x00, + 0x00, + 0x00, + 0xCB, + 0x15, + 0x00, + 0x00, + 0x02, + 0x00, + 0xB4, + 0x01, + 0x00, + 0x00, + 0x00, + 0x00, + 0x3D, + 0x61, + 0xE5, + 0x5E, + 0x07, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x12, + 0x00, + 0x00, + 0x00, + 0x02, + 0x00, + 0xB4, + 0x01, + 0x00, + 0x00, + 0x00, + 0x00, + 0xFC, + 0x96, + 0x40, + 0x5C, + 0x08, + 0x00, + 0x00, + 0x00, + 0x60, + 0x00, + 0x00, + 0x00, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0x00, + 0x00, + 0x00, + 0x00, + 0xF8, + 0x83, + 0x12, + 0x00, + 0xD4, + 0x99, + 0x00, + 0x00, + 0x43, + 0x95, + 0x00, + 0x00, + 0xEB, + 0x7A, + 0x00, + 0x00, + 0x40, + 0x6F, + 0x00, + 0x00, + 0xD2, + 0x6F, + 0x00, + 0x00, + 0x67, + 0x74, + 0x00, + 0x00, + 0x02, + 0x69, + 0x00, + 0x00, + 0x76, + 0x79, + 0x00, + 0x00, + 0x98, + 0x66, + 0x00, + 0x00, + 0x23, + 0x25, + 0x00, + 0x00, + 0x01, + 0x00, + 0xFD, + 0x01, + 0x00, + 0x00, + 0x00, + 0x00, + 0x3B, + 0x2F, + 0xC0, + 0x5F, + 0x09, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x03, + 0x00, + 0x00, + 0x00, + 0x69, + 0x00, + 0x3D, + 0x00, + 0x0A, + 0x00, + 0x00, + 0x00 + }; - var fileLengthBytes = new byte[8]; - input.Read(fileLengthBytes, 0, 8); - var fileLength = BitConverter.ToInt64(fileLengthBytes, 0); + [Fact] + public void TestLzmaBuffer() + { + var input = new MemoryStream(lzmaData); + using var output = new MemoryStream(); + var properties = new byte[5]; + input.Read(properties, 0, 5); - var coder = new Decoder(); - coder.SetDecoderProperties(properties); - coder.Code(input, output, input.Length, fileLength, null); + var fileLengthBytes = new byte[8]; + input.Read(fileLengthBytes, 0, 8); + var fileLength = BitConverter.ToInt64(fileLengthBytes, 0); - Assert.Equal(output.ToArray(), lzmaResultData); - } - } + var coder = new Decoder(); + coder.SetDecoderProperties(properties); + coder.Code(input, output, input.Length, fileLength, null); + + Assert.Equal(output.ToArray(), lzmaResultData); } } diff --git a/tests/SharpCompress.Test/Streams/RewindableStreamTest.cs b/tests/SharpCompress.Test/Streams/RewindableStreamTest.cs index 14beab4f..ab18da45 100644 --- a/tests/SharpCompress.Test/Streams/RewindableStreamTest.cs +++ b/tests/SharpCompress.Test/Streams/RewindableStreamTest.cs @@ -1,83 +1,82 @@ -using System.IO; +using System.IO; using SharpCompress.IO; using Xunit; -namespace SharpCompress.Test.Streams -{ - public class RewindableStreamTest - { - [Fact] - public void TestRewind() - { - MemoryStream ms = new MemoryStream(); - BinaryWriter bw = new BinaryWriter(ms); - bw.Write(1); - bw.Write(2); - bw.Write(3); - bw.Write(4); - bw.Write(5); - bw.Write(6); - bw.Write(7); - bw.Flush(); - ms.Position = 0; - RewindableStream stream = new RewindableStream(ms); - stream.StartRecording(); - BinaryReader br = new BinaryReader(stream); - Assert.Equal(1, br.ReadInt32()); - Assert.Equal(2, br.ReadInt32()); - Assert.Equal(3, br.ReadInt32()); - Assert.Equal(4, br.ReadInt32()); - stream.Rewind(true); - stream.StartRecording(); - Assert.Equal(1, br.ReadInt32()); - Assert.Equal(2, br.ReadInt32()); - Assert.Equal(3, br.ReadInt32()); - Assert.Equal(4, br.ReadInt32()); - Assert.Equal(5, br.ReadInt32()); - Assert.Equal(6, br.ReadInt32()); - Assert.Equal(7, br.ReadInt32()); - stream.Rewind(true); - stream.StartRecording(); - Assert.Equal(1, br.ReadInt32()); - Assert.Equal(2, br.ReadInt32()); - Assert.Equal(3, br.ReadInt32()); - Assert.Equal(4, br.ReadInt32()); - } +namespace SharpCompress.Test.Streams; - [Fact] - public void TestIncompleteRewind() - { - MemoryStream ms = new MemoryStream(); - BinaryWriter bw = new BinaryWriter(ms); - bw.Write(1); - bw.Write(2); - bw.Write(3); - bw.Write(4); - bw.Write(5); - bw.Write(6); - bw.Write(7); - bw.Flush(); - ms.Position = 0; - RewindableStream stream = new RewindableStream(ms); - stream.StartRecording(); - BinaryReader br = new BinaryReader(stream); - Assert.Equal(1, br.ReadInt32()); - Assert.Equal(2, br.ReadInt32()); - Assert.Equal(3, br.ReadInt32()); - Assert.Equal(4, br.ReadInt32()); - stream.Rewind(true); - Assert.Equal(1, br.ReadInt32()); - Assert.Equal(2, br.ReadInt32()); - stream.StartRecording(); - Assert.Equal(3, br.ReadInt32()); - Assert.Equal(4, br.ReadInt32()); - Assert.Equal(5, br.ReadInt32()); - stream.Rewind(true); - Assert.Equal(3, br.ReadInt32()); - Assert.Equal(4, br.ReadInt32()); - Assert.Equal(5, br.ReadInt32()); - Assert.Equal(6, br.ReadInt32()); - Assert.Equal(7, br.ReadInt32()); - } +public class RewindableStreamTest +{ + [Fact] + public void TestRewind() + { + var ms = new MemoryStream(); + var bw = new BinaryWriter(ms); + bw.Write(1); + bw.Write(2); + bw.Write(3); + bw.Write(4); + bw.Write(5); + bw.Write(6); + bw.Write(7); + bw.Flush(); + ms.Position = 0; + var stream = new RewindableStream(ms); + stream.StartRecording(); + var br = new BinaryReader(stream); + Assert.Equal(1, br.ReadInt32()); + Assert.Equal(2, br.ReadInt32()); + Assert.Equal(3, br.ReadInt32()); + Assert.Equal(4, br.ReadInt32()); + stream.Rewind(true); + stream.StartRecording(); + Assert.Equal(1, br.ReadInt32()); + Assert.Equal(2, br.ReadInt32()); + Assert.Equal(3, br.ReadInt32()); + Assert.Equal(4, br.ReadInt32()); + Assert.Equal(5, br.ReadInt32()); + Assert.Equal(6, br.ReadInt32()); + Assert.Equal(7, br.ReadInt32()); + stream.Rewind(true); + stream.StartRecording(); + Assert.Equal(1, br.ReadInt32()); + Assert.Equal(2, br.ReadInt32()); + Assert.Equal(3, br.ReadInt32()); + Assert.Equal(4, br.ReadInt32()); + } + + [Fact] + public void TestIncompleteRewind() + { + var ms = new MemoryStream(); + var bw = new BinaryWriter(ms); + bw.Write(1); + bw.Write(2); + bw.Write(3); + bw.Write(4); + bw.Write(5); + bw.Write(6); + bw.Write(7); + bw.Flush(); + ms.Position = 0; + var stream = new RewindableStream(ms); + stream.StartRecording(); + var br = new BinaryReader(stream); + Assert.Equal(1, br.ReadInt32()); + Assert.Equal(2, br.ReadInt32()); + Assert.Equal(3, br.ReadInt32()); + Assert.Equal(4, br.ReadInt32()); + stream.Rewind(true); + Assert.Equal(1, br.ReadInt32()); + Assert.Equal(2, br.ReadInt32()); + stream.StartRecording(); + Assert.Equal(3, br.ReadInt32()); + Assert.Equal(4, br.ReadInt32()); + Assert.Equal(5, br.ReadInt32()); + stream.Rewind(true); + Assert.Equal(3, br.ReadInt32()); + Assert.Equal(4, br.ReadInt32()); + Assert.Equal(5, br.ReadInt32()); + Assert.Equal(6, br.ReadInt32()); + Assert.Equal(7, br.ReadInt32()); } } diff --git a/tests/SharpCompress.Test/Streams/ZlibBaseStreamTests.cs b/tests/SharpCompress.Test/Streams/ZlibBaseStreamTests.cs index 99bdeb38..44f6843c 100644 --- a/tests/SharpCompress.Test/Streams/ZlibBaseStreamTests.cs +++ b/tests/SharpCompress.Test/Streams/ZlibBaseStreamTests.cs @@ -6,116 +6,101 @@ using SharpCompress.Compressors.Deflate; using SharpCompress.IO; using Xunit; -namespace SharpCompress.Test.Streams +namespace SharpCompress.Test.Streams; + +public class ZLibBaseStreamTests { - public class ZLibBaseStreamTests + [Fact] + public void TestChunkedZlibCompressesEverything() { - [Fact] - public void TestChunkedZlibCompressesEverything() + var plainData = new byte[] { - byte[] plainData = new byte[] - { - 0xf7, - 0x1b, - 0xda, - 0x0f, - 0xb6, - 0x2b, - 0x3d, - 0x91, - 0xd7, - 0xe1, - 0xb5, - 0x11, - 0x34, - 0x5a, - 0x51, - 0x3f, - 0x8b, - 0xce, - 0x49, - 0xd2 - }; - byte[] buf = new byte[plainData.Length * 2]; + 0xf7, + 0x1b, + 0xda, + 0x0f, + 0xb6, + 0x2b, + 0x3d, + 0x91, + 0xd7, + 0xe1, + 0xb5, + 0x11, + 0x34, + 0x5a, + 0x51, + 0x3f, + 0x8b, + 0xce, + 0x49, + 0xd2 + }; + var buf = new byte[plainData.Length * 2]; - MemoryStream plainStream1 = new MemoryStream(plainData); - DeflateStream compressor1 = new DeflateStream(plainStream1, CompressionMode.Compress); - // This is enough to read the entire data - int realCompressedSize = compressor1.Read(buf, 0, plainData.Length * 2); + var plainStream1 = new MemoryStream(plainData); + var compressor1 = new DeflateStream(plainStream1, CompressionMode.Compress); + // This is enough to read the entire data + var realCompressedSize = compressor1.Read(buf, 0, plainData.Length * 2); - MemoryStream plainStream2 = new MemoryStream(plainData); - DeflateStream compressor2 = new DeflateStream(plainStream2, CompressionMode.Compress); - int total = 0; - int r = -1; // Jumpstart - while (r != 0) - { - // Reading in chunks - r = compressor2.Read(buf, 0, plainData.Length); - total += r; - } - - Assert.Equal(total, realCompressedSize); + var plainStream2 = new MemoryStream(plainData); + var compressor2 = new DeflateStream(plainStream2, CompressionMode.Compress); + var total = 0; + var r = -1; // Jumpstart + while (r != 0) + { + // Reading in chunks + r = compressor2.Read(buf, 0, plainData.Length); + total += r; } - [Fact] - public void Zlib_should_read_the_previously_written_message() - { - var message = new string('a', 131073); // 131073 causes the failure, but 131072 (-1) doesn't - var bytes = Encoding.ASCII.GetBytes(message); + Assert.Equal(total, realCompressedSize); + } - using (var inputStream = new MemoryStream(bytes)) - { - using (var compressedStream = new MemoryStream()) - using (var byteBufferStream = new BufferedStream(inputStream)) // System.IO - { - Compress(byteBufferStream, compressedStream, compressionLevel: 1); - compressedStream.Position = 0; + [Fact] + public void Zlib_should_read_the_previously_written_message() + { + var message = new string('a', 131073); // 131073 causes the failure, but 131072 (-1) doesn't + var bytes = Encoding.ASCII.GetBytes(message); - using (var decompressedStream = new MemoryStream()) - { - Decompress(compressedStream, decompressedStream); + using var inputStream = new MemoryStream(bytes); + using var compressedStream = new MemoryStream(); + using var byteBufferStream = new BufferedStream(inputStream); // System.IO + Compress(byteBufferStream, compressedStream, compressionLevel: 1); + compressedStream.Position = 0; - byteBufferStream.Position = 0; - var result = Encoding.ASCII.GetString(GetBytes(byteBufferStream)); - result.Should().Be(message); - } - } - } - } + using var decompressedStream = new MemoryStream(); + Decompress(compressedStream, decompressedStream); - private void Compress(Stream input, Stream output, int compressionLevel) - { - using ( - var zlibStream = new ZlibStream( - NonDisposingStream.Create(output), - CompressionMode.Compress, - (CompressionLevel)compressionLevel - ) - ) - { - zlibStream.FlushMode = FlushType.Sync; - input.CopyTo(zlibStream); - } - } + byteBufferStream.Position = 0; + var result = Encoding.ASCII.GetString(GetBytes(byteBufferStream)); + result.Should().Be(message); + } - private void Decompress(Stream input, Stream output) - { - using ( - var zlibStream = new ZlibStream( - NonDisposingStream.Create(input), - CompressionMode.Decompress - ) - ) - { - zlibStream.CopyTo(output); - } - } + private void Compress(Stream input, Stream output, int compressionLevel) + { + using var zlibStream = new ZlibStream( + NonDisposingStream.Create(output), + CompressionMode.Compress, + (CompressionLevel)compressionLevel + ); + zlibStream.FlushMode = FlushType.Sync; + input.CopyTo(zlibStream); + } - byte[] GetBytes(BufferedStream stream) - { - byte[] bytes = new byte[stream.Length]; - stream.Read(bytes, 0, (int)stream.Length); - return bytes; - } + private void Decompress(Stream input, Stream output) + { + using var zlibStream = new ZlibStream( + NonDisposingStream.Create(input), + CompressionMode.Decompress + ); + zlibStream.CopyTo(output); + } + + private byte[] GetBytes(BufferedStream stream) + { + var bytes = new byte[stream.Length]; + stream.Read(bytes, 0, (int)stream.Length); + return bytes; } } diff --git a/tests/SharpCompress.Test/Tar/TarArchiveTests.cs b/tests/SharpCompress.Test/Tar/TarArchiveTests.cs index 45b32694..37dc7650 100644 --- a/tests/SharpCompress.Test/Tar/TarArchiveTests.cs +++ b/tests/SharpCompress.Test/Tar/TarArchiveTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; using System.Linq; using SharpCompress.Archives; diff --git a/tests/SharpCompress.Test/Tar/TarReaderTests.cs b/tests/SharpCompress.Test/Tar/TarReaderTests.cs index 966b82bf..52ad2b33 100644 --- a/tests/SharpCompress.Test/Tar/TarReaderTests.cs +++ b/tests/SharpCompress.Test/Tar/TarReaderTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using SharpCompress.Common; diff --git a/tests/SharpCompress.Test/Tar/TarWriterTests.cs b/tests/SharpCompress.Test/Tar/TarWriterTests.cs index d9bff3d8..197e7ba3 100644 --- a/tests/SharpCompress.Test/Tar/TarWriterTests.cs +++ b/tests/SharpCompress.Test/Tar/TarWriterTests.cs @@ -1,90 +1,85 @@ -using System.IO; +using System.IO; using System.Text; using SharpCompress.Common; using SharpCompress.Writers.Tar; using Xunit; -namespace SharpCompress.Test.Tar +namespace SharpCompress.Test.Tar; + +public class TarWriterTests : WriterTests { - public class TarWriterTests : WriterTests + public TarWriterTests() : base(ArchiveType.Tar) { - public TarWriterTests() : base(ArchiveType.Tar) - { - UseExtensionInsteadOfNameToVerify = true; - } + UseExtensionInsteadOfNameToVerify = true; + } - [Fact] - public void Tar_Writer() - { - Write( - CompressionType.None, - "Tar.noEmptyDirs.tar", - "Tar.noEmptyDirs.tar", - Encoding.GetEncoding(866) - ); - } + [Fact] + public void Tar_Writer() + { + Write( + CompressionType.None, + "Tar.noEmptyDirs.tar", + "Tar.noEmptyDirs.tar", + Encoding.GetEncoding(866) + ); + } - [Fact] - public void Tar_BZip2_Writer() - { - Write( - CompressionType.BZip2, - "Tar.noEmptyDirs.tar.bz2", - "Tar.noEmptyDirs.tar.bz2", - Encoding.GetEncoding(866) - ); - } + [Fact] + public void Tar_BZip2_Writer() + { + Write( + CompressionType.BZip2, + "Tar.noEmptyDirs.tar.bz2", + "Tar.noEmptyDirs.tar.bz2", + Encoding.GetEncoding(866) + ); + } - [Fact] - public void Tar_LZip_Writer() - { - Write( - CompressionType.LZip, - "Tar.noEmptyDirs.tar.lz", - "Tar.noEmptyDirs.tar.lz", - Encoding.GetEncoding(866) - ); - } + [Fact] + public void Tar_LZip_Writer() + { + Write( + CompressionType.LZip, + "Tar.noEmptyDirs.tar.lz", + "Tar.noEmptyDirs.tar.lz", + Encoding.GetEncoding(866) + ); + } - [Fact] - public void Tar_Rar_Write() - { - Assert.Throws( - () => - Write( - CompressionType.Rar, - "Zip.ppmd.noEmptyDirs.zip", - "Zip.ppmd.noEmptyDirs.zip" - ) - ); - } - - [Theory] - [InlineData(true)] - [InlineData(false)] - public void Tar_Finalize_Archive(bool finalizeArchive) - { - using (MemoryStream stream = new MemoryStream()) - using ( - Stream content = File.OpenRead(Path.Combine(ORIGINAL_FILES_PATH, "jpg", "test.jpg")) - ) - { - using ( - TarWriter writer = new TarWriter( - stream, - new TarWriterOptions(CompressionType.None, finalizeArchive) - ) + [Fact] + public void Tar_Rar_Write() + { + Assert.Throws( + () => + Write( + CompressionType.Rar, + "Zip.ppmd.noEmptyDirs.zip", + "Zip.ppmd.noEmptyDirs.zip" ) - { - writer.Write("doesn't matter", content, null); - } + ); + } - var paddedContentWithHeader = content.Length / 512 * 512 + 512 + 512; - var expectedStreamLength = finalizeArchive - ? paddedContentWithHeader + 512 * 2 - : paddedContentWithHeader; - Assert.Equal(expectedStreamLength, stream.Length); - } + [Theory] + [InlineData(true)] + [InlineData(false)] + public void Tar_Finalize_Archive(bool finalizeArchive) + { + using var stream = new MemoryStream(); + using Stream content = File.OpenRead(Path.Combine(ORIGINAL_FILES_PATH, "jpg", "test.jpg")); + using ( + var writer = new TarWriter( + stream, + new TarWriterOptions(CompressionType.None, finalizeArchive) + ) + ) + { + writer.Write("doesn't matter", content, null); } + + var paddedContentWithHeader = (content.Length / 512 * 512) + 512 + 512; + var expectedStreamLength = finalizeArchive + ? paddedContentWithHeader + (512 * 2) + : paddedContentWithHeader; + Assert.Equal(expectedStreamLength, stream.Length); } } diff --git a/tests/SharpCompress.Test/TestBase.cs b/tests/SharpCompress.Test/TestBase.cs index 455d4845..51900b33 100644 --- a/tests/SharpCompress.Test/TestBase.cs +++ b/tests/SharpCompress.Test/TestBase.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -6,221 +6,218 @@ using System.Text; using SharpCompress.Readers; using Xunit; -namespace SharpCompress.Test +namespace SharpCompress.Test; + +public class TestBase : IDisposable { - public class TestBase : IDisposable + private string SOLUTION_BASE_PATH; + protected string TEST_ARCHIVES_PATH; + protected string ORIGINAL_FILES_PATH; + protected string MISC_TEST_FILES_PATH; + private string SCRATCH_BASE_PATH; + public string SCRATCH_FILES_PATH; + protected string SCRATCH2_FILES_PATH; + + public TestBase() { - private string SOLUTION_BASE_PATH; - protected string TEST_ARCHIVES_PATH; - protected string ORIGINAL_FILES_PATH; - protected string MISC_TEST_FILES_PATH; - private string SCRATCH_BASE_PATH; - public string SCRATCH_FILES_PATH; - protected string SCRATCH2_FILES_PATH; + var index = AppDomain.CurrentDomain.BaseDirectory.IndexOf( + "SharpCompress.Test", + StringComparison.OrdinalIgnoreCase + ); + var path = AppDomain.CurrentDomain.BaseDirectory.Substring(0, index); + SOLUTION_BASE_PATH = Path.GetDirectoryName(path) ?? throw new ArgumentNullException(); - public TestBase() + TEST_ARCHIVES_PATH = Path.Combine(SOLUTION_BASE_PATH, "TestArchives", "Archives"); + ORIGINAL_FILES_PATH = Path.Combine(SOLUTION_BASE_PATH, "TestArchives", "Original"); + MISC_TEST_FILES_PATH = Path.Combine(SOLUTION_BASE_PATH, "TestArchives", "MiscTest"); + + SCRATCH_BASE_PATH = Path.Combine( + SOLUTION_BASE_PATH, + "TestArchives", + Guid.NewGuid().ToString() + ); + SCRATCH_FILES_PATH = Path.Combine(SCRATCH_BASE_PATH, "Scratch"); + SCRATCH2_FILES_PATH = Path.Combine(SCRATCH_BASE_PATH, "Scratch2"); + + Directory.CreateDirectory(SCRATCH_FILES_PATH); + Directory.CreateDirectory(SCRATCH2_FILES_PATH); + } + + public void Dispose() + { + Directory.Delete(SCRATCH_BASE_PATH, true); + } + + public void VerifyFiles() + { + if (UseExtensionInsteadOfNameToVerify) { - var index = AppDomain.CurrentDomain.BaseDirectory.IndexOf( - "SharpCompress.Test", - StringComparison.OrdinalIgnoreCase - ); - var path = AppDomain.CurrentDomain.BaseDirectory.Substring(0, index); - SOLUTION_BASE_PATH = Path.GetDirectoryName(path) ?? throw new ArgumentNullException(); + VerifyFilesByExtension(); + } + else + { + VerifyFilesByName(); + } + } - TEST_ARCHIVES_PATH = Path.Combine(SOLUTION_BASE_PATH, "TestArchives", "Archives"); - ORIGINAL_FILES_PATH = Path.Combine(SOLUTION_BASE_PATH, "TestArchives", "Original"); - MISC_TEST_FILES_PATH = Path.Combine(SOLUTION_BASE_PATH, "TestArchives", "MiscTest"); + /// + /// Verifies the files also check modified time and attributes. + /// + public void VerifyFilesEx() + { + if (UseExtensionInsteadOfNameToVerify) + { + VerifyFilesByExtensionEx(); + } + else + { + VerifyFilesByNameEx(); + } + } - SCRATCH_BASE_PATH = Path.Combine( - SOLUTION_BASE_PATH, - "TestArchives", - Guid.NewGuid().ToString() - ); - SCRATCH_FILES_PATH = Path.Combine(SCRATCH_BASE_PATH, "Scratch"); - SCRATCH2_FILES_PATH = Path.Combine(SCRATCH_BASE_PATH, "Scratch2"); + protected void VerifyFilesByName() + { + var extracted = Directory + .EnumerateFiles(SCRATCH_FILES_PATH, "*.*", SearchOption.AllDirectories) + .ToLookup(path => path.Substring(SCRATCH_FILES_PATH.Length)); + var original = Directory + .EnumerateFiles(ORIGINAL_FILES_PATH, "*.*", SearchOption.AllDirectories) + .ToLookup(path => path.Substring(ORIGINAL_FILES_PATH.Length)); - Directory.CreateDirectory(SCRATCH_FILES_PATH); - Directory.CreateDirectory(SCRATCH2_FILES_PATH); + Assert.Equal(extracted.Count, original.Count); + + foreach (var orig in original) + { + Assert.True(extracted.Contains(orig.Key)); + + CompareFilesByPath(orig.Single(), extracted[orig.Key].Single()); + } + } + + /// + /// Verifies the files by name also check modified time and attributes. + /// + protected void VerifyFilesByNameEx() + { + var extracted = Directory + .EnumerateFiles(SCRATCH_FILES_PATH, "*.*", SearchOption.AllDirectories) + .ToLookup(path => path.Substring(SCRATCH_FILES_PATH.Length)); + var original = Directory + .EnumerateFiles(ORIGINAL_FILES_PATH, "*.*", SearchOption.AllDirectories) + .ToLookup(path => path.Substring(ORIGINAL_FILES_PATH.Length)); + + Assert.Equal(extracted.Count, original.Count); + + foreach (var orig in original) + { + Assert.True(extracted.Contains(orig.Key)); + + CompareFilesByPath(orig.Single(), extracted[orig.Key].Single()); + CompareFilesByTimeAndAttribut(orig.Single(), extracted[orig.Key].Single()); + } + } + + /// + /// Verifies the files by extension also check modified time and attributes. + /// + protected void VerifyFilesByExtensionEx() + { + var extracted = Directory + .EnumerateFiles(SCRATCH_FILES_PATH, "*.*", SearchOption.AllDirectories) + .ToLookup(path => Path.GetExtension(path)); + var original = Directory + .EnumerateFiles(ORIGINAL_FILES_PATH, "*.*", SearchOption.AllDirectories) + .ToLookup(path => Path.GetExtension(path)); + + Assert.Equal(extracted.Count, original.Count); + + foreach (var orig in original) + { + Assert.True(extracted.Contains(orig.Key)); + + CompareFilesByPath(orig.Single(), extracted[orig.Key].Single()); + CompareFilesByTimeAndAttribut(orig.Single(), extracted[orig.Key].Single()); + } + } + + protected bool UseExtensionInsteadOfNameToVerify { get; set; } + + protected void VerifyFilesByExtension() + { + var extracted = Directory + .EnumerateFiles(SCRATCH_FILES_PATH, "*.*", SearchOption.AllDirectories) + .ToLookup(path => Path.GetExtension(path)); + var original = Directory + .EnumerateFiles(ORIGINAL_FILES_PATH, "*.*", SearchOption.AllDirectories) + .ToLookup(path => Path.GetExtension(path)); + + Assert.Equal(extracted.Count, original.Count); + + foreach (var orig in original) + { + Assert.True(extracted.Contains(orig.Key)); + + CompareFilesByPath(orig.Single(), extracted[orig.Key].Single()); + } + } + + protected void CompareFilesByPath(string file1, string file2) + { + //TODO: fix line ending issues with the text file + if (file1.EndsWith("txt", StringComparison.OrdinalIgnoreCase)) + { + return; } - public void Dispose() + using var file1Stream = File.OpenRead(file1); + using var file2Stream = File.OpenRead(file2); + Assert.Equal(file1Stream.Length, file2Stream.Length); + var byte1 = 0; + var byte2 = 0; + for (var counter = 0; byte1 != -1; counter++) { - Directory.Delete(SCRATCH_BASE_PATH, true); - } - - public void VerifyFiles() - { - if (UseExtensionInsteadOfNameToVerify) + byte1 = file1Stream.ReadByte(); + byte2 = file2Stream.ReadByte(); + if (byte1 != byte2) { - VerifyFilesByExtension(); - } - else - { - VerifyFilesByName(); - } - } - - /// - /// Verifies the files also check modified time and attributes. - /// - public void VerifyFilesEx() - { - if (UseExtensionInsteadOfNameToVerify) - { - VerifyFilesByExtensionEx(); - } - else - { - VerifyFilesByNameEx(); - } - } - - protected void VerifyFilesByName() - { - var extracted = Directory - .EnumerateFiles(SCRATCH_FILES_PATH, "*.*", SearchOption.AllDirectories) - .ToLookup(path => path.Substring(SCRATCH_FILES_PATH.Length)); - var original = Directory - .EnumerateFiles(ORIGINAL_FILES_PATH, "*.*", SearchOption.AllDirectories) - .ToLookup(path => path.Substring(ORIGINAL_FILES_PATH.Length)); - - Assert.Equal(extracted.Count, original.Count); - - foreach (var orig in original) - { - Assert.True(extracted.Contains(orig.Key)); - - CompareFilesByPath(orig.Single(), extracted[orig.Key].Single()); - } - } - - /// - /// Verifies the files by name also check modified time and attributes. - /// - protected void VerifyFilesByNameEx() - { - var extracted = Directory - .EnumerateFiles(SCRATCH_FILES_PATH, "*.*", SearchOption.AllDirectories) - .ToLookup(path => path.Substring(SCRATCH_FILES_PATH.Length)); - var original = Directory - .EnumerateFiles(ORIGINAL_FILES_PATH, "*.*", SearchOption.AllDirectories) - .ToLookup(path => path.Substring(ORIGINAL_FILES_PATH.Length)); - - Assert.Equal(extracted.Count, original.Count); - - foreach (var orig in original) - { - Assert.True(extracted.Contains(orig.Key)); - - CompareFilesByPath(orig.Single(), extracted[orig.Key].Single()); - CompareFilesByTimeAndAttribut(orig.Single(), extracted[orig.Key].Single()); - } - } - - /// - /// Verifies the files by extension also check modified time and attributes. - /// - protected void VerifyFilesByExtensionEx() - { - var extracted = Directory - .EnumerateFiles(SCRATCH_FILES_PATH, "*.*", SearchOption.AllDirectories) - .ToLookup(path => Path.GetExtension(path)); - var original = Directory - .EnumerateFiles(ORIGINAL_FILES_PATH, "*.*", SearchOption.AllDirectories) - .ToLookup(path => Path.GetExtension(path)); - - Assert.Equal(extracted.Count, original.Count); - - foreach (var orig in original) - { - Assert.True(extracted.Contains(orig.Key)); - - CompareFilesByPath(orig.Single(), extracted[orig.Key].Single()); - CompareFilesByTimeAndAttribut(orig.Single(), extracted[orig.Key].Single()); - } - } - - protected bool UseExtensionInsteadOfNameToVerify { get; set; } - - protected void VerifyFilesByExtension() - { - var extracted = Directory - .EnumerateFiles(SCRATCH_FILES_PATH, "*.*", SearchOption.AllDirectories) - .ToLookup(path => Path.GetExtension(path)); - var original = Directory - .EnumerateFiles(ORIGINAL_FILES_PATH, "*.*", SearchOption.AllDirectories) - .ToLookup(path => Path.GetExtension(path)); - - Assert.Equal(extracted.Count, original.Count); - - foreach (var orig in original) - { - Assert.True(extracted.Contains(orig.Key)); - - CompareFilesByPath(orig.Single(), extracted[orig.Key].Single()); - } - } - - protected void CompareFilesByPath(string file1, string file2) - { - //TODO: fix line ending issues with the text file - if (file1.EndsWith("txt", StringComparison.OrdinalIgnoreCase)) - { - return; - } - - using (var file1Stream = File.OpenRead(file1)) - using (var file2Stream = File.OpenRead(file2)) - { - Assert.Equal(file1Stream.Length, file2Stream.Length); - int byte1 = 0; - int byte2 = 0; - for (int counter = 0; byte1 != -1; counter++) - { - byte1 = file1Stream.ReadByte(); - byte2 = file2Stream.ReadByte(); - if (byte1 != byte2) - { - //string.Format("Byte {0} differ between {1} and {2}", counter, file1, file2) - Assert.Equal(byte1, byte2); - } - } - } - } - - protected void CompareFilesByTimeAndAttribut(string file1, string file2) - { - FileInfo fi1 = new FileInfo(file1); - FileInfo fi2 = new FileInfo(file2); - Assert.NotEqual(fi1.LastWriteTime, fi2.LastWriteTime); - Assert.Equal(fi1.Attributes, fi2.Attributes); - } - - protected void CompareArchivesByPath(string file1, string file2, Encoding? encoding = null) - { - ReaderOptions readerOptions = new ReaderOptions { LeaveStreamOpen = false }; - readerOptions.ArchiveEncoding.Default = encoding ?? Encoding.Default; - - //don't compare the order. OS X reads files from the file system in a different order therefore makes the archive ordering different - var archive1Entries = new List(); - var archive2Entries = new List(); - using (var archive1 = ReaderFactory.Open(File.OpenRead(file1), readerOptions)) - using (var archive2 = ReaderFactory.Open(File.OpenRead(file2), readerOptions)) - { - while (archive1.MoveToNextEntry()) - { - Assert.True(archive2.MoveToNextEntry()); - archive1Entries.Add(archive1.Entry.Key); - archive2Entries.Add(archive2.Entry.Key); - } - Assert.False(archive2.MoveToNextEntry()); - } - archive1Entries.Sort(); - archive2Entries.Sort(); - for (int i = 0; i < archive1Entries.Count; i++) - { - Assert.Equal(archive1Entries[i], archive2Entries[i]); + //string.Format("Byte {0} differ between {1} and {2}", counter, file1, file2) + Assert.Equal(byte1, byte2); } } } + + protected void CompareFilesByTimeAndAttribut(string file1, string file2) + { + var fi1 = new FileInfo(file1); + var fi2 = new FileInfo(file2); + Assert.NotEqual(fi1.LastWriteTime, fi2.LastWriteTime); + Assert.Equal(fi1.Attributes, fi2.Attributes); + } + + protected void CompareArchivesByPath(string file1, string file2, Encoding? encoding = null) + { + var readerOptions = new ReaderOptions { LeaveStreamOpen = false }; + readerOptions.ArchiveEncoding.Default = encoding ?? Encoding.Default; + + //don't compare the order. OS X reads files from the file system in a different order therefore makes the archive ordering different + var archive1Entries = new List(); + var archive2Entries = new List(); + using (var archive1 = ReaderFactory.Open(File.OpenRead(file1), readerOptions)) + using (var archive2 = ReaderFactory.Open(File.OpenRead(file2), readerOptions)) + { + while (archive1.MoveToNextEntry()) + { + Assert.True(archive2.MoveToNextEntry()); + archive1Entries.Add(archive1.Entry.Key); + archive2Entries.Add(archive2.Entry.Key); + } + Assert.False(archive2.MoveToNextEntry()); + } + archive1Entries.Sort(); + archive2Entries.Sort(); + for (var i = 0; i < archive1Entries.Count; i++) + { + Assert.Equal(archive1Entries[i], archive2Entries[i]); + } + } } diff --git a/tests/SharpCompress.Test/WriterTests.cs b/tests/SharpCompress.Test/WriterTests.cs index ad322949..7134ea9e 100644 --- a/tests/SharpCompress.Test/WriterTests.cs +++ b/tests/SharpCompress.Test/WriterTests.cs @@ -5,63 +5,56 @@ using SharpCompress.IO; using SharpCompress.Readers; using SharpCompress.Writers; -namespace SharpCompress.Test +namespace SharpCompress.Test; + +public class WriterTests : TestBase { - public class WriterTests : TestBase + private readonly ArchiveType type; + + protected WriterTests(ArchiveType type) { - private readonly ArchiveType type; + this.type = type; + } - protected WriterTests(ArchiveType type) + protected void Write( + CompressionType compressionType, + string archive, + string archiveToVerifyAgainst, + Encoding? encoding = null + ) + { + using (Stream stream = File.OpenWrite(Path.Combine(SCRATCH2_FILES_PATH, archive))) { - this.type = type; - } - - protected void Write( - CompressionType compressionType, - string archive, - string archiveToVerifyAgainst, - Encoding? encoding = null - ) - { - using (Stream stream = File.OpenWrite(Path.Combine(SCRATCH2_FILES_PATH, archive))) + var writerOptions = new WriterOptions(compressionType) { - WriterOptions writerOptions = new WriterOptions(compressionType) - { - LeaveStreamOpen = true, - }; + LeaveStreamOpen = true, + }; - writerOptions.ArchiveEncoding.Default = encoding ?? Encoding.Default; + writerOptions.ArchiveEncoding.Default = encoding ?? Encoding.Default; - using (var writer = WriterFactory.Open(stream, type, writerOptions)) - { - writer.WriteAll(ORIGINAL_FILES_PATH, "*", SearchOption.AllDirectories); - } - } - CompareArchivesByPath( - Path.Combine(SCRATCH2_FILES_PATH, archive), - Path.Combine(TEST_ARCHIVES_PATH, archiveToVerifyAgainst) + using var writer = WriterFactory.Open(stream, type, writerOptions); + writer.WriteAll(ORIGINAL_FILES_PATH, "*", SearchOption.AllDirectories); + } + CompareArchivesByPath( + Path.Combine(SCRATCH2_FILES_PATH, archive), + Path.Combine(TEST_ARCHIVES_PATH, archiveToVerifyAgainst) + ); + + using (Stream stream = File.OpenRead(Path.Combine(SCRATCH2_FILES_PATH, archive))) + { + var readerOptions = new ReaderOptions(); + + readerOptions.ArchiveEncoding.Default = encoding ?? Encoding.Default; + + using var reader = ReaderFactory.Open( + NonDisposingStream.Create(stream), + readerOptions + ); + reader.WriteAllToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() { ExtractFullPath = true } ); - - using (Stream stream = File.OpenRead(Path.Combine(SCRATCH2_FILES_PATH, archive))) - { - ReaderOptions readerOptions = new ReaderOptions(); - - readerOptions.ArchiveEncoding.Default = encoding ?? Encoding.Default; - - using ( - var reader = ReaderFactory.Open( - NonDisposingStream.Create(stream), - readerOptions - ) - ) - { - reader.WriteAllToDirectory( - SCRATCH_FILES_PATH, - new ExtractionOptions() { ExtractFullPath = true } - ); - } - } - VerifyFiles(); } + VerifyFiles(); } } diff --git a/tests/SharpCompress.Test/Xz/Crc32Tests.cs b/tests/SharpCompress.Test/Xz/Crc32Tests.cs index 7afa27a1..7476b748 100644 --- a/tests/SharpCompress.Test/Xz/Crc32Tests.cs +++ b/tests/SharpCompress.Test/Xz/Crc32Tests.cs @@ -1,32 +1,31 @@ -using SharpCompress.Compressors.Xz; using System; using System.Text; +using SharpCompress.Compressors.Xz; using Xunit; -namespace SharpCompress.Test.Xz +namespace SharpCompress.Test.Xz; + +public class Crc32Tests { - public class Crc32Tests + private const string SimpleString = @"The quick brown fox jumps over the lazy dog."; + private readonly byte[] SimpleBytes = Encoding.ASCII.GetBytes(SimpleString); + private const string SimpleString2 = + @"Life moves pretty fast. If you don't stop and look around once in a while, you could miss it."; + private readonly byte[] SimpleBytes2 = Encoding.ASCII.GetBytes(SimpleString2); + + [Fact] + public void ShortAsciiString() { - private const string SimpleString = @"The quick brown fox jumps over the lazy dog."; - private readonly byte[] SimpleBytes = Encoding.ASCII.GetBytes(SimpleString); - private const string SimpleString2 = - @"Life moves pretty fast. If you don't stop and look around once in a while, you could miss it."; - private readonly byte[] SimpleBytes2 = Encoding.ASCII.GetBytes(SimpleString2); + var actual = Crc32.Compute(SimpleBytes); - [Fact] - public void ShortAsciiString() - { - var actual = Crc32.Compute(SimpleBytes); + Assert.Equal((uint)0x519025e9, actual); + } - Assert.Equal((UInt32)0x519025e9, actual); - } + [Fact] + public void ShortAsciiString2() + { + var actual = Crc32.Compute(SimpleBytes2); - [Fact] - public void ShortAsciiString2() - { - var actual = Crc32.Compute(SimpleBytes2); - - Assert.Equal((UInt32)0x6ee3ad88, actual); - } + Assert.Equal((uint)0x6ee3ad88, actual); } } diff --git a/tests/SharpCompress.Test/Xz/Crc64Tests.cs b/tests/SharpCompress.Test/Xz/Crc64Tests.cs index f4ef9493..6b9cb31e 100644 --- a/tests/SharpCompress.Test/Xz/Crc64Tests.cs +++ b/tests/SharpCompress.Test/Xz/Crc64Tests.cs @@ -1,32 +1,31 @@ -using SharpCompress.Compressors.Xz; using System; using System.Text; +using SharpCompress.Compressors.Xz; using Xunit; -namespace SharpCompress.Test.Xz +namespace SharpCompress.Test.Xz; + +public class Crc64Tests { - public class Crc64Tests + private const string SimpleString = @"The quick brown fox jumps over the lazy dog."; + private readonly byte[] SimpleBytes = Encoding.ASCII.GetBytes(SimpleString); + private const string SimpleString2 = + @"Life moves pretty fast. If you don't stop and look around once in a while, you could miss it."; + private readonly byte[] SimpleBytes2 = Encoding.ASCII.GetBytes(SimpleString2); + + [Fact] + public void ShortAsciiString() { - private const string SimpleString = @"The quick brown fox jumps over the lazy dog."; - private readonly byte[] SimpleBytes = Encoding.ASCII.GetBytes(SimpleString); - private const string SimpleString2 = - @"Life moves pretty fast. If you don't stop and look around once in a while, you could miss it."; - private readonly byte[] SimpleBytes2 = Encoding.ASCII.GetBytes(SimpleString2); + var actual = Crc64.Compute(SimpleBytes); - [Fact] - public void ShortAsciiString() - { - var actual = Crc64.Compute(SimpleBytes); + Assert.Equal((ulong)0x7E210EB1B03E5A1D, actual); + } - Assert.Equal((UInt64)0x7E210EB1B03E5A1D, actual); - } + [Fact] + public void ShortAsciiString2() + { + var actual = Crc64.Compute(SimpleBytes2); - [Fact] - public void ShortAsciiString2() - { - var actual = Crc64.Compute(SimpleBytes2); - - Assert.Equal((UInt64)0x416B4150508661EE, actual); - } + Assert.Equal((ulong)0x416B4150508661EE, actual); } } diff --git a/tests/SharpCompress.Test/Xz/Filters/BCJTests.cs b/tests/SharpCompress.Test/Xz/Filters/BCJTests.cs index a18005dd..427a7b98 100644 --- a/tests/SharpCompress.Test/Xz/Filters/BCJTests.cs +++ b/tests/SharpCompress.Test/Xz/Filters/BCJTests.cs @@ -7,83 +7,82 @@ using System.IO; using SharpCompress.Compressors.Xz.Filters; using Xunit; -namespace SharpCompress.Test.Xz.Filters +namespace SharpCompress.Test.Xz.Filters; + +public class BCJTests : XZTestsBase { - public class BCJTests : XZTestsBase + private readonly ArmFilter armFilter; + private readonly ArmThumbFilter armtFilter; + private readonly IA64Filter ia64Filter; + private readonly PowerPCFilter ppcFilter; + private readonly SparcFilter sparcFilter; + private readonly X86Filter x86Filter; + + public BCJTests() { - private readonly ArmFilter armFilter; - private readonly ArmThumbFilter armtFilter; - private readonly IA64Filter ia64Filter; - private readonly PowerPCFilter ppcFilter; - private readonly SparcFilter sparcFilter; - private readonly X86Filter x86Filter; + armFilter = new ArmFilter(); + armtFilter = new ArmThumbFilter(); + ia64Filter = new IA64Filter(); + ppcFilter = new PowerPCFilter(); + sparcFilter = new SparcFilter(); + x86Filter = new X86Filter(); + } - public BCJTests() - { - armFilter = new ArmFilter(); - armtFilter = new ArmThumbFilter(); - ia64Filter = new IA64Filter(); - ppcFilter = new PowerPCFilter(); - sparcFilter = new SparcFilter(); - x86Filter = new X86Filter(); - } + [Fact] + public void IsOnlyAllowedLast() + { + Assert.False(armFilter.AllowAsLast); + Assert.True(armFilter.AllowAsNonLast); - [Fact] - public void IsOnlyAllowedLast() - { - Assert.False(armFilter.AllowAsLast); - Assert.True(armFilter.AllowAsNonLast); + Assert.False(armtFilter.AllowAsLast); + Assert.True(armtFilter.AllowAsNonLast); - Assert.False(armtFilter.AllowAsLast); - Assert.True(armtFilter.AllowAsNonLast); + Assert.False(ia64Filter.AllowAsLast); + Assert.True(ia64Filter.AllowAsNonLast); - Assert.False(ia64Filter.AllowAsLast); - Assert.True(ia64Filter.AllowAsNonLast); + Assert.False(ppcFilter.AllowAsLast); + Assert.True(ppcFilter.AllowAsNonLast); - Assert.False(ppcFilter.AllowAsLast); - Assert.True(ppcFilter.AllowAsNonLast); + Assert.False(sparcFilter.AllowAsLast); + Assert.True(sparcFilter.AllowAsNonLast); - Assert.False(sparcFilter.AllowAsLast); - Assert.True(sparcFilter.AllowAsNonLast); + Assert.False(x86Filter.AllowAsLast); + Assert.True(x86Filter.AllowAsNonLast); + } - Assert.False(x86Filter.AllowAsLast); - Assert.True(x86Filter.AllowAsNonLast); - } + [Fact] + public void ChangesStreamSize() + { + Assert.False(armFilter.ChangesDataSize); + Assert.False(armtFilter.ChangesDataSize); + Assert.False(ia64Filter.ChangesDataSize); + Assert.False(ppcFilter.ChangesDataSize); + Assert.False(sparcFilter.ChangesDataSize); + Assert.False(x86Filter.ChangesDataSize); + } - [Fact] - public void ChangesStreamSize() - { - Assert.False(armFilter.ChangesDataSize); - Assert.False(armtFilter.ChangesDataSize); - Assert.False(ia64Filter.ChangesDataSize); - Assert.False(ppcFilter.ChangesDataSize); - Assert.False(sparcFilter.ChangesDataSize); - Assert.False(x86Filter.ChangesDataSize); - } + [Theory] + [InlineData(new byte[] { 0 })] + [InlineData(new byte[] { 0, 0, 0, 0, 0 })] + public void OnlyAcceptsOneByte(byte[] bytes) + { + InvalidDataException ex; + ex = Assert.Throws(() => armFilter.Init(bytes)); + Assert.Equal("ARM properties unexpected length", ex.Message); - [Theory] - [InlineData(new byte[] { 0 })] - [InlineData(new byte[] { 0, 0, 0, 0, 0 })] - public void OnlyAcceptsOneByte(byte[] bytes) - { - InvalidDataException ex; - ex = Assert.Throws(() => armFilter.Init(bytes)); - Assert.Equal("ARM properties unexpected length", ex.Message); + ex = Assert.Throws(() => armtFilter.Init(bytes)); + Assert.Equal("ARM Thumb properties unexpected length", ex.Message); - ex = Assert.Throws(() => armtFilter.Init(bytes)); - Assert.Equal("ARM Thumb properties unexpected length", ex.Message); + ex = Assert.Throws(() => ia64Filter.Init(bytes)); + Assert.Equal("IA64 properties unexpected length", ex.Message); - ex = Assert.Throws(() => ia64Filter.Init(bytes)); - Assert.Equal("IA64 properties unexpected length", ex.Message); + ex = Assert.Throws(() => ppcFilter.Init(bytes)); + Assert.Equal("PPC properties unexpected length", ex.Message); - ex = Assert.Throws(() => ppcFilter.Init(bytes)); - Assert.Equal("PPC properties unexpected length", ex.Message); + ex = Assert.Throws(() => sparcFilter.Init(bytes)); + Assert.Equal("SPARC properties unexpected length", ex.Message); - ex = Assert.Throws(() => sparcFilter.Init(bytes)); - Assert.Equal("SPARC properties unexpected length", ex.Message); - - ex = Assert.Throws(() => x86Filter.Init(bytes)); - Assert.Equal("X86 properties unexpected length", ex.Message); - } + ex = Assert.Throws(() => x86Filter.Init(bytes)); + Assert.Equal("X86 properties unexpected length", ex.Message); } } diff --git a/tests/SharpCompress.Test/Xz/Filters/Lzma2Tests.cs b/tests/SharpCompress.Test/Xz/Filters/Lzma2Tests.cs index 1f527452..fd6caf61 100644 --- a/tests/SharpCompress.Test/Xz/Filters/Lzma2Tests.cs +++ b/tests/SharpCompress.Test/Xz/Filters/Lzma2Tests.cs @@ -1,4 +1,4 @@ -using System; +using System; using Xunit; using System.IO; using SharpCompress.Compressors.Xz.Filters; diff --git a/tests/SharpCompress.Test/Xz/XZBlockTests.cs b/tests/SharpCompress.Test/Xz/XZBlockTests.cs index 0e070c67..4218fa36 100644 --- a/tests/SharpCompress.Test/Xz/XZBlockTests.cs +++ b/tests/SharpCompress.Test/Xz/XZBlockTests.cs @@ -1,107 +1,102 @@ -using System.Text; using System.IO; +using System.Text; using SharpCompress.Compressors.Xz; using Xunit; -namespace SharpCompress.Test.Xz +namespace SharpCompress.Test.Xz; + +public class XZBlockTests : XZTestsBase { - public class XZBlockTests : XZTestsBase + protected override void Rewind(Stream stream) { - protected override void Rewind(Stream stream) + stream.Position = 12; + } + + protected override void RewindIndexed(Stream stream) + { + stream.Position = 12; + } + + private byte[] ReadBytes(XZBlock block, int bytesToRead) + { + var buffer = new byte[bytesToRead]; + var read = block.Read(buffer, 0, bytesToRead); + if (read != bytesToRead) { - stream.Position = 12; + throw new EndOfStreamException(); } - protected override void RewindIndexed(Stream stream) - { - stream.Position = 12; - } + return buffer; + } - private byte[] ReadBytes(XZBlock block, int bytesToRead) + [Fact] + public void OnFindIndexBlockThrow() + { + var bytes = new byte[] { 0 }; + using Stream indexBlockStream = new MemoryStream(bytes); + var XZBlock = new XZBlock(indexBlockStream, CheckType.CRC64, 8); + Assert.Throws(() => { - byte[] buffer = new byte[bytesToRead]; - var read = block.Read(buffer, 0, bytesToRead); - if (read != bytesToRead) - { - throw new EndOfStreamException(); - } + ReadBytes(XZBlock, 1); + }); + } - return buffer; - } - - [Fact] - public void OnFindIndexBlockThrow() + [Fact] + public void CrcIncorrectThrows() + { + var bytes = (byte[])Compressed.Clone(); + bytes[20]++; + using Stream badCrcStream = new MemoryStream(bytes); + Rewind(badCrcStream); + var XZBlock = new XZBlock(badCrcStream, CheckType.CRC64, 8); + var ex = Assert.Throws(() => { - var bytes = new byte[] { 0 }; - using (Stream indexBlockStream = new MemoryStream(bytes)) - { - var XZBlock = new XZBlock(indexBlockStream, CheckType.CRC64, 8); - Assert.Throws(() => - { - ReadBytes(XZBlock, 1); - }); - } - } + ReadBytes(XZBlock, 1); + }); + Assert.Equal("Block header corrupt", ex.Message); + } - [Fact] - public void CrcIncorrectThrows() - { - var bytes = (byte[])Compressed.Clone(); - bytes[20]++; - using (Stream badCrcStream = new MemoryStream(bytes)) - { - Rewind(badCrcStream); - var XZBlock = new XZBlock(badCrcStream, CheckType.CRC64, 8); - var ex = Assert.Throws(() => - { - ReadBytes(XZBlock, 1); - }); - Assert.Equal("Block header corrupt", ex.Message); - } - } + [Fact] + public void CanReadM() + { + var XZBlock = new XZBlock(CompressedStream, CheckType.CRC64, 8); + Assert.Equal(Encoding.ASCII.GetBytes("M"), ReadBytes(XZBlock, 1)); + } - [Fact] - public void CanReadM() - { - var XZBlock = new XZBlock(CompressedStream, CheckType.CRC64, 8); - Assert.Equal(Encoding.ASCII.GetBytes("M"), ReadBytes(XZBlock, 1)); - } + [Fact] + public void CanReadMary() + { + var XZBlock = new XZBlock(CompressedStream, CheckType.CRC64, 8); + Assert.Equal(Encoding.ASCII.GetBytes("M"), ReadBytes(XZBlock, 1)); + Assert.Equal(Encoding.ASCII.GetBytes("a"), ReadBytes(XZBlock, 1)); + Assert.Equal(Encoding.ASCII.GetBytes("ry"), ReadBytes(XZBlock, 2)); + } - [Fact] - public void CanReadMary() - { - var XZBlock = new XZBlock(CompressedStream, CheckType.CRC64, 8); - Assert.Equal(Encoding.ASCII.GetBytes("M"), ReadBytes(XZBlock, 1)); - Assert.Equal(Encoding.ASCII.GetBytes("a"), ReadBytes(XZBlock, 1)); - Assert.Equal(Encoding.ASCII.GetBytes("ry"), ReadBytes(XZBlock, 2)); - } + [Fact] + public void CanReadPoemWithStreamReader() + { + var XZBlock = new XZBlock(CompressedStream, CheckType.CRC64, 8); + var sr = new StreamReader(XZBlock); + Assert.Equal(sr.ReadToEnd(), Original); + } - [Fact] - public void CanReadPoemWithStreamReader() - { - var XZBlock = new XZBlock(CompressedStream, CheckType.CRC64, 8); - var sr = new StreamReader(XZBlock); - Assert.Equal(sr.ReadToEnd(), Original); - } + [Fact] + public void NoopWhenNoPadding() + { + // CompressedStream's only block has no padding. + var XZBlock = new XZBlock(CompressedStream, CheckType.CRC64, 8); + var sr = new StreamReader(XZBlock); + sr.ReadToEnd(); + Assert.Equal(0L, CompressedStream.Position % 4L); + } - [Fact] - public void NoopWhenNoPadding() - { - // CompressedStream's only block has no padding. - var XZBlock = new XZBlock(CompressedStream, CheckType.CRC64, 8); - var sr = new StreamReader(XZBlock); - sr.ReadToEnd(); - Assert.Equal(0L, CompressedStream.Position % 4L); - } - - [Fact] - public void SkipsPaddingWhenPresent() - { - // CompressedIndexedStream's first block has 1-byte padding. - var XZBlock = new XZBlock(CompressedIndexedStream, CheckType.CRC64, 8); - var sr = new StreamReader(XZBlock); - sr.ReadToEnd(); - Assert.Equal(0L, CompressedIndexedStream.Position % 4L); - } + [Fact] + public void SkipsPaddingWhenPresent() + { + // CompressedIndexedStream's first block has 1-byte padding. + var XZBlock = new XZBlock(CompressedIndexedStream, CheckType.CRC64, 8); + var sr = new StreamReader(XZBlock); + sr.ReadToEnd(); + Assert.Equal(0L, CompressedIndexedStream.Position % 4L); } } diff --git a/tests/SharpCompress.Test/Xz/XZHeaderTests.cs b/tests/SharpCompress.Test/Xz/XZHeaderTests.cs index 30893fbc..db1f876d 100644 --- a/tests/SharpCompress.Test/Xz/XZHeaderTests.cs +++ b/tests/SharpCompress.Test/Xz/XZHeaderTests.cs @@ -1,4 +1,4 @@ -using SharpCompress.Compressors.Xz; +using SharpCompress.Compressors.Xz; using System.IO; using Xunit; diff --git a/tests/SharpCompress.Test/Xz/XZIndexTests.cs b/tests/SharpCompress.Test/Xz/XZIndexTests.cs index 898d71f4..ecc249e0 100644 --- a/tests/SharpCompress.Test/Xz/XZIndexTests.cs +++ b/tests/SharpCompress.Test/Xz/XZIndexTests.cs @@ -1,4 +1,4 @@ -using SharpCompress.Compressors.Xz; +using SharpCompress.Compressors.Xz; using System.IO; using Xunit; diff --git a/tests/SharpCompress.Test/Xz/XZStreamTests.cs b/tests/SharpCompress.Test/Xz/XZStreamTests.cs index 4b6bbaf6..fea155de 100644 --- a/tests/SharpCompress.Test/Xz/XZStreamTests.cs +++ b/tests/SharpCompress.Test/Xz/XZStreamTests.cs @@ -1,4 +1,4 @@ -using SharpCompress.Compressors.Xz; +using SharpCompress.Compressors.Xz; using System.IO; using Xunit; diff --git a/tests/SharpCompress.Test/Xz/XZTestsBase.cs b/tests/SharpCompress.Test/Xz/XZTestsBase.cs index e5a3b53c..2e931820 100644 --- a/tests/SharpCompress.Test/Xz/XZTestsBase.cs +++ b/tests/SharpCompress.Test/Xz/XZTestsBase.cs @@ -1,1150 +1,1149 @@ -using System; -using System.Text; +using System; using System.IO; +using System.Text; -namespace SharpCompress.Test.Xz +namespace SharpCompress.Test.Xz; + +public abstract class XZTestsBase : IDisposable { - public abstract class XZTestsBase : IDisposable + public XZTestsBase() { - public XZTestsBase() - { - RewindEmpty(CompressedEmptyStream); - Rewind(CompressedStream); - RewindIndexed(CompressedIndexedStream); - } - - public void Dispose() - { - CompressedEmptyStream?.Dispose(); - CompressedStream?.Dispose(); - CompressedIndexedStream?.Dispose(); - } - - protected virtual void RewindEmpty(Stream stream) - { - stream.Position = 0; - } - - protected virtual void Rewind(Stream stream) - { - stream.Position = 0; - } - - protected virtual void RewindIndexed(Stream stream) - { - stream.Position = 0; - } - - protected Stream CompressedEmptyStream { get; } = new MemoryStream(CompressedEmpty); - - protected static byte[] CompressedEmpty { get; } = - new byte[] - { - 0xfd, - 0x37, - 0x7a, - 0x58, - 0x5a, - 0x00, - 0x00, - 0x01, - 0x69, - 0x22, - 0xde, - 0x36, - 0x00, - 0x00, - 0x00, - 0x00, - 0x1c, - 0xdf, - 0x44, - 0x21, - 0x90, - 0x42, - 0x99, - 0x0d, - 0x01, - 0x00, - 0x00, - 0x00, - 0x00, - 0x01, - 0x59, - 0x5a - }; - - protected static byte[] OriginalEmptyBytes => Encoding.ASCII.GetBytes(OriginalEmpty); - - protected static string OriginalEmpty { get; } = string.Empty; - - protected Stream CompressedStream { get; } = new MemoryStream(Compressed); - - protected static byte[] Compressed { get; } = - new byte[] - { - 0xfd, - 0x37, - 0x7a, - 0x58, - 0x5a, - 0x00, - 0x00, - 0x04, - 0xe6, - 0xd6, - 0xb4, - 0x46, - 0x02, - 0x00, - 0x21, - 0x01, - 0x16, - 0x00, - 0x00, - 0x00, - 0x74, - 0x2f, - 0xe5, - 0xa3, - 0xe0, - 0x01, - 0xe4, - 0x01, - 0x3c, - 0x5d, - 0x00, - 0x26, - 0x98, - 0x4a, - 0x47, - 0xc6, - 0x6a, - 0x27, - 0xd7, - 0x36, - 0x7a, - 0x05, - 0xb9, - 0x4f, - 0xd7, - 0xde, - 0x52, - 0x4c, - 0xca, - 0x26, - 0x4f, - 0x23, - 0x60, - 0x4d, - 0xf3, - 0x1f, - 0xa3, - 0x67, - 0x49, - 0x53, - 0xd0, - 0xf5, - 0xc7, - 0xa9, - 0x3e, - 0xd6, - 0xb5, - 0x3d, - 0x2b, - 0x02, - 0xbe, - 0x83, - 0x27, - 0xe2, - 0xa6, - 0xc3, - 0x13, - 0x4a, - 0x31, - 0x14, - 0x33, - 0xed, - 0x9a, - 0x85, - 0x1d, - 0x05, - 0x6e, - 0x7e, - 0xa4, - 0x91, - 0xbf, - 0x46, - 0x71, - 0x7d, - 0xa7, - 0xfb, - 0x12, - 0x10, - 0xdf, - 0x21, - 0x73, - 0x75, - 0xd8, - 0xd9, - 0xab, - 0x8f, - 0x1f, - 0x8b, - 0xb0, - 0xb9, - 0x3f, - 0x9a, - 0xa5, - 0x1e, - 0xd4, - 0x2f, - 0xdf, - 0x09, - 0xb3, - 0xfe, - 0x45, - 0xef, - 0x16, - 0xec, - 0x95, - 0x68, - 0x64, - 0xbb, - 0x42, - 0x0c, - 0x8b, - 0x96, - 0x27, - 0x30, - 0x62, - 0x42, - 0x91, - 0x7c, - 0xf3, - 0x6e, - 0x4d, - 0x03, - 0xc5, - 0x00, - 0x04, - 0x73, - 0xdd, - 0xee, - 0xb0, - 0xaa, - 0xd6, - 0x0b, - 0x11, - 0x90, - 0x81, - 0xd4, - 0xaa, - 0x69, - 0x63, - 0xfa, - 0x2f, - 0xb4, - 0x25, - 0x0a, - 0x7f, - 0xf9, - 0x47, - 0x77, - 0xb1, - 0x1f, - 0xc3, - 0xb4, - 0x4d, - 0x51, - 0xf8, - 0x23, - 0x3a, - 0x7c, - 0x44, - 0xc8, - 0xcc, - 0xca, - 0x72, - 0x09, - 0xae, - 0xc9, - 0x7b, - 0x7e, - 0x91, - 0x5d, - 0xff, - 0xc4, - 0xeb, - 0xfd, - 0xa1, - 0x9b, - 0xd4, - 0x8d, - 0xd7, - 0xd3, - 0x57, - 0xac, - 0x7e, - 0x3b, - 0x97, - 0x2e, - 0xe4, - 0xc2, - 0x2e, - 0x93, - 0x3d, - 0xb0, - 0x16, - 0x64, - 0x78, - 0x45, - 0xb1, - 0xc9, - 0x40, - 0x96, - 0xcf, - 0x5b, - 0xc2, - 0x2f, - 0xaa, - 0xba, - 0xcf, - 0x98, - 0x38, - 0x21, - 0x3d, - 0x1a, - 0x13, - 0xe8, - 0xa6, - 0xa6, - 0xdf, - 0xf4, - 0x3d, - 0x01, - 0xa1, - 0x9d, - 0xc1, - 0x3e, - 0x37, - 0xac, - 0x20, - 0xc4, - 0xef, - 0x18, - 0xb1, - 0xeb, - 0x35, - 0xf4, - 0x66, - 0x9a, - 0x47, - 0x3c, - 0xce, - 0x7c, - 0xad, - 0xdb, - 0x2e, - 0x39, - 0xf5, - 0x8d, - 0x4a, - 0x1d, - 0x65, - 0xc2, - 0x0f, - 0xa4, - 0x40, - 0x7e, - 0xe6, - 0xa7, - 0x17, - 0xce, - 0x75, - 0x7f, - 0xd9, - 0xa3, - 0xf9, - 0x27, - 0x42, - 0xd7, - 0x98, - 0x54, - 0x17, - 0xa7, - 0x7a, - 0x7c, - 0x82, - 0xdf, - 0xeb, - 0x08, - 0x28, - 0x86, - 0xdd, - 0x57, - 0x77, - 0x92, - 0x80, - 0x5f, - 0x7b, - 0x3b, - 0xce, - 0x77, - 0x72, - 0xff, - 0xa3, - 0x85, - 0xd8, - 0x5c, - 0x8a, - 0xb7, - 0x83, - 0x58, - 0xfa, - 0xbd, - 0x72, - 0xe3, - 0x66, - 0x9d, - 0x3b, - 0xff, - 0x13, - 0x5b, - 0x0b, - 0xf1, - 0x6c, - 0xa6, - 0xb1, - 0x3b, - 0x85, - 0x3b, - 0x47, - 0x91, - 0xc8, - 0x7c, - 0x38, - 0xe2, - 0xe5, - 0x54, - 0xf8, - 0x27, - 0xee, - 0x00, - 0xff, - 0xd3, - 0x68, - 0xf1, - 0xc6, - 0xc7, - 0xd7, - 0x24, - 0x00, - 0x01, - 0xd8, - 0x02, - 0xe5, - 0x03, - 0x00, - 0x00, - 0xac, - 0x16, - 0x1f, - 0xa4, - 0xb1, - 0xc4, - 0x67, - 0xfb, - 0x02, - 0x00, - 0x00, - 0x00, - 0x00, - 0x04, - 0x59, - 0x5a - }; - protected static byte[] OriginalBytes => Encoding.ASCII.GetBytes(Original); - - protected static string Original { get; } = - "Mary had a little lamb,\r\n" - + "His fleece was white as snow,\r\n" - + "And everywhere that Mary went,\r\n" - + "The lamb was sure to go.\r\n" - + "\r\n" - + "He followed her to school one day,\r\n" - + "Which was against the rule,\r\n" - + "It made the children laugh and play\r\n" - + "To see a lamb at school.\r\n" - + "\r\n" - + "And so the teacher turned it out,\r\n" - + "But still it lingered near,\r\n" - + "And waited patiently about,\r\n" - + "Till Mary did appear.\r\n" - + "\r\n" - + "\"Why does the lamb love Mary so?\"\r\n" - + "The eager children cry.\r\n" - + "\"Why, Mary loves the lamb, you know.\"\r\n" - + "The teacher did reply."; - - protected Stream CompressedIndexedStream { get; } = new MemoryStream(CompressedIndexed); - - protected static byte[] CompressedIndexed { get; } = - new byte[] - { - 0xfd, - 0x37, - 0x7a, - 0x58, - 0x5a, - 0x00, - 0x00, - 0x01, - 0x69, - 0x22, - 0xde, - 0x36, - 0x03, - 0xc0, - 0xe3, - 0x02, - 0x80, - 0x20, - 0x21, - 0x01, - 0x00, - 0x00, - 0x00, - 0x00, - 0x7e, - 0xe5, - 0xd7, - 0x32, - 0xe0, - 0x0f, - 0xff, - 0x01, - 0x5b, - 0x5d, - 0x00, - 0x26, - 0x98, - 0x4a, - 0x47, - 0xc6, - 0x6a, - 0x27, - 0xd7, - 0x36, - 0x7a, - 0x05, - 0xb9, - 0x4f, - 0xd7, - 0xde, - 0x3a, - 0x0e, - 0xee, - 0x1b, - 0xd7, - 0x81, - 0xe9, - 0xf5, - 0x90, - 0x1e, - 0xd5, - 0x9e, - 0x88, - 0x32, - 0x1c, - 0x7b, - 0x43, - 0x84, - 0x02, - 0x58, - 0x92, - 0xcf, - 0x97, - 0xfc, - 0xae, - 0x01, - 0x83, - 0x23, - 0x48, - 0x93, - 0xc6, - 0x56, - 0xcc, - 0x6d, - 0xb1, - 0x23, - 0x10, - 0x24, - 0x3b, - 0x9e, - 0x06, - 0xaa, - 0xc0, - 0xce, - 0x86, - 0x0a, - 0xb7, - 0x9f, - 0x99, - 0x61, - 0xbe, - 0x3b, - 0x6d, - 0xfe, - 0x60, - 0xef, - 0x14, - 0x35, - 0x7f, - 0x21, - 0xe8, - 0x96, - 0x0e, - 0xbd, - 0x41, - 0x7c, - 0x65, - 0x89, - 0x96, - 0x28, - 0x5e, - 0x85, - 0xa6, - 0x4b, - 0xf3, - 0xf9, - 0xf8, - 0x25, - 0x31, - 0x4a, - 0xbb, - 0x72, - 0xce, - 0xcf, - 0x53, - 0xdf, - 0x13, - 0x42, - 0x2d, - 0xbc, - 0x95, - 0xa5, - 0x6d, - 0xc4, - 0x8c, - 0x72, - 0x99, - 0xe8, - 0x9a, - 0xcf, - 0x80, - 0xd4, - 0xc4, - 0x3f, - 0x55, - 0xc3, - 0x9b, - 0x00, - 0xce, - 0x65, - 0x27, - 0x6e, - 0xbf, - 0xb2, - 0x88, - 0xab, - 0xc0, - 0x5f, - 0xf9, - 0xd0, - 0xc8, - 0xbb, - 0xd7, - 0x48, - 0xd7, - 0x2e, - 0x5e, - 0xbb, - 0x23, - 0x35, - 0x6e, - 0x62, - 0xb6, - 0x13, - 0xd4, - 0x06, - 0xd1, - 0x5b, - 0x97, - 0xee, - 0x5b, - 0x89, - 0x78, - 0x07, - 0x24, - 0x74, - 0x59, - 0x06, - 0x1e, - 0x7f, - 0x8c, - 0xb0, - 0x48, - 0xff, - 0x0a, - 0x76, - 0xb2, - 0x07, - 0xa0, - 0x99, - 0xf5, - 0x4b, - 0x68, - 0xd4, - 0x55, - 0x32, - 0xb3, - 0x17, - 0x7b, - 0xb6, - 0x26, - 0xdb, - 0x1c, - 0xc3, - 0x0b, - 0xda, - 0x3e, - 0x46, - 0xba, - 0x1a, - 0x67, - 0x23, - 0xb7, - 0x2a, - 0x40, - 0xdc, - 0xc9, - 0xa2, - 0xe4, - 0xb5, - 0x68, - 0x5c, - 0x81, - 0x60, - 0xa7, - 0xad, - 0xe6, - 0xba, - 0xbb, - 0x0d, - 0x82, - 0x8a, - 0xe2, - 0x03, - 0xa9, - 0x22, - 0x09, - 0x5e, - 0xd8, - 0x69, - 0xfa, - 0x29, - 0xd1, - 0x32, - 0xa1, - 0xf0, - 0x9b, - 0x3c, - 0xc3, - 0x0b, - 0x9a, - 0x53, - 0xf0, - 0x3e, - 0xf3, - 0x1b, - 0x77, - 0xee, - 0x8f, - 0xa6, - 0x15, - 0x02, - 0x77, - 0x14, - 0x54, - 0x60, - 0xae, - 0xbe, - 0x91, - 0x9e, - 0xe6, - 0x8b, - 0x87, - 0x6e, - 0x46, - 0x44, - 0x64, - 0xc7, - 0x58, - 0x90, - 0x62, - 0x25, - 0x32, - 0xf9, - 0xcd, - 0xd2, - 0x73, - 0x2e, - 0x3f, - 0xd7, - 0x5d, - 0x3c, - 0x86, - 0x1c, - 0xa8, - 0x35, - 0xa9, - 0xc2, - 0xcb, - 0x59, - 0xcb, - 0xac, - 0xb3, - 0x03, - 0x12, - 0xd4, - 0x8a, - 0xde, - 0xd5, - 0xc1, - 0xd8, - 0x0c, - 0x32, - 0x49, - 0x87, - 0x97, - 0x62, - 0x4f, - 0x32, - 0x39, - 0x63, - 0x5b, - 0x8b, - 0xd1, - 0x6c, - 0x5c, - 0x90, - 0xd9, - 0x93, - 0x13, - 0xae, - 0x70, - 0xf5, - 0x2f, - 0x40, - 0xaf, - 0x01, - 0x95, - 0x01, - 0x0c, - 0xc5, - 0xfa, - 0x82, - 0xf8, - 0x71, - 0x9d, - 0x53, - 0xe6, - 0x47, - 0x6e, - 0x99, - 0x54, - 0x57, - 0x41, - 0x72, - 0xea, - 0xf5, - 0x78, - 0xdd, - 0x86, - 0xbd, - 0x00, - 0x00, - 0x00, - 0x72, - 0x6a, - 0xf2, - 0x47, - 0x03, - 0xc0, - 0xcb, - 0x01, - 0x8d, - 0x02, - 0x21, - 0x01, - 0x00, - 0x00, - 0x00, - 0x00, - 0xfb, - 0xa7, - 0xf7, - 0x94, - 0xe0, - 0x01, - 0x0c, - 0x00, - 0xc3, - 0x5d, - 0x00, - 0x06, - 0x82, - 0xca, - 0x9b, - 0x77, - 0x93, - 0x57, - 0xb3, - 0x76, - 0xbd, - 0x8b, - 0xcb, - 0xee, - 0xf4, - 0x2c, - 0xff, - 0x7f, - 0x95, - 0x33, - 0x15, - 0x10, - 0xa5, - 0xf9, - 0xfd, - 0xa6, - 0xbb, - 0x9e, - 0xf9, - 0x75, - 0x67, - 0xee, - 0xec, - 0x8b, - 0x40, - 0xea, - 0x32, - 0x47, - 0x3d, - 0x26, - 0xbe, - 0x11, - 0x9c, - 0xa6, - 0x40, - 0xbe, - 0x84, - 0x1f, - 0x1b, - 0x35, - 0x1a, - 0x66, - 0x10, - 0x9c, - 0xf4, - 0x12, - 0x1a, - 0x95, - 0x81, - 0xb5, - 0x55, - 0x6b, - 0xc5, - 0x42, - 0xfd, - 0x37, - 0x70, - 0xc5, - 0x08, - 0xa4, - 0x27, - 0x67, - 0x11, - 0x0b, - 0x1f, - 0xcc, - 0xdb, - 0x54, - 0x9b, - 0x5a, - 0x5f, - 0xee, - 0x21, - 0x63, - 0xdd, - 0x4b, - 0xbc, - 0x49, - 0x95, - 0x6d, - 0xf4, - 0xcb, - 0x9a, - 0x9a, - 0x5e, - 0xe4, - 0x7d, - 0x0f, - 0x02, - 0x22, - 0xa9, - 0x42, - 0x46, - 0x1a, - 0x04, - 0x87, - 0x43, - 0x72, - 0x59, - 0xa4, - 0xd6, - 0xeb, - 0x69, - 0x36, - 0xde, - 0xea, - 0x53, - 0x8c, - 0x89, - 0xd7, - 0x22, - 0xa6, - 0xf7, - 0xa8, - 0x4c, - 0x72, - 0x6c, - 0x80, - 0x69, - 0x01, - 0xb2, - 0xa7, - 0xe8, - 0x8b, - 0x94, - 0xaf, - 0x0e, - 0x47, - 0x58, - 0x1d, - 0x0e, - 0x5c, - 0x7c, - 0x33, - 0x9f, - 0x21, - 0x17, - 0x2c, - 0x4f, - 0x3d, - 0x72, - 0xff, - 0xcf, - 0x7a, - 0x4f, - 0x82, - 0x5b, - 0x85, - 0x28, - 0x70, - 0xf4, - 0x8c, - 0x81, - 0x41, - 0xb8, - 0x20, - 0x5c, - 0x3e, - 0x02, - 0x5e, - 0x5a, - 0x61, - 0xbb, - 0x2f, - 0x64, - 0xc5, - 0x4e, - 0x53, - 0xe4, - 0xca, - 0xe4, - 0xd9, - 0x75, - 0xaf, - 0x15, - 0x4d, - 0xff, - 0x01, - 0xec, - 0x13, - 0x4a, - 0x70, - 0x00, - 0x04, - 0xf9, - 0xfa, - 0x00, - 0x00, - 0x99, - 0x57, - 0xc4, - 0x96, - 0x00, - 0x02, - 0xf7, - 0x02, - 0x80, - 0x20, - 0xdf, - 0x01, - 0x8d, - 0x02, - 0x00, - 0x00, - 0x4c, - 0x41, - 0xe6, - 0xa1, - 0x9b, - 0xe3, - 0x51, - 0x40, - 0x03, - 0x00, - 0x00, - 0x00, - 0x00, - 0x01, - 0x59, - 0x5a - }; - - protected static byte[] OriginalIndexedBytes => Encoding.ASCII.GetBytes(OriginalIndexed); - - protected static string OriginalIndexed { get; } = - Original - + Original - + Original - + Original - + Original - + Original - + Original - + Original - + Original; + RewindEmpty(CompressedEmptyStream); + Rewind(CompressedStream); + RewindIndexed(CompressedIndexedStream); } + + public void Dispose() + { + CompressedEmptyStream?.Dispose(); + CompressedStream?.Dispose(); + CompressedIndexedStream?.Dispose(); + } + + protected virtual void RewindEmpty(Stream stream) + { + stream.Position = 0; + } + + protected virtual void Rewind(Stream stream) + { + stream.Position = 0; + } + + protected virtual void RewindIndexed(Stream stream) + { + stream.Position = 0; + } + + protected Stream CompressedEmptyStream { get; } = new MemoryStream(CompressedEmpty); + + protected static byte[] CompressedEmpty { get; } = + new byte[] + { + 0xfd, + 0x37, + 0x7a, + 0x58, + 0x5a, + 0x00, + 0x00, + 0x01, + 0x69, + 0x22, + 0xde, + 0x36, + 0x00, + 0x00, + 0x00, + 0x00, + 0x1c, + 0xdf, + 0x44, + 0x21, + 0x90, + 0x42, + 0x99, + 0x0d, + 0x01, + 0x00, + 0x00, + 0x00, + 0x00, + 0x01, + 0x59, + 0x5a + }; + + protected static byte[] OriginalEmptyBytes => Encoding.ASCII.GetBytes(OriginalEmpty); + + protected static string OriginalEmpty { get; } = string.Empty; + + protected Stream CompressedStream { get; } = new MemoryStream(Compressed); + + protected static byte[] Compressed { get; } = + new byte[] + { + 0xfd, + 0x37, + 0x7a, + 0x58, + 0x5a, + 0x00, + 0x00, + 0x04, + 0xe6, + 0xd6, + 0xb4, + 0x46, + 0x02, + 0x00, + 0x21, + 0x01, + 0x16, + 0x00, + 0x00, + 0x00, + 0x74, + 0x2f, + 0xe5, + 0xa3, + 0xe0, + 0x01, + 0xe4, + 0x01, + 0x3c, + 0x5d, + 0x00, + 0x26, + 0x98, + 0x4a, + 0x47, + 0xc6, + 0x6a, + 0x27, + 0xd7, + 0x36, + 0x7a, + 0x05, + 0xb9, + 0x4f, + 0xd7, + 0xde, + 0x52, + 0x4c, + 0xca, + 0x26, + 0x4f, + 0x23, + 0x60, + 0x4d, + 0xf3, + 0x1f, + 0xa3, + 0x67, + 0x49, + 0x53, + 0xd0, + 0xf5, + 0xc7, + 0xa9, + 0x3e, + 0xd6, + 0xb5, + 0x3d, + 0x2b, + 0x02, + 0xbe, + 0x83, + 0x27, + 0xe2, + 0xa6, + 0xc3, + 0x13, + 0x4a, + 0x31, + 0x14, + 0x33, + 0xed, + 0x9a, + 0x85, + 0x1d, + 0x05, + 0x6e, + 0x7e, + 0xa4, + 0x91, + 0xbf, + 0x46, + 0x71, + 0x7d, + 0xa7, + 0xfb, + 0x12, + 0x10, + 0xdf, + 0x21, + 0x73, + 0x75, + 0xd8, + 0xd9, + 0xab, + 0x8f, + 0x1f, + 0x8b, + 0xb0, + 0xb9, + 0x3f, + 0x9a, + 0xa5, + 0x1e, + 0xd4, + 0x2f, + 0xdf, + 0x09, + 0xb3, + 0xfe, + 0x45, + 0xef, + 0x16, + 0xec, + 0x95, + 0x68, + 0x64, + 0xbb, + 0x42, + 0x0c, + 0x8b, + 0x96, + 0x27, + 0x30, + 0x62, + 0x42, + 0x91, + 0x7c, + 0xf3, + 0x6e, + 0x4d, + 0x03, + 0xc5, + 0x00, + 0x04, + 0x73, + 0xdd, + 0xee, + 0xb0, + 0xaa, + 0xd6, + 0x0b, + 0x11, + 0x90, + 0x81, + 0xd4, + 0xaa, + 0x69, + 0x63, + 0xfa, + 0x2f, + 0xb4, + 0x25, + 0x0a, + 0x7f, + 0xf9, + 0x47, + 0x77, + 0xb1, + 0x1f, + 0xc3, + 0xb4, + 0x4d, + 0x51, + 0xf8, + 0x23, + 0x3a, + 0x7c, + 0x44, + 0xc8, + 0xcc, + 0xca, + 0x72, + 0x09, + 0xae, + 0xc9, + 0x7b, + 0x7e, + 0x91, + 0x5d, + 0xff, + 0xc4, + 0xeb, + 0xfd, + 0xa1, + 0x9b, + 0xd4, + 0x8d, + 0xd7, + 0xd3, + 0x57, + 0xac, + 0x7e, + 0x3b, + 0x97, + 0x2e, + 0xe4, + 0xc2, + 0x2e, + 0x93, + 0x3d, + 0xb0, + 0x16, + 0x64, + 0x78, + 0x45, + 0xb1, + 0xc9, + 0x40, + 0x96, + 0xcf, + 0x5b, + 0xc2, + 0x2f, + 0xaa, + 0xba, + 0xcf, + 0x98, + 0x38, + 0x21, + 0x3d, + 0x1a, + 0x13, + 0xe8, + 0xa6, + 0xa6, + 0xdf, + 0xf4, + 0x3d, + 0x01, + 0xa1, + 0x9d, + 0xc1, + 0x3e, + 0x37, + 0xac, + 0x20, + 0xc4, + 0xef, + 0x18, + 0xb1, + 0xeb, + 0x35, + 0xf4, + 0x66, + 0x9a, + 0x47, + 0x3c, + 0xce, + 0x7c, + 0xad, + 0xdb, + 0x2e, + 0x39, + 0xf5, + 0x8d, + 0x4a, + 0x1d, + 0x65, + 0xc2, + 0x0f, + 0xa4, + 0x40, + 0x7e, + 0xe6, + 0xa7, + 0x17, + 0xce, + 0x75, + 0x7f, + 0xd9, + 0xa3, + 0xf9, + 0x27, + 0x42, + 0xd7, + 0x98, + 0x54, + 0x17, + 0xa7, + 0x7a, + 0x7c, + 0x82, + 0xdf, + 0xeb, + 0x08, + 0x28, + 0x86, + 0xdd, + 0x57, + 0x77, + 0x92, + 0x80, + 0x5f, + 0x7b, + 0x3b, + 0xce, + 0x77, + 0x72, + 0xff, + 0xa3, + 0x85, + 0xd8, + 0x5c, + 0x8a, + 0xb7, + 0x83, + 0x58, + 0xfa, + 0xbd, + 0x72, + 0xe3, + 0x66, + 0x9d, + 0x3b, + 0xff, + 0x13, + 0x5b, + 0x0b, + 0xf1, + 0x6c, + 0xa6, + 0xb1, + 0x3b, + 0x85, + 0x3b, + 0x47, + 0x91, + 0xc8, + 0x7c, + 0x38, + 0xe2, + 0xe5, + 0x54, + 0xf8, + 0x27, + 0xee, + 0x00, + 0xff, + 0xd3, + 0x68, + 0xf1, + 0xc6, + 0xc7, + 0xd7, + 0x24, + 0x00, + 0x01, + 0xd8, + 0x02, + 0xe5, + 0x03, + 0x00, + 0x00, + 0xac, + 0x16, + 0x1f, + 0xa4, + 0xb1, + 0xc4, + 0x67, + 0xfb, + 0x02, + 0x00, + 0x00, + 0x00, + 0x00, + 0x04, + 0x59, + 0x5a + }; + protected static byte[] OriginalBytes => Encoding.ASCII.GetBytes(Original); + + protected static string Original { get; } = + "Mary had a little lamb,\r\n" + + "His fleece was white as snow,\r\n" + + "And everywhere that Mary went,\r\n" + + "The lamb was sure to go.\r\n" + + "\r\n" + + "He followed her to school one day,\r\n" + + "Which was against the rule,\r\n" + + "It made the children laugh and play\r\n" + + "To see a lamb at school.\r\n" + + "\r\n" + + "And so the teacher turned it out,\r\n" + + "But still it lingered near,\r\n" + + "And waited patiently about,\r\n" + + "Till Mary did appear.\r\n" + + "\r\n" + + "\"Why does the lamb love Mary so?\"\r\n" + + "The eager children cry.\r\n" + + "\"Why, Mary loves the lamb, you know.\"\r\n" + + "The teacher did reply."; + + protected Stream CompressedIndexedStream { get; } = new MemoryStream(CompressedIndexed); + + protected static byte[] CompressedIndexed { get; } = + new byte[] + { + 0xfd, + 0x37, + 0x7a, + 0x58, + 0x5a, + 0x00, + 0x00, + 0x01, + 0x69, + 0x22, + 0xde, + 0x36, + 0x03, + 0xc0, + 0xe3, + 0x02, + 0x80, + 0x20, + 0x21, + 0x01, + 0x00, + 0x00, + 0x00, + 0x00, + 0x7e, + 0xe5, + 0xd7, + 0x32, + 0xe0, + 0x0f, + 0xff, + 0x01, + 0x5b, + 0x5d, + 0x00, + 0x26, + 0x98, + 0x4a, + 0x47, + 0xc6, + 0x6a, + 0x27, + 0xd7, + 0x36, + 0x7a, + 0x05, + 0xb9, + 0x4f, + 0xd7, + 0xde, + 0x3a, + 0x0e, + 0xee, + 0x1b, + 0xd7, + 0x81, + 0xe9, + 0xf5, + 0x90, + 0x1e, + 0xd5, + 0x9e, + 0x88, + 0x32, + 0x1c, + 0x7b, + 0x43, + 0x84, + 0x02, + 0x58, + 0x92, + 0xcf, + 0x97, + 0xfc, + 0xae, + 0x01, + 0x83, + 0x23, + 0x48, + 0x93, + 0xc6, + 0x56, + 0xcc, + 0x6d, + 0xb1, + 0x23, + 0x10, + 0x24, + 0x3b, + 0x9e, + 0x06, + 0xaa, + 0xc0, + 0xce, + 0x86, + 0x0a, + 0xb7, + 0x9f, + 0x99, + 0x61, + 0xbe, + 0x3b, + 0x6d, + 0xfe, + 0x60, + 0xef, + 0x14, + 0x35, + 0x7f, + 0x21, + 0xe8, + 0x96, + 0x0e, + 0xbd, + 0x41, + 0x7c, + 0x65, + 0x89, + 0x96, + 0x28, + 0x5e, + 0x85, + 0xa6, + 0x4b, + 0xf3, + 0xf9, + 0xf8, + 0x25, + 0x31, + 0x4a, + 0xbb, + 0x72, + 0xce, + 0xcf, + 0x53, + 0xdf, + 0x13, + 0x42, + 0x2d, + 0xbc, + 0x95, + 0xa5, + 0x6d, + 0xc4, + 0x8c, + 0x72, + 0x99, + 0xe8, + 0x9a, + 0xcf, + 0x80, + 0xd4, + 0xc4, + 0x3f, + 0x55, + 0xc3, + 0x9b, + 0x00, + 0xce, + 0x65, + 0x27, + 0x6e, + 0xbf, + 0xb2, + 0x88, + 0xab, + 0xc0, + 0x5f, + 0xf9, + 0xd0, + 0xc8, + 0xbb, + 0xd7, + 0x48, + 0xd7, + 0x2e, + 0x5e, + 0xbb, + 0x23, + 0x35, + 0x6e, + 0x62, + 0xb6, + 0x13, + 0xd4, + 0x06, + 0xd1, + 0x5b, + 0x97, + 0xee, + 0x5b, + 0x89, + 0x78, + 0x07, + 0x24, + 0x74, + 0x59, + 0x06, + 0x1e, + 0x7f, + 0x8c, + 0xb0, + 0x48, + 0xff, + 0x0a, + 0x76, + 0xb2, + 0x07, + 0xa0, + 0x99, + 0xf5, + 0x4b, + 0x68, + 0xd4, + 0x55, + 0x32, + 0xb3, + 0x17, + 0x7b, + 0xb6, + 0x26, + 0xdb, + 0x1c, + 0xc3, + 0x0b, + 0xda, + 0x3e, + 0x46, + 0xba, + 0x1a, + 0x67, + 0x23, + 0xb7, + 0x2a, + 0x40, + 0xdc, + 0xc9, + 0xa2, + 0xe4, + 0xb5, + 0x68, + 0x5c, + 0x81, + 0x60, + 0xa7, + 0xad, + 0xe6, + 0xba, + 0xbb, + 0x0d, + 0x82, + 0x8a, + 0xe2, + 0x03, + 0xa9, + 0x22, + 0x09, + 0x5e, + 0xd8, + 0x69, + 0xfa, + 0x29, + 0xd1, + 0x32, + 0xa1, + 0xf0, + 0x9b, + 0x3c, + 0xc3, + 0x0b, + 0x9a, + 0x53, + 0xf0, + 0x3e, + 0xf3, + 0x1b, + 0x77, + 0xee, + 0x8f, + 0xa6, + 0x15, + 0x02, + 0x77, + 0x14, + 0x54, + 0x60, + 0xae, + 0xbe, + 0x91, + 0x9e, + 0xe6, + 0x8b, + 0x87, + 0x6e, + 0x46, + 0x44, + 0x64, + 0xc7, + 0x58, + 0x90, + 0x62, + 0x25, + 0x32, + 0xf9, + 0xcd, + 0xd2, + 0x73, + 0x2e, + 0x3f, + 0xd7, + 0x5d, + 0x3c, + 0x86, + 0x1c, + 0xa8, + 0x35, + 0xa9, + 0xc2, + 0xcb, + 0x59, + 0xcb, + 0xac, + 0xb3, + 0x03, + 0x12, + 0xd4, + 0x8a, + 0xde, + 0xd5, + 0xc1, + 0xd8, + 0x0c, + 0x32, + 0x49, + 0x87, + 0x97, + 0x62, + 0x4f, + 0x32, + 0x39, + 0x63, + 0x5b, + 0x8b, + 0xd1, + 0x6c, + 0x5c, + 0x90, + 0xd9, + 0x93, + 0x13, + 0xae, + 0x70, + 0xf5, + 0x2f, + 0x40, + 0xaf, + 0x01, + 0x95, + 0x01, + 0x0c, + 0xc5, + 0xfa, + 0x82, + 0xf8, + 0x71, + 0x9d, + 0x53, + 0xe6, + 0x47, + 0x6e, + 0x99, + 0x54, + 0x57, + 0x41, + 0x72, + 0xea, + 0xf5, + 0x78, + 0xdd, + 0x86, + 0xbd, + 0x00, + 0x00, + 0x00, + 0x72, + 0x6a, + 0xf2, + 0x47, + 0x03, + 0xc0, + 0xcb, + 0x01, + 0x8d, + 0x02, + 0x21, + 0x01, + 0x00, + 0x00, + 0x00, + 0x00, + 0xfb, + 0xa7, + 0xf7, + 0x94, + 0xe0, + 0x01, + 0x0c, + 0x00, + 0xc3, + 0x5d, + 0x00, + 0x06, + 0x82, + 0xca, + 0x9b, + 0x77, + 0x93, + 0x57, + 0xb3, + 0x76, + 0xbd, + 0x8b, + 0xcb, + 0xee, + 0xf4, + 0x2c, + 0xff, + 0x7f, + 0x95, + 0x33, + 0x15, + 0x10, + 0xa5, + 0xf9, + 0xfd, + 0xa6, + 0xbb, + 0x9e, + 0xf9, + 0x75, + 0x67, + 0xee, + 0xec, + 0x8b, + 0x40, + 0xea, + 0x32, + 0x47, + 0x3d, + 0x26, + 0xbe, + 0x11, + 0x9c, + 0xa6, + 0x40, + 0xbe, + 0x84, + 0x1f, + 0x1b, + 0x35, + 0x1a, + 0x66, + 0x10, + 0x9c, + 0xf4, + 0x12, + 0x1a, + 0x95, + 0x81, + 0xb5, + 0x55, + 0x6b, + 0xc5, + 0x42, + 0xfd, + 0x37, + 0x70, + 0xc5, + 0x08, + 0xa4, + 0x27, + 0x67, + 0x11, + 0x0b, + 0x1f, + 0xcc, + 0xdb, + 0x54, + 0x9b, + 0x5a, + 0x5f, + 0xee, + 0x21, + 0x63, + 0xdd, + 0x4b, + 0xbc, + 0x49, + 0x95, + 0x6d, + 0xf4, + 0xcb, + 0x9a, + 0x9a, + 0x5e, + 0xe4, + 0x7d, + 0x0f, + 0x02, + 0x22, + 0xa9, + 0x42, + 0x46, + 0x1a, + 0x04, + 0x87, + 0x43, + 0x72, + 0x59, + 0xa4, + 0xd6, + 0xeb, + 0x69, + 0x36, + 0xde, + 0xea, + 0x53, + 0x8c, + 0x89, + 0xd7, + 0x22, + 0xa6, + 0xf7, + 0xa8, + 0x4c, + 0x72, + 0x6c, + 0x80, + 0x69, + 0x01, + 0xb2, + 0xa7, + 0xe8, + 0x8b, + 0x94, + 0xaf, + 0x0e, + 0x47, + 0x58, + 0x1d, + 0x0e, + 0x5c, + 0x7c, + 0x33, + 0x9f, + 0x21, + 0x17, + 0x2c, + 0x4f, + 0x3d, + 0x72, + 0xff, + 0xcf, + 0x7a, + 0x4f, + 0x82, + 0x5b, + 0x85, + 0x28, + 0x70, + 0xf4, + 0x8c, + 0x81, + 0x41, + 0xb8, + 0x20, + 0x5c, + 0x3e, + 0x02, + 0x5e, + 0x5a, + 0x61, + 0xbb, + 0x2f, + 0x64, + 0xc5, + 0x4e, + 0x53, + 0xe4, + 0xca, + 0xe4, + 0xd9, + 0x75, + 0xaf, + 0x15, + 0x4d, + 0xff, + 0x01, + 0xec, + 0x13, + 0x4a, + 0x70, + 0x00, + 0x04, + 0xf9, + 0xfa, + 0x00, + 0x00, + 0x99, + 0x57, + 0xc4, + 0x96, + 0x00, + 0x02, + 0xf7, + 0x02, + 0x80, + 0x20, + 0xdf, + 0x01, + 0x8d, + 0x02, + 0x00, + 0x00, + 0x4c, + 0x41, + 0xe6, + 0xa1, + 0x9b, + 0xe3, + 0x51, + 0x40, + 0x03, + 0x00, + 0x00, + 0x00, + 0x00, + 0x01, + 0x59, + 0x5a + }; + + protected static byte[] OriginalIndexedBytes => Encoding.ASCII.GetBytes(OriginalIndexed); + + protected static string OriginalIndexed { get; } = + Original + + Original + + Original + + Original + + Original + + Original + + Original + + Original + + Original; } diff --git a/tests/SharpCompress.Test/Zip/Zip64Tests.cs b/tests/SharpCompress.Test/Zip/Zip64Tests.cs index c1f4453f..d19913e1 100644 --- a/tests/SharpCompress.Test/Zip/Zip64Tests.cs +++ b/tests/SharpCompress.Test/Zip/Zip64Tests.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; using System.Linq; using SharpCompress.Archives; @@ -10,224 +10,218 @@ using SharpCompress.Writers; using SharpCompress.Writers.Zip; using Xunit; -namespace SharpCompress.Test.Zip +namespace SharpCompress.Test.Zip; + +public class Zip64Tests : WriterTests { - public class Zip64Tests : WriterTests + public Zip64Tests() : base(ArchiveType.Zip) { } + + // 4GiB + 1 + private const long FOUR_GB_LIMIT = ((long)uint.MaxValue) + 1; + + [Trait("format", "zip64")] + public void Zip64_Single_Large_File() { - public Zip64Tests() : base(ArchiveType.Zip) { } + // One single file, requires zip64 + RunSingleTest(1, FOUR_GB_LIMIT, set_zip64: true, forward_only: false); + } - // 4GiB + 1 - private const long FOUR_GB_LIMIT = ((long)uint.MaxValue) + 1; + [Trait("format", "zip64")] + public void Zip64_Two_Large_Files() + { + // One single file, requires zip64 + RunSingleTest(2, FOUR_GB_LIMIT, set_zip64: true, forward_only: false); + } - [Trait("format", "zip64")] - public void Zip64_Single_Large_File() + [Trait("format", "zip64")] + public void Zip64_Two_Small_files() + { + // Multiple files, does not require zip64 + RunSingleTest(2, FOUR_GB_LIMIT / 2, set_zip64: false, forward_only: false); + } + + [Trait("format", "zip64")] + public void Zip64_Two_Small_files_stream() + { + // Multiple files, does not require zip64, and works with streams + RunSingleTest(2, FOUR_GB_LIMIT / 2, set_zip64: false, forward_only: true); + } + + [Trait("format", "zip64")] + public void Zip64_Two_Small_Files_Zip64() + { + // Multiple files, use zip64 even though it is not required + RunSingleTest(2, FOUR_GB_LIMIT / 2, set_zip64: true, forward_only: false); + } + + [Trait("format", "zip64")] + public void Zip64_Single_Large_File_Fail() + { + try { - // One single file, requires zip64 - RunSingleTest(1, FOUR_GB_LIMIT, set_zip64: true, forward_only: false); + // One single file, should fail + RunSingleTest(1, FOUR_GB_LIMIT, set_zip64: false, forward_only: false); + throw new InvalidOperationException("Test did not fail?"); + } + catch (NotSupportedException) { } + } + + [Trait("zip64", "true")] + public void Zip64_Single_Large_File_Zip64_Streaming_Fail() + { + try + { + // One single file, should fail (fast) with zip64 + RunSingleTest(1, FOUR_GB_LIMIT, set_zip64: true, forward_only: true); + throw new InvalidOperationException("Test did not fail?"); + } + catch (NotSupportedException) { } + } + + [Trait("zip64", "true")] + public void Zip64_Single_Large_File_Streaming_Fail() + { + try + { + // One single file, should fail once the write discovers the problem + RunSingleTest(1, FOUR_GB_LIMIT, set_zip64: false, forward_only: true); + throw new InvalidOperationException("Test did not fail?"); + } + catch (NotSupportedException) { } + } + + public void RunSingleTest( + long files, + long filesize, + bool set_zip64, + bool forward_only, + long write_chunk_size = 1024 * 1024, + string filename = "zip64-test.zip" + ) + { + filename = Path.Combine(SCRATCH2_FILES_PATH, filename); + + if (File.Exists(filename)) + { + File.Delete(filename); } - [Trait("format", "zip64")] - public void Zip64_Two_Large_Files() + if (!File.Exists(filename)) { - // One single file, requires zip64 - RunSingleTest(2, FOUR_GB_LIMIT, set_zip64: true, forward_only: false); + CreateZipArchive( + filename, + files, + filesize, + write_chunk_size, + set_zip64, + forward_only + ); } - [Trait("format", "zip64")] - public void Zip64_Two_Small_files() + var resForward = ReadForwardOnly(filename); + if (resForward.Item1 != files) { - // Multiple files, does not require zip64 - RunSingleTest(2, FOUR_GB_LIMIT / 2, set_zip64: false, forward_only: false); + throw new InvalidOperationException( + $"Incorrect number of items reported: {resForward.Item1}, should have been {files}" + ); } - [Trait("format", "zip64")] - public void Zip64_Two_Small_files_stream() + if (resForward.Item2 != files * filesize) { - // Multiple files, does not require zip64, and works with streams - RunSingleTest(2, FOUR_GB_LIMIT / 2, set_zip64: false, forward_only: true); + throw new InvalidOperationException( + $"Incorrect combined size reported: {resForward.Item2}, should have been {files * filesize}" + ); } - [Trait("format", "zip64")] - public void Zip64_Two_Small_Files_Zip64() + var resArchive = ReadArchive(filename); + if (resArchive.Item1 != files) { - // Multiple files, use zip64 even though it is not required - RunSingleTest(2, FOUR_GB_LIMIT / 2, set_zip64: true, forward_only: false); + throw new InvalidOperationException( + $"Incorrect number of items reported: {resArchive.Item1}, should have been {files}" + ); } - [Trait("format", "zip64")] - public void Zip64_Single_Large_File_Fail() + if (resArchive.Item2 != files * filesize) { - try - { - // One single file, should fail - RunSingleTest(1, FOUR_GB_LIMIT, set_zip64: false, forward_only: false); - throw new InvalidOperationException("Test did not fail?"); - } - catch (NotSupportedException) { } + throw new InvalidOperationException( + $"Incorrect number of items reported: {resArchive.Item2}, should have been {files * filesize}" + ); } + } - [Trait("zip64", "true")] - public void Zip64_Single_Large_File_Zip64_Streaming_Fail() + public void CreateZipArchive( + string filename, + long files, + long filesize, + long chunksize, + bool set_zip64, + bool forward_only + ) + { + var data = new byte[chunksize]; + + // Use deflate for speed + var opts = new ZipWriterOptions(CompressionType.Deflate) { UseZip64 = set_zip64 }; + + // Use no compression to ensure we hit the limits (actually inflates a bit, but seems better than using method==Store) + var eo = new ZipWriterEntryOptions() { - try - { - // One single file, should fail (fast) with zip64 - RunSingleTest(1, FOUR_GB_LIMIT, set_zip64: true, forward_only: true); - throw new InvalidOperationException("Test did not fail?"); - } - catch (NotSupportedException) { } - } + DeflateCompressionLevel = Compressors.Deflate.CompressionLevel.None + }; - [Trait("zip64", "true")] - public void Zip64_Single_Large_File_Streaming_Fail() + using var zip = File.OpenWrite(filename); + using var st = forward_only ? (Stream)new ForwardOnlyStream(zip) : zip; + using var zipWriter = (ZipWriter)WriterFactory.Open(st, ArchiveType.Zip, opts); + for (var i = 0; i < files; i++) { - try + using var str = zipWriter.WriteToStream(i.ToString(), eo); + var left = filesize; + while (left > 0) { - // One single file, should fail once the write discovers the problem - RunSingleTest(1, FOUR_GB_LIMIT, set_zip64: false, forward_only: true); - throw new InvalidOperationException("Test did not fail?"); - } - catch (NotSupportedException) { } - } - - public void RunSingleTest( - long files, - long filesize, - bool set_zip64, - bool forward_only, - long write_chunk_size = 1024 * 1024, - string filename = "zip64-test.zip" - ) - { - filename = Path.Combine(SCRATCH2_FILES_PATH, filename); - - if (File.Exists(filename)) - { - File.Delete(filename); - } - - if (!File.Exists(filename)) - { - CreateZipArchive( - filename, - files, - filesize, - write_chunk_size, - set_zip64, - forward_only - ); - } - - var resForward = ReadForwardOnly(filename); - if (resForward.Item1 != files) - { - throw new InvalidOperationException( - $"Incorrect number of items reported: {resForward.Item1}, should have been {files}" - ); - } - - if (resForward.Item2 != files * filesize) - { - throw new InvalidOperationException( - $"Incorrect combined size reported: {resForward.Item2}, should have been {files * filesize}" - ); - } - - var resArchive = ReadArchive(filename); - if (resArchive.Item1 != files) - { - throw new InvalidOperationException( - $"Incorrect number of items reported: {resArchive.Item1}, should have been {files}" - ); - } - - if (resArchive.Item2 != files * filesize) - { - throw new InvalidOperationException( - $"Incorrect number of items reported: {resArchive.Item2}, should have been {files * filesize}" - ); - } - } - - public void CreateZipArchive( - string filename, - long files, - long filesize, - long chunksize, - bool set_zip64, - bool forward_only - ) - { - var data = new byte[chunksize]; - - // Use deflate for speed - var opts = new ZipWriterOptions(CompressionType.Deflate) { UseZip64 = set_zip64 }; - - // Use no compression to ensure we hit the limits (actually inflates a bit, but seems better than using method==Store) - var eo = new ZipWriterEntryOptions() - { - DeflateCompressionLevel = Compressors.Deflate.CompressionLevel.None - }; - - using (var zip = File.OpenWrite(filename)) - using (var st = forward_only ? (Stream)new ForwardOnlyStream(zip) : zip) - using (var zipWriter = (ZipWriter)WriterFactory.Open(st, ArchiveType.Zip, opts)) - { - for (var i = 0; i < files; i++) - { - using (var str = zipWriter.WriteToStream(i.ToString(), eo)) - { - var left = filesize; - while (left > 0) - { - var b = (int)Math.Min(left, data.Length); - str.Write(data, 0, b); - left -= b; - } - } - } - } - } - - public Tuple ReadForwardOnly(string filename) - { - long count = 0; - long size = 0; - Common.Zip.ZipEntry? prev = null; - using (var fs = File.OpenRead(filename)) - using (var rd = ZipReader.Open(fs, new ReaderOptions() { LookForHeader = false })) - { - while (rd.MoveToNextEntry()) - { - using (rd.OpenEntryStream()) { } - - count++; - if (prev != null) - { - size += prev.Size; - } - - prev = rd.Entry; - } - } - - if (prev != null) - { - size += prev.Size; - } - - return new Tuple(count, size); - } - - public Tuple ReadArchive(string filename) - { - using (var archive = ArchiveFactory.Open(filename)) - { - return new Tuple( - archive.Entries.Count(), - archive.Entries.Select(x => x.Size).Sum() - ); + var b = (int)Math.Min(left, data.Length); + str.Write(data, 0, b); + left -= b; } } } + + public Tuple ReadForwardOnly(string filename) + { + long count = 0; + long size = 0; + Common.Zip.ZipEntry? prev = null; + using (var fs = File.OpenRead(filename)) + using (var rd = ZipReader.Open(fs, new ReaderOptions() { LookForHeader = false })) + { + while (rd.MoveToNextEntry()) + { + using (rd.OpenEntryStream()) + { } + + count++; + if (prev != null) + { + size += prev.Size; + } + + prev = rd.Entry; + } + } + + if (prev != null) + { + size += prev.Size; + } + + return new Tuple(count, size); + } + + public Tuple ReadArchive(string filename) + { + using var archive = ArchiveFactory.Open(filename); + return new Tuple( + archive.Entries.Count(), + archive.Entries.Select(x => x.Size).Sum() + ); + } } diff --git a/tests/SharpCompress.Test/Zip/ZipArchiveTests.cs b/tests/SharpCompress.Test/Zip/ZipArchiveTests.cs index c1375801..738223a7 100644 --- a/tests/SharpCompress.Test/Zip/ZipArchiveTests.cs +++ b/tests/SharpCompress.Test/Zip/ZipArchiveTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; using System.Linq; using System.Text; diff --git a/tests/SharpCompress.Test/Zip/ZipReaderTests.cs b/tests/SharpCompress.Test/Zip/ZipReaderTests.cs index 446c0e82..dab65cc0 100644 --- a/tests/SharpCompress.Test/Zip/ZipReaderTests.cs +++ b/tests/SharpCompress.Test/Zip/ZipReaderTests.cs @@ -8,263 +8,223 @@ using SharpCompress.Test.Mocks; using SharpCompress.Writers; using Xunit; -namespace SharpCompress.Test.Zip +namespace SharpCompress.Test.Zip; + +public class ZipReaderTests : ReaderTests { - public class ZipReaderTests : ReaderTests + public ZipReaderTests() { - public ZipReaderTests() - { - UseExtensionInsteadOfNameToVerify = true; - } + UseExtensionInsteadOfNameToVerify = true; + } - [Fact] - public void Issue_269_Double_Skip() + [Fact] + public void Issue_269_Double_Skip() + { + var path = Path.Combine(TEST_ARCHIVES_PATH, "PrePostHeaders.zip"); + using Stream stream = new ForwardOnlyStream(File.OpenRead(path)); + using var reader = ReaderFactory.Open(stream); + var count = 0; + while (reader.MoveToNextEntry()) { - var path = Path.Combine(TEST_ARCHIVES_PATH, "PrePostHeaders.zip"); - using (Stream stream = new ForwardOnlyStream(File.OpenRead(path))) - using (IReader reader = ReaderFactory.Open(stream)) + count++; + if (!reader.Entry.IsDirectory) { - int count = 0; - while (reader.MoveToNextEntry()) + if (count % 2 != 0) { - count++; - if (!reader.Entry.IsDirectory) - { - if (count % 2 != 0) - { - reader.WriteEntryTo(Stream.Null); - } - } + reader.WriteEntryTo(Stream.Null); } } } + } - [Fact] - public void Zip_Zip64_Streamed_Read() + [Fact] + public void Zip_Zip64_Streamed_Read() + { + Read("Zip.zip64.zip", CompressionType.Deflate); + } + + [Fact] + public void Zip_ZipX_Streamed_Read() + { + Read("Zip.zipx", CompressionType.LZMA); + } + + [Fact] + public void Zip_BZip2_Streamed_Read() + { + Read("Zip.bzip2.dd.zip", CompressionType.BZip2); + } + + [Fact] + public void Zip_BZip2_Read() + { + Read("Zip.bzip2.zip", CompressionType.BZip2); + } + + [Fact] + public void Zip_Deflate_Streamed2_Read() + { + Read("Zip.deflate.dd-.zip", CompressionType.Deflate); + } + + [Fact] + public void Zip_Deflate_Streamed_Read() + { + Read("Zip.deflate.dd.zip", CompressionType.Deflate); + } + + [Fact] + public void Zip_Deflate_Streamed_Skip() + { + using Stream stream = new ForwardOnlyStream( + File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.dd.zip")) + ); + using var reader = ReaderFactory.Open(stream); + var x = 0; + while (reader.MoveToNextEntry()) { - Read("Zip.zip64.zip", CompressionType.Deflate); + if (!reader.Entry.IsDirectory) + { + x++; + if (x % 2 == 0) + { + reader.WriteEntryToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } + ); + } + } } + } - [Fact] - public void Zip_ZipX_Streamed_Read() - { - Read("Zip.zipx", CompressionType.LZMA); - } + [Fact] + public void Zip_Deflate_Read() + { + Read("Zip.deflate.zip", CompressionType.Deflate); + } - [Fact] - public void Zip_BZip2_Streamed_Read() - { - Read("Zip.bzip2.dd.zip", CompressionType.BZip2); - } + [Fact] + public void Zip_Deflate64_Read() + { + Read("Zip.deflate64.zip", CompressionType.Deflate64); + } - [Fact] - public void Zip_BZip2_Read() - { - Read("Zip.bzip2.zip", CompressionType.BZip2); - } + [Fact] + public void Zip_LZMA_Streamed_Read() + { + Read("Zip.lzma.dd.zip", CompressionType.LZMA); + } - [Fact] - public void Zip_Deflate_Streamed2_Read() - { - Read("Zip.deflate.dd-.zip", CompressionType.Deflate); - } + [Fact] + public void Zip_LZMA_Read() + { + Read("Zip.lzma.zip", CompressionType.LZMA); + } - [Fact] - public void Zip_Deflate_Streamed_Read() - { - Read("Zip.deflate.dd.zip", CompressionType.Deflate); - } + [Fact] + public void Zip_PPMd_Streamed_Read() + { + Read("Zip.ppmd.dd.zip", CompressionType.PPMd); + } - [Fact] - public void Zip_Deflate_Streamed_Skip() - { - using ( - Stream stream = new ForwardOnlyStream( - File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.dd.zip")) - ) + [Fact] + public void Zip_PPMd_Read() + { + Read("Zip.ppmd.zip", CompressionType.PPMd); + } + + [Fact] + public void Zip_None_Read() + { + Read("Zip.none.zip", CompressionType.None); + } + + [Fact] + public void Zip_Deflate_NoEmptyDirs_Read() + { + Read("Zip.deflate.noEmptyDirs.zip", CompressionType.Deflate); + } + + [Fact] + public void Zip_BZip2_PkwareEncryption_Read() + { + using ( + Stream stream = File.OpenRead( + Path.Combine(TEST_ARCHIVES_PATH, "Zip.bzip2.pkware.zip") ) - using (IReader reader = ReaderFactory.Open(stream)) + ) + using (var reader = ZipReader.Open(stream, new ReaderOptions() { Password = "test" })) + { + while (reader.MoveToNextEntry()) { - int x = 0; - while (reader.MoveToNextEntry()) + if (!reader.Entry.IsDirectory) { - if (!reader.Entry.IsDirectory) - { - x++; - if (x % 2 == 0) - { - reader.WriteEntryToDirectory( - SCRATCH_FILES_PATH, - new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } - ); - } - } + Assert.Equal(CompressionType.BZip2, reader.Entry.CompressionType); + reader.WriteEntryToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } + ); } } } + VerifyFiles(); + } - [Fact] - public void Zip_Deflate_Read() + [Fact] + public void Zip_Reader_Disposal_Test() + { + using var stream = new TestStream( + File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.dd.zip")) + ); + using (var reader = ReaderFactory.Open(stream)) { - Read("Zip.deflate.zip", CompressionType.Deflate); + while (reader.MoveToNextEntry()) + { + if (!reader.Entry.IsDirectory) + { + reader.WriteEntryToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } + ); + } + } } + Assert.True(stream.IsDisposed); + } - [Fact] - public void Zip_Deflate64_Read() + [Fact] + public void Zip_Reader_Disposal_Test2() + { + using var stream = new TestStream( + File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.dd.zip")) + ); + var reader = ReaderFactory.Open(stream); + while (reader.MoveToNextEntry()) { - Read("Zip.deflate64.zip", CompressionType.Deflate64); + if (!reader.Entry.IsDirectory) + { + reader.WriteEntryToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } + ); + } } + Assert.False(stream.IsDisposed); + } - [Fact] - public void Zip_LZMA_Streamed_Read() - { - Read("Zip.lzma.dd.zip", CompressionType.LZMA); - } - - [Fact] - public void Zip_LZMA_Read() - { - Read("Zip.lzma.zip", CompressionType.LZMA); - } - - [Fact] - public void Zip_PPMd_Streamed_Read() - { - Read("Zip.ppmd.dd.zip", CompressionType.PPMd); - } - - [Fact] - public void Zip_PPMd_Read() - { - Read("Zip.ppmd.zip", CompressionType.PPMd); - } - - [Fact] - public void Zip_None_Read() - { - Read("Zip.none.zip", CompressionType.None); - } - - [Fact] - public void Zip_Deflate_NoEmptyDirs_Read() - { - Read("Zip.deflate.noEmptyDirs.zip", CompressionType.Deflate); - } - - [Fact] - public void Zip_BZip2_PkwareEncryption_Read() + [Fact] + public void Zip_LZMA_WinzipAES_Read() + { + Assert.Throws(() => { using ( Stream stream = File.OpenRead( - Path.Combine(TEST_ARCHIVES_PATH, "Zip.bzip2.pkware.zip") + Path.Combine(TEST_ARCHIVES_PATH, "Zip.lzma.WinzipAES.zip") ) ) - using (var reader = ZipReader.Open(stream, new ReaderOptions() { Password = "test" })) - { - while (reader.MoveToNextEntry()) - { - if (!reader.Entry.IsDirectory) - { - Assert.Equal(CompressionType.BZip2, reader.Entry.CompressionType); - reader.WriteEntryToDirectory( - SCRATCH_FILES_PATH, - new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } - ); - } - } - } - VerifyFiles(); - } - - [Fact] - public void Zip_Reader_Disposal_Test() - { using ( - TestStream stream = new TestStream( - File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.dd.zip")) - ) + var reader = ZipReader.Open(stream, new ReaderOptions() { Password = "test" }) ) - { - using (var reader = ReaderFactory.Open(stream)) - { - while (reader.MoveToNextEntry()) - { - if (!reader.Entry.IsDirectory) - { - reader.WriteEntryToDirectory( - SCRATCH_FILES_PATH, - new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } - ); - } - } - } - Assert.True(stream.IsDisposed); - } - } - - [Fact] - public void Zip_Reader_Disposal_Test2() - { - using ( - TestStream stream = new TestStream( - File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.dd.zip")) - ) - ) - { - var reader = ReaderFactory.Open(stream); - while (reader.MoveToNextEntry()) - { - if (!reader.Entry.IsDirectory) - { - reader.WriteEntryToDirectory( - SCRATCH_FILES_PATH, - new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } - ); - } - } - Assert.False(stream.IsDisposed); - } - } - - [Fact] - public void Zip_LZMA_WinzipAES_Read() - { - Assert.Throws(() => - { - using ( - Stream stream = File.OpenRead( - Path.Combine(TEST_ARCHIVES_PATH, "Zip.lzma.WinzipAES.zip") - ) - ) - using ( - var reader = ZipReader.Open(stream, new ReaderOptions() { Password = "test" }) - ) - { - while (reader.MoveToNextEntry()) - { - if (!reader.Entry.IsDirectory) - { - Assert.Equal(CompressionType.Unknown, reader.Entry.CompressionType); - reader.WriteEntryToDirectory( - SCRATCH_FILES_PATH, - new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } - ); - } - } - } - VerifyFiles(); - }); - } - - [Fact] - public void Zip_Deflate_WinzipAES_Read() - { - using ( - Stream stream = File.OpenRead( - Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.WinzipAES.zip") - ) - ) - using (var reader = ZipReader.Open(stream, new ReaderOptions() { Password = "test" })) { while (reader.MoveToNextEntry()) { @@ -279,187 +239,193 @@ namespace SharpCompress.Test.Zip } } VerifyFiles(); - } + }); + } - [Fact] - public void Zip_Deflate_ZipCrypto_Read() - { - int count = 0; - using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "zipcrypto.zip"))) - using (var reader = ZipReader.Open(stream, new ReaderOptions() { Password = "test" })) - { - while (reader.MoveToNextEntry()) - { - if (!reader.Entry.IsDirectory) - { - Assert.Equal(CompressionType.None, reader.Entry.CompressionType); - reader.WriteEntryToDirectory( - SCRATCH_FILES_PATH, - new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } - ); - count++; - } - } - } - Assert.Equal(8, count); - } - - [Fact] - public void TestSharpCompressWithEmptyStream() - { - var expected = new Tuple[] - { - new Tuple("foo.txt", Array.Empty()), - new Tuple("foo2.txt", new byte[10]) - }; - - using (var memory = new MemoryStream()) - { - Stream stream = new TestStream(memory, read: true, write: true, seek: false); - - using ( - IWriter zipWriter = WriterFactory.Open( - stream, - ArchiveType.Zip, - CompressionType.Deflate - ) - ) - { - zipWriter.Write(expected[0].Item1, new MemoryStream(expected[0].Item2)); - zipWriter.Write(expected[1].Item1, new MemoryStream(expected[1].Item2)); - } - - stream = new MemoryStream(memory.ToArray()); - File.WriteAllBytes(Path.Combine(SCRATCH_FILES_PATH, "foo.zip"), memory.ToArray()); - - using (IReader zipReader = ZipReader.Open(NonDisposingStream.Create(stream, true))) - { - var i = 0; - while (zipReader.MoveToNextEntry()) - { - using (EntryStream entry = zipReader.OpenEntryStream()) - { - MemoryStream tempStream = new MemoryStream(); - const int bufSize = 0x1000; - byte[] buf = new byte[bufSize]; - int bytesRead = 0; - while ((bytesRead = entry.Read(buf, 0, bufSize)) > 0) - { - tempStream.Write(buf, 0, bytesRead); - } - - Assert.Equal(expected[i].Item1, zipReader.Entry.Key); - Assert.Equal(expected[i].Item2, tempStream.ToArray()); - } - i++; - } - } - } - } - - [Fact] - public void Zip_None_Issue86_Streamed_Read() - { - var keys = new string[] - { - "Empty1", - "Empty2", - "Dir1/", - "Dir2/", - "Fake1", - "Fake2", - "Internal.zip" - }; - - using ( - Stream stream = File.OpenRead( - Path.Combine(TEST_ARCHIVES_PATH, "Zip.none.issue86.zip") - ) + [Fact] + public void Zip_Deflate_WinzipAES_Read() + { + using ( + Stream stream = File.OpenRead( + Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.WinzipAES.zip") ) - using (var reader = ZipReader.Open(stream)) - { - foreach (var key in keys) - { - reader.MoveToNextEntry(); - - Assert.Equal(reader.Entry.Key, key); - - if (!reader.Entry.IsDirectory) - { - Assert.Equal(CompressionType.None, reader.Entry.CompressionType); - } - } - - Assert.False(reader.MoveToNextEntry()); - } - } - - [Fact] - public void Zip_ReaderMoveToNextEntry() + ) + using (var reader = ZipReader.Open(stream, new ReaderOptions() { Password = "test" })) { - var keys = new string[] { "version", "sizehint", "data/0/metadata", "data/0/records" }; - - using (var fileStream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "test_477.zip"))) - using (var reader = ZipReader.Open(fileStream)) + while (reader.MoveToNextEntry()) { - foreach (var key in keys) + if (!reader.Entry.IsDirectory) { - reader.MoveToNextEntry(); - - Assert.Equal(reader.Entry.Key, key); + Assert.Equal(CompressionType.Unknown, reader.Entry.CompressionType); + reader.WriteEntryToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } + ); } } } + VerifyFiles(); + } - [Fact] - public void Issue_685() + [Fact] + public void Zip_Deflate_ZipCrypto_Read() + { + var count = 0; + using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "zipcrypto.zip"))) + using (var reader = ZipReader.Open(stream, new ReaderOptions() { Password = "test" })) { - var count = 0; - using ( - var fileStream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Issue_685.zip")) - ) - using (var reader = ZipReader.Open(fileStream)) + while (reader.MoveToNextEntry()) { - while (reader.MoveToNextEntry()) + if (!reader.Entry.IsDirectory) { + Assert.Equal(CompressionType.None, reader.Entry.CompressionType); + reader.WriteEntryToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } + ); count++; - reader.OpenEntryStream().Dispose(); // Uncomment for workaround - } - Assert.Equal(4, count); - } - } - - [Fact] - public void Zip_Uncompressed_Skip_All() - { - var zipPath = Path.Combine(TEST_ARCHIVES_PATH, "Zip.uncompressed.zip"); - using (var stream = File.Open(zipPath, FileMode.Open, FileAccess.Read)) - { - using (var reader = ReaderFactory.Open(stream)) - { - while (reader.MoveToNextEntry()) { } } } } + Assert.Equal(8, count); + } - [Fact] - public void Zip_Uncompressed_64bit() + [Fact] + public void TestSharpCompressWithEmptyStream() + { + var expected = new Tuple[] { - var zipPath = Path.Combine(TEST_ARCHIVES_PATH, "64bitstream.zip.7z"); - using (var stream = File.Open(zipPath, FileMode.Open, FileAccess.Read)) + new Tuple("foo.txt", Array.Empty()), + new Tuple("foo2.txt", new byte[10]) + }; + + using var memory = new MemoryStream(); + Stream stream = new TestStream(memory, read: true, write: true, seek: false); + + using ( + var zipWriter = WriterFactory.Open( + stream, + ArchiveType.Zip, + CompressionType.Deflate + ) + ) + { + zipWriter.Write(expected[0].Item1, new MemoryStream(expected[0].Item2)); + zipWriter.Write(expected[1].Item1, new MemoryStream(expected[1].Item2)); + } + + stream = new MemoryStream(memory.ToArray()); + File.WriteAllBytes(Path.Combine(SCRATCH_FILES_PATH, "foo.zip"), memory.ToArray()); + + using IReader zipReader = ZipReader.Open(NonDisposingStream.Create(stream, true)); + var i = 0; + while (zipReader.MoveToNextEntry()) + { + using (var entry = zipReader.OpenEntryStream()) { - var archive = Archives.ArchiveFactory.Open(stream); - var reader = archive.ExtractAllEntries(); - reader.MoveToNextEntry(); - var zipReader = ZipReader.Open(reader.OpenEntryStream()); - var x = 0; - while (zipReader.MoveToNextEntry()) + var tempStream = new MemoryStream(); + const int bufSize = 0x1000; + var buf = new byte[bufSize]; + var bytesRead = 0; + while ((bytesRead = entry.Read(buf, 0, bufSize)) > 0) { - x++; + tempStream.Write(buf, 0, bytesRead); } - Assert.Equal(4, x); + Assert.Equal(expected[i].Item1, zipReader.Entry.Key); + Assert.Equal(expected[i].Item2, tempStream.ToArray()); } + i++; } } + + [Fact] + public void Zip_None_Issue86_Streamed_Read() + { + var keys = new string[] + { + "Empty1", + "Empty2", + "Dir1/", + "Dir2/", + "Fake1", + "Fake2", + "Internal.zip" + }; + + using Stream stream = File.OpenRead( + Path.Combine(TEST_ARCHIVES_PATH, "Zip.none.issue86.zip") + ); + using var reader = ZipReader.Open(stream); + foreach (var key in keys) + { + reader.MoveToNextEntry(); + + Assert.Equal(reader.Entry.Key, key); + + if (!reader.Entry.IsDirectory) + { + Assert.Equal(CompressionType.None, reader.Entry.CompressionType); + } + } + + Assert.False(reader.MoveToNextEntry()); + } + + [Fact] + public void Zip_ReaderMoveToNextEntry() + { + var keys = new string[] { "version", "sizehint", "data/0/metadata", "data/0/records" }; + + using var fileStream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "test_477.zip")); + using var reader = ZipReader.Open(fileStream); + foreach (var key in keys) + { + reader.MoveToNextEntry(); + + Assert.Equal(reader.Entry.Key, key); + } + } + + [Fact] + public void Issue_685() + { + var count = 0; + using var fileStream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Issue_685.zip")); + using var reader = ZipReader.Open(fileStream); + while (reader.MoveToNextEntry()) + { + count++; + reader.OpenEntryStream().Dispose(); // Uncomment for workaround + } + Assert.Equal(4, count); + } + + [Fact] + public void Zip_Uncompressed_Skip_All() + { + var zipPath = Path.Combine(TEST_ARCHIVES_PATH, "Zip.uncompressed.zip"); + using var stream = File.Open(zipPath, FileMode.Open, FileAccess.Read); + using var reader = ReaderFactory.Open(stream); + while (reader.MoveToNextEntry()) + { } + } + + [Fact] + public void Zip_Uncompressed_64bit() + { + var zipPath = Path.Combine(TEST_ARCHIVES_PATH, "64bitstream.zip.7z"); + using var stream = File.Open(zipPath, FileMode.Open, FileAccess.Read); + var archive = Archives.ArchiveFactory.Open(stream); + var reader = archive.ExtractAllEntries(); + reader.MoveToNextEntry(); + var zipReader = ZipReader.Open(reader.OpenEntryStream()); + var x = 0; + while (zipReader.MoveToNextEntry()) + { + x++; + } + + Assert.Equal(4, x); + } } diff --git a/tests/SharpCompress.Test/Zip/ZipWriterTests.cs b/tests/SharpCompress.Test/Zip/ZipWriterTests.cs index 28e90f51..c073a8a2 100644 --- a/tests/SharpCompress.Test/Zip/ZipWriterTests.cs +++ b/tests/SharpCompress.Test/Zip/ZipWriterTests.cs @@ -3,78 +3,77 @@ using System.Text; using SharpCompress.Common; using Xunit; -namespace SharpCompress.Test.Zip +namespace SharpCompress.Test.Zip; + +public class ZipWriterTests : WriterTests { - public class ZipWriterTests : WriterTests + public ZipWriterTests() : base(ArchiveType.Zip) { } + + [Fact] + public void Zip_Deflate_Write() { - public ZipWriterTests() : base(ArchiveType.Zip) { } + Write( + CompressionType.Deflate, + "Zip.deflate.noEmptyDirs.zip", + "Zip.deflate.noEmptyDirs.zip", + Encoding.UTF8 + ); + } - [Fact] - public void Zip_Deflate_Write() - { - Write( - CompressionType.Deflate, - "Zip.deflate.noEmptyDirs.zip", - "Zip.deflate.noEmptyDirs.zip", - Encoding.UTF8 - ); - } + [Fact] + public void Zip_BZip2_Write() + { + Write( + CompressionType.BZip2, + "Zip.bzip2.noEmptyDirs.zip", + "Zip.bzip2.noEmptyDirs.zip", + Encoding.UTF8 + ); + } - [Fact] - public void Zip_BZip2_Write() - { - Write( - CompressionType.BZip2, - "Zip.bzip2.noEmptyDirs.zip", - "Zip.bzip2.noEmptyDirs.zip", - Encoding.UTF8 - ); - } + [Fact] + public void Zip_None_Write() + { + Write( + CompressionType.None, + "Zip.none.noEmptyDirs.zip", + "Zip.none.noEmptyDirs.zip", + Encoding.UTF8 + ); + } - [Fact] - public void Zip_None_Write() - { - Write( - CompressionType.None, - "Zip.none.noEmptyDirs.zip", - "Zip.none.noEmptyDirs.zip", - Encoding.UTF8 - ); - } + [Fact] + public void Zip_LZMA_Write() + { + Write( + CompressionType.LZMA, + "Zip.lzma.noEmptyDirs.zip", + "Zip.lzma.noEmptyDirs.zip", + Encoding.UTF8 + ); + } - [Fact] - public void Zip_LZMA_Write() - { - Write( - CompressionType.LZMA, - "Zip.lzma.noEmptyDirs.zip", - "Zip.lzma.noEmptyDirs.zip", - Encoding.UTF8 - ); - } + [Fact] + public void Zip_PPMd_Write() + { + Write( + CompressionType.PPMd, + "Zip.ppmd.noEmptyDirs.zip", + "Zip.ppmd.noEmptyDirs.zip", + Encoding.UTF8 + ); + } - [Fact] - public void Zip_PPMd_Write() - { - Write( - CompressionType.PPMd, - "Zip.ppmd.noEmptyDirs.zip", - "Zip.ppmd.noEmptyDirs.zip", - Encoding.UTF8 - ); - } - - [Fact] - public void Zip_Rar_Write() - { - Assert.Throws( - () => - Write( - CompressionType.Rar, - "Zip.ppmd.noEmptyDirs.zip", - "Zip.ppmd.noEmptyDirs.zip" - ) - ); - } + [Fact] + public void Zip_Rar_Write() + { + Assert.Throws( + () => + Write( + CompressionType.Rar, + "Zip.ppmd.noEmptyDirs.zip", + "Zip.ppmd.noEmptyDirs.zip" + ) + ); } } From 7da10795a12f007ef847078af94b59a300f79c44 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Tue, 20 Dec 2022 15:14:22 +0000 Subject: [PATCH 6/7] csharpier --- .editorconfig | 2 +- src/SharpCompress/Algorithms/Adler32.cs | 10 +- src/SharpCompress/Archives/AbstractArchive.cs | 5 +- .../Archives/AbstractWritableArchive.cs | 4 +- src/SharpCompress/Archives/ArchiveFactory.cs | 2 +- .../Archives/GZip/GZipArchive.cs | 18 +- .../Archives/IMultiArchiveFactory.cs | 5 +- .../Archives/IWritableArchiveExtensions.cs | 4 +- src/SharpCompress/Archives/Rar/RarArchive.cs | 9 +- .../Archives/Rar/SeekableFilePart.cs | 3 +- .../Archives/Rar/StreamRarArchiveVolume.cs | 8 +- .../Archives/SevenZip/SevenZipArchive.cs | 7 +- src/SharpCompress/Archives/Tar/TarArchive.cs | 9 +- .../Archives/Tar/TarArchiveEntry.cs | 7 +- src/SharpCompress/Archives/Zip/ZipArchive.cs | 66 +- src/SharpCompress/Common/GZip/GZipFilePart.cs | 3 +- src/SharpCompress/Common/GZip/GZipVolume.cs | 3 +- .../Common/MultiVolumeExtractionException.cs | 4 +- .../Common/PasswordProtectedException.cs | 3 +- .../Common/Rar/Headers/ArchiveCryptHeader.cs | 5 +- .../Common/Rar/Headers/FileHeader.cs | 112 +- .../Common/Rar/Headers/FileNameDecoder.cs | 6 +- .../Common/Rar/Headers/RarHeaderFactory.cs | 83 +- src/SharpCompress/Common/Rar/RarVolume.cs | 58 +- .../Common/SevenZip/ArchiveReader.cs | 47 +- .../Common/SevenZip/SevenZipFilePart.cs | 10 +- .../Common/Tar/Headers/TarHeader.cs | 10 +- .../Common/Tar/TarHeaderFactory.cs | 20 +- .../Zip/Headers/DirectoryEntryHeader.cs | 4 +- .../Common/Zip/Headers/LocalEntryHeader.cs | 4 +- .../Headers/LocalEntryHeaderExtraFactory.cs | 15 +- .../Common/Zip/Headers/ZipFileEntry.cs | 8 +- .../Common/Zip/StreamingZipHeaderFactory.cs | 6 +- src/SharpCompress/Common/Zip/ZipFilePart.cs | 16 +- .../Common/Zip/ZipHeaderFactory.cs | 7 +- .../Compressors/ADC/ADCStream.cs | 7 +- .../Compressors/BZip2/BZip2Stream.cs | 6 +- .../Compressors/BZip2/CBZip2InputStream.cs | 13 +- .../Compressors/BZip2/CBZip2OutputStream.cs | 46 +- .../Compressors/Deflate/DeflateManager.cs | 41 +- .../Compressors/Deflate/InfTree.cs | 8 +- .../Compressors/Deflate/Inflate.cs | 21 +- src/SharpCompress/Compressors/Deflate/Tree.cs | 4 +- src/SharpCompress/Compressors/Deflate/Zlib.cs | 7 +- .../Compressors/Deflate64/DeflateInput.cs | 2 +- .../Compressors/Deflate64/InflaterManaged.cs | 3 +- .../Compressors/Filters/BranchExecFilter.cs | 12 +- .../Compressors/LZMA/DecoderStream.cs | 11 +- src/SharpCompress/Compressors/LZMA/ICoder.cs | 8 +- .../Compressors/LZMA/LZipStream.cs | 3 +- .../Compressors/LZMA/LzmaDecoder.cs | 22 +- .../Compressors/LZMA/LzmaEncoder.cs | 73 +- .../Compressors/LZMA/LzmaStream.cs | 4 +- .../LZMA/RangeCoder/RangeCoderBit.cs | 3 +- .../LZMA/RangeCoder/RangeCoderBitTree.cs | 4 +- .../Compressors/PPMd/H/ModelPPM.cs | 25 +- .../Compressors/PPMd/H/PPMContext.cs | 23 +- .../Compressors/PPMd/H/RarMemBlock.cs | 3 +- src/SharpCompress/Compressors/PPMd/H/State.cs | 18 +- .../Compressors/PPMd/H/SubAllocator.cs | 6 +- .../Compressors/PPMd/I1/Allocator.cs | 9 +- .../Compressors/PPMd/I1/Coder.cs | 6 +- .../Compressors/PPMd/I1/Model.cs | 19 +- .../Compressors/PPMd/I1/Pointer.cs | 16 +- .../Compressors/PPMd/I1/PpmContext.cs | 2 +- .../Compressors/Rar/UnpackV1/Unpack.cs | 24 +- .../Compressors/Rar/UnpackV1/Unpack15.cs | 40 +- .../Compressors/Rar/UnpackV1/Unpack20.cs | 7 +- .../Compressors/Rar/UnpackV1/Unpack50.cs | 12 +- .../Compressors/Rar/UnpackV1/UnpackUtility.cs | 13 +- .../Rar/UnpackV2017/Unpack.unpack15_cpp.cs | 14 +- .../Rar/UnpackV2017/Unpack.unpack20_cpp.cs | 2 +- .../Rar/UnpackV2017/Unpack.unpack50_cpp.cs | 111 +- .../Rar/UnpackV2017/Unpack.unpack_cpp.cs | 4 +- src/SharpCompress/Compressors/Rar/VM/RarVM.cs | 1214 ++++++++--------- .../Compressors/Xz/Filters/BlockFilter.cs | 4 +- src/SharpCompress/Compressors/Xz/XZStream.cs | 4 +- src/SharpCompress/Crypto/Crc32Stream.cs | 3 +- .../Crypto/DataLengthException.cs | 3 +- src/SharpCompress/Factories/GZipFactory.cs | 4 +- src/SharpCompress/IO/ListeningStream.cs | 10 +- src/SharpCompress/IO/ReadOnlySubStream.cs | 3 +- src/SharpCompress/IO/SourceStream.cs | 3 +- src/SharpCompress/Readers/AbstractReader.cs | 8 +- .../Readers/Rar/NonSeekableStreamFilePart.cs | 3 +- src/SharpCompress/Readers/Rar/RarReader.cs | 4 +- src/SharpCompress/Readers/ReaderFactory.cs | 5 +- src/SharpCompress/Readers/Zip/ZipReader.cs | 17 +- src/SharpCompress/Utility.cs | 3 +- src/SharpCompress/Writers/Tar/TarWriter.cs | 27 +- src/SharpCompress/Writers/WriterFactory.cs | 6 +- src/SharpCompress/Writers/Zip/ZipWriter.cs | 27 +- tests/SharpCompress.Test/ADCTest.cs | 34 +- tests/SharpCompress.Test/ArchiveTests.cs | 21 +- .../GZip/GZipArchiveTests.cs | 4 +- .../GZip/GZipReaderTests.cs | 4 +- tests/SharpCompress.Test/Mocks/TestStream.cs | 4 +- .../SharpCompress.Test/Rar/RarArchiveTests.cs | 16 +- .../Rar/RarHeaderFactoryTest.cs | 13 +- .../SharpCompress.Test/Rar/RarReaderTests.cs | 23 +- tests/SharpCompress.Test/ReaderTests.cs | 11 +- .../SevenZip/SevenZipArchiveTests.cs | 5 +- .../Streams/ZlibBaseStreamTests.cs | 14 +- .../SharpCompress.Test/Tar/TarWriterTests.cs | 7 +- tests/SharpCompress.Test/WriterTests.cs | 10 +- tests/SharpCompress.Test/Zip/Zip64Tests.cs | 12 +- .../SharpCompress.Test/Zip/ZipReaderTests.cs | 35 +- .../SharpCompress.Test/Zip/ZipWriterTests.cs | 7 +- 108 files changed, 1112 insertions(+), 1691 deletions(-) diff --git a/.editorconfig b/.editorconfig index be296daf..1903a97c 100644 --- a/.editorconfig +++ b/.editorconfig @@ -351,7 +351,7 @@ 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 = suggestion # namespace folder structure +dotnet_diagnostic.IDE0130.severity = error # 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 diff --git a/src/SharpCompress/Algorithms/Adler32.cs b/src/SharpCompress/Algorithms/Adler32.cs index e32893ac..1f094c13 100644 --- a/src/SharpCompress/Algorithms/Adler32.cs +++ b/src/SharpCompress/Algorithms/Adler32.cs @@ -236,17 +236,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() - ); + v_s1 = Sse2.Add(v_s1, Sse2.SumAbsoluteDifferences(bytes1, zero).AsUInt32()); Vector128 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() - ); + v_s1 = Sse2.Add(v_s1, Sse2.SumAbsoluteDifferences(bytes2, zero).AsUInt32()); Vector128 mad2 = Ssse3.MultiplyAddAdjacent(bytes2, tap2); v_s2 = Sse2.Add(v_s2, Sse2.MultiplyAddAdjacent(mad2, ones).AsUInt32()); diff --git a/src/SharpCompress/Archives/AbstractArchive.cs b/src/SharpCompress/Archives/AbstractArchive.cs index d747189e..630cf3c5 100644 --- a/src/SharpCompress/Archives/AbstractArchive.cs +++ b/src/SharpCompress/Archives/AbstractArchive.cs @@ -49,10 +49,7 @@ public abstract class AbstractArchive : IArchive, IArchiveExtra void IArchiveExtractionListener.FireEntryExtractionBegin(IArchiveEntry entry) { - EntryExtractionBegin?.Invoke( - this, - new ArchiveExtractionEventArgs(entry) - ); + EntryExtractionBegin?.Invoke(this, new ArchiveExtractionEventArgs(entry)); } void IArchiveExtractionListener.FireEntryExtractionEnd(IArchiveEntry entry) diff --git a/src/SharpCompress/Archives/AbstractWritableArchive.cs b/src/SharpCompress/Archives/AbstractWritableArchive.cs index 146c8338..f3f98be8 100644 --- a/src/SharpCompress/Archives/AbstractWritableArchive.cs +++ b/src/SharpCompress/Archives/AbstractWritableArchive.cs @@ -146,9 +146,7 @@ public abstract class AbstractWritableArchive public void SaveTo(Stream stream, WriterOptions options) { //reset streams of new entries - newEntries - .Cast() - .ForEach(x => x.Stream.Seek(0, SeekOrigin.Begin)); + newEntries.Cast().ForEach(x => x.Stream.Seek(0, SeekOrigin.Begin)); SaveTo(stream, options, OldEntries, newEntries); } diff --git a/src/SharpCompress/Archives/ArchiveFactory.cs b/src/SharpCompress/Archives/ArchiveFactory.cs index a246bad9..6b489fa1 100644 --- a/src/SharpCompress/Archives/ArchiveFactory.cs +++ b/src/SharpCompress/Archives/ArchiveFactory.cs @@ -27,7 +27,7 @@ public static class ArchiveFactory { var factory = Factory.Factories .OfType() -.FirstOrDefault(item => item.KnownArchiveType == type); + .FirstOrDefault(item => item.KnownArchiveType == type); if (factory != null) { diff --git a/src/SharpCompress/Archives/GZip/GZipArchive.cs b/src/SharpCompress/Archives/GZip/GZipArchive.cs index 4100f2f2..43a43c00 100644 --- a/src/SharpCompress/Archives/GZip/GZipArchive.cs +++ b/src/SharpCompress/Archives/GZip/GZipArchive.cs @@ -68,10 +68,7 @@ public class GZipArchive : AbstractWritableArchive ///
/// /// - public static GZipArchive Open( - IEnumerable streams, - ReaderOptions? readerOptions = null - ) + public static GZipArchive Open(IEnumerable streams, ReaderOptions? readerOptions = null) { streams.CheckNotNull(nameof(streams)); var strms = streams.ToArray(); @@ -176,14 +173,7 @@ public class GZipArchive : AbstractWritableArchive { throw new InvalidOperationException("Only one entry is allowed in a GZip Archive"); } - return new GZipWritableArchiveEntry( - this, - source, - filePath, - size, - modified, - closeStream - ); + return new GZipWritableArchiveEntry(this, source, filePath, size, modified, closeStream); } protected override void SaveTo( @@ -205,9 +195,7 @@ public class GZipArchive : AbstractWritableArchive } } - protected override IEnumerable LoadEntries( - IEnumerable volumes - ) + protected override IEnumerable LoadEntries(IEnumerable volumes) { var stream = volumes.Single().Stream; yield return new GZipArchiveEntry( diff --git a/src/SharpCompress/Archives/IMultiArchiveFactory.cs b/src/SharpCompress/Archives/IMultiArchiveFactory.cs index be2eefb8..c26b649f 100644 --- a/src/SharpCompress/Archives/IMultiArchiveFactory.cs +++ b/src/SharpCompress/Archives/IMultiArchiveFactory.cs @@ -32,8 +32,5 @@ public interface IMultiArchiveFactory : IFactory /// /// /// reading options. - IArchive Open( - IReadOnlyList fileInfos, - ReaderOptions? readerOptions = null - ); + IArchive Open(IReadOnlyList fileInfos, ReaderOptions? readerOptions = null); } diff --git a/src/SharpCompress/Archives/IWritableArchiveExtensions.cs b/src/SharpCompress/Archives/IWritableArchiveExtensions.cs index e534b306..794aea1f 100644 --- a/src/SharpCompress/Archives/IWritableArchiveExtensions.cs +++ b/src/SharpCompress/Archives/IWritableArchiveExtensions.cs @@ -54,9 +54,7 @@ public static class IWritableArchiveExtensions { using (writableArchive.PauseEntryRebuilding()) { - foreach ( - var path in Directory.EnumerateFiles(filePath, searchPattern, searchOption) - ) + foreach (var path in Directory.EnumerateFiles(filePath, searchPattern, searchOption)) { var fileInfo = new FileInfo(path); writableArchive.AddEntry( diff --git a/src/SharpCompress/Archives/Rar/RarArchive.cs b/src/SharpCompress/Archives/Rar/RarArchive.cs index dad32f3c..c9d8a6a8 100644 --- a/src/SharpCompress/Archives/Rar/RarArchive.cs +++ b/src/SharpCompress/Archives/Rar/RarArchive.cs @@ -107,9 +107,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, i => null, options ?? new ReaderOptions())); } /// @@ -138,10 +136,7 @@ public class RarArchive : AbstractArchive /// /// /// - public static RarArchive Open( - IEnumerable streams, - ReaderOptions? readerOptions = null - ) + public static RarArchive Open(IEnumerable streams, ReaderOptions? readerOptions = null) { streams.CheckNotNull(nameof(streams)); var strms = streams.ToArray(); diff --git a/src/SharpCompress/Archives/Rar/SeekableFilePart.cs b/src/SharpCompress/Archives/Rar/SeekableFilePart.cs index 9f27b674..e7247eae 100644 --- a/src/SharpCompress/Archives/Rar/SeekableFilePart.cs +++ b/src/SharpCompress/Archives/Rar/SeekableFilePart.cs @@ -31,6 +31,5 @@ internal class SeekableFilePart : RarFilePart return stream; } - internal override string FilePartName => - "Unknown Stream - File Entry: " + FileHeader.FileName; + 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 6d388746..236c64e2 100644 --- a/src/SharpCompress/Archives/Rar/StreamRarArchiveVolume.cs +++ b/src/SharpCompress/Archives/Rar/StreamRarArchiveVolume.cs @@ -19,12 +19,6 @@ internal class StreamRarArchiveVolume : RarVolume internal override RarFilePart CreateFilePart(MarkHeader markHeader, FileHeader fileHeader) { - return new SeekableFilePart( - markHeader, - fileHeader, - Index, - Stream, - ReaderOptions.Password - ); + return new SeekableFilePart(markHeader, fileHeader, Index, Stream, ReaderOptions.Password); } } diff --git a/src/SharpCompress/Archives/SevenZip/SevenZipArchive.cs b/src/SharpCompress/Archives/SevenZip/SevenZipArchive.cs index 870de6b2..c49bd550 100644 --- a/src/SharpCompress/Archives/SevenZip/SevenZipArchive.cs +++ b/src/SharpCompress/Archives/SevenZip/SevenZipArchive.cs @@ -145,9 +145,7 @@ public class SevenZipArchive : AbstractArchive !x.IsDirectory).GroupBy(x => x.FilePart.Folder) - ) + foreach (var group in entries.Where(x => !x.IsDirectory).GroupBy(x => x.FilePart.Folder)) { var isSolid = false; foreach (var entry in group) @@ -202,8 +200,7 @@ public class SevenZipArchive : AbstractArchive !x.IsDirectory).GroupBy(x => x.FilePart.Folder).Count() - > 1; + return Entries.Where(x => !x.IsDirectory).GroupBy(x => x.FilePart.Folder).Count() > 1; } } diff --git a/src/SharpCompress/Archives/Tar/TarArchive.cs b/src/SharpCompress/Archives/Tar/TarArchive.cs index 2870555c..cb808761 100644 --- a/src/SharpCompress/Archives/Tar/TarArchive.cs +++ b/src/SharpCompress/Archives/Tar/TarArchive.cs @@ -69,10 +69,7 @@ public class TarArchive : AbstractWritableArchive /// /// /// - public static TarArchive Open( - IEnumerable streams, - ReaderOptions? readerOptions = null - ) + public static TarArchive Open(IEnumerable streams, ReaderOptions? readerOptions = null) { streams.CheckNotNull(nameof(streams)); var strms = streams.ToArray(); @@ -182,9 +179,7 @@ public class TarArchive : AbstractWritableArchive memoryStream.Position = 0; var bytes = memoryStream.ToArray(); - header.Name = ReaderOptions.ArchiveEncoding - .Decode(bytes) - .TrimNulls(); + header.Name = ReaderOptions.ArchiveEncoding.Decode(bytes).TrimNulls(); } stream.Position = oldStreamPos; diff --git a/src/SharpCompress/Archives/Tar/TarArchiveEntry.cs b/src/SharpCompress/Archives/Tar/TarArchiveEntry.cs index d2ac353f..eee8ed7a 100644 --- a/src/SharpCompress/Archives/Tar/TarArchiveEntry.cs +++ b/src/SharpCompress/Archives/Tar/TarArchiveEntry.cs @@ -7,11 +7,8 @@ namespace SharpCompress.Archives.Tar; public class TarArchiveEntry : TarEntry, IArchiveEntry { - internal TarArchiveEntry( - TarArchive archive, - TarFilePart part, - CompressionType compressionType - ) : base(part, compressionType) + internal TarArchiveEntry(TarArchive archive, TarFilePart part, CompressionType compressionType) + : base(part, compressionType) { Archive = archive; } diff --git a/src/SharpCompress/Archives/Zip/ZipArchive.cs b/src/SharpCompress/Archives/Zip/ZipArchive.cs index 11b8cd0a..ba3ccdb9 100644 --- a/src/SharpCompress/Archives/Zip/ZipArchive.cs +++ b/src/SharpCompress/Archives/Zip/ZipArchive.cs @@ -94,10 +94,7 @@ public class ZipArchive : AbstractWritableArchive /// /// /// - public static ZipArchive Open( - IEnumerable streams, - ReaderOptions? readerOptions = null - ) + public static ZipArchive Open(IEnumerable streams, ReaderOptions? readerOptions = null) { streams.CheckNotNull(nameof(streams)); var strms = streams.ToArray(); @@ -140,10 +137,7 @@ public class ZipArchive : AbstractWritableArchive public static bool IsZipFile(Stream stream, string? password = null) { - var headerFactory = new StreamingZipHeaderFactory( - password, - new ArchiveEncoding() - ); + var headerFactory = new StreamingZipHeaderFactory(password, new ArchiveEncoding()); try { var header = headerFactory @@ -167,10 +161,7 @@ public class ZipArchive : AbstractWritableArchive public static bool IsZipMulti(Stream stream, string? password = null) { - var headerFactory = new StreamingZipHeaderFactory( - password, - new ArchiveEncoding() - ); + var headerFactory = new StreamingZipHeaderFactory(password, new ArchiveEncoding()); try { var header = headerFactory @@ -180,10 +171,7 @@ public class ZipArchive : AbstractWritableArchive { if (stream.CanSeek) //could be multipart. Test for central directory - might not be z64 safe { - var z = new SeekableZipHeaderFactory( - password, - new ArchiveEncoding() - ); + var z = new SeekableZipHeaderFactory(password, new ArchiveEncoding()); var x = z.ReadSeekableHeader(stream).FirstOrDefault(); return x?.ZipHeaderType == ZipHeaderType.DirectoryEntry; } @@ -246,32 +234,32 @@ public class ZipArchive : AbstractWritableArchive { case ZipHeaderType.DirectoryEntry: - { - var deh = (DirectoryEntryHeader)h; - Stream s; - if ( - deh.RelativeOffsetOfEntryHeader + deh.CompressedSize - > vols[deh.DiskNumberStart].Stream.Length - ) { - var v = vols.Skip(deh.DiskNumberStart).ToArray(); - s = new SourceStream( - v[0].Stream, - i => i < v.Length ? v[i].Stream : null, - new ReaderOptions() { LeaveStreamOpen = true } + var deh = (DirectoryEntryHeader)h; + Stream s; + if ( + deh.RelativeOffsetOfEntryHeader + deh.CompressedSize + > vols[deh.DiskNumberStart].Stream.Length + ) + { + var v = vols.Skip(deh.DiskNumberStart).ToArray(); + s = new SourceStream( + v[0].Stream, + i => i < v.Length ? v[i].Stream : null, + new ReaderOptions() { LeaveStreamOpen = true } + ); + } + else + { + s = vols[deh.DiskNumberStart].Stream; + } + + yield return new ZipArchiveEntry( + this, + new SeekableZipFilePart(headerFactory, deh, s) ); } - else - { - s = vols[deh.DiskNumberStart].Stream; - } - - yield return new ZipArchiveEntry( - this, - new SeekableZipFilePart(headerFactory, deh, s) - ); - } - break; + break; case ZipHeaderType.DirectoryEnd: { var bytes = ((DirectoryEndHeader)h).Comment ?? Array.Empty(); diff --git a/src/SharpCompress/Common/GZip/GZipFilePart.cs b/src/SharpCompress/Common/GZip/GZipFilePart.cs index e5e969f1..04cfc355 100644 --- a/src/SharpCompress/Common/GZip/GZipFilePart.cs +++ b/src/SharpCompress/Common/GZip/GZipFilePart.cs @@ -13,8 +13,7 @@ internal sealed class GZipFilePart : FilePart private string? _name; private readonly Stream _stream; - internal GZipFilePart(Stream stream, ArchiveEncoding archiveEncoding) - : base(archiveEncoding) + internal GZipFilePart(Stream stream, ArchiveEncoding archiveEncoding) : base(archiveEncoding) { _stream = stream; ReadAndValidateGzipHeader(); diff --git a/src/SharpCompress/Common/GZip/GZipVolume.cs b/src/SharpCompress/Common/GZip/GZipVolume.cs index cc2ec364..e13abd8c 100644 --- a/src/SharpCompress/Common/GZip/GZipVolume.cs +++ b/src/SharpCompress/Common/GZip/GZipVolume.cs @@ -8,8 +8,7 @@ public class GZipVolume : Volume public GZipVolume(Stream stream, ReaderOptions options, int index = 0) : base(stream, options, index) { } - public GZipVolume(FileInfo fileInfo, ReaderOptions options) - : base(fileInfo.OpenRead(), options) + public GZipVolume(FileInfo fileInfo, ReaderOptions options) : base(fileInfo.OpenRead(), options) { options.LeaveStreamOpen = false; } diff --git a/src/SharpCompress/Common/MultiVolumeExtractionException.cs b/src/SharpCompress/Common/MultiVolumeExtractionException.cs index 7e6f14e3..ee2f95ad 100644 --- a/src/SharpCompress/Common/MultiVolumeExtractionException.cs +++ b/src/SharpCompress/Common/MultiVolumeExtractionException.cs @@ -6,6 +6,6 @@ public class MultiVolumeExtractionException : ExtractionException { public MultiVolumeExtractionException(string message) : base(message) { } - public MultiVolumeExtractionException(string message, Exception inner) - : base(message, inner) { } + public MultiVolumeExtractionException(string message, Exception inner) : base(message, inner) + { } } diff --git a/src/SharpCompress/Common/PasswordProtectedException.cs b/src/SharpCompress/Common/PasswordProtectedException.cs index ab5317c2..7b559625 100644 --- a/src/SharpCompress/Common/PasswordProtectedException.cs +++ b/src/SharpCompress/Common/PasswordProtectedException.cs @@ -6,6 +6,5 @@ public class PasswordProtectedException : ExtractionException { public PasswordProtectedException(string message) : base(message) { } - public PasswordProtectedException(string message, Exception inner) : base(message, inner) - { } + public PasswordProtectedException(string message, Exception inner) : base(message, inner) { } } diff --git a/src/SharpCompress/Common/Rar/Headers/ArchiveCryptHeader.cs b/src/SharpCompress/Common/Rar/Headers/ArchiveCryptHeader.cs index 64edb8c4..619e8fc9 100644 --- a/src/SharpCompress/Common/Rar/Headers/ArchiveCryptHeader.cs +++ b/src/SharpCompress/Common/Rar/Headers/ArchiveCryptHeader.cs @@ -30,10 +30,7 @@ internal class ArchiveCryptHeader : RarHeader return; } var encryptionFlags = reader.ReadRarVIntUInt32(); - _usePswCheck = FlagUtility.HasFlag( - encryptionFlags, - EncryptionFlagsV5.CHFL_CRYPT_PSWCHECK - ); + _usePswCheck = FlagUtility.HasFlag(encryptionFlags, EncryptionFlagsV5.CHFL_CRYPT_PSWCHECK); _lg2Count = reader.ReadRarVIntByte(1); //UsePswCheck = HasHeaderFlag(EncryptionFlagsV5.CHFL_CRYPT_PSWCHECK); diff --git a/src/SharpCompress/Common/Rar/Headers/FileHeader.cs b/src/SharpCompress/Common/Rar/Headers/FileHeader.cs index 66a8a78b..d0f7450b 100644 --- a/src/SharpCompress/Common/Rar/Headers/FileHeader.cs +++ b/src/SharpCompress/Common/Rar/Headers/FileHeader.cs @@ -116,13 +116,13 @@ internal class FileHeader : RarHeader //TODO case 1: // file encryption - { - isEncryptedRar5 = true; + { + isEncryptedRar5 = true; - //var version = reader.ReadRarVIntByte(); - //if (version != 0) throw new InvalidFormatException("unknown encryption algorithm " + version); - } - break; + //var version = reader.ReadRarVIntByte(); + //if (version != 0) throw new InvalidFormatException("unknown encryption algorithm " + version); + } + break; // case 2: // file hash // { // @@ -130,23 +130,23 @@ internal class FileHeader : RarHeader // break; case 3: // file time - { - var flags = reader.ReadRarVIntUInt16(); - var isWindowsTime = (flags & 1) == 0; - if ((flags & 0x2) == 0x2) { - FileLastModifiedTime = ReadExtendedTimeV5(reader, isWindowsTime); + var flags = reader.ReadRarVIntUInt16(); + var isWindowsTime = (flags & 1) == 0; + if ((flags & 0x2) == 0x2) + { + FileLastModifiedTime = ReadExtendedTimeV5(reader, isWindowsTime); + } + if ((flags & 0x4) == 0x4) + { + FileCreatedTime = ReadExtendedTimeV5(reader, isWindowsTime); + } + if ((flags & 0x8) == 0x8) + { + FileLastAccessedTime = ReadExtendedTimeV5(reader, isWindowsTime); + } } - if ((flags & 0x4) == 0x4) - { - FileCreatedTime = ReadExtendedTimeV5(reader, isWindowsTime); - } - if ((flags & 0x8) == 0x8) - { - FileLastAccessedTime = ReadExtendedTimeV5(reader, isWindowsTime); - } - } - break; + break; //TODO // case 4: // file version // { @@ -262,54 +262,54 @@ internal class FileHeader : RarHeader { case HeaderCodeV.RAR4_FILE_HEADER: - { - if (HasFlag(FileFlagsV4.UNICODE)) { - var length = 0; - while (length < fileNameBytes.Length && fileNameBytes[length] != 0) + if (HasFlag(FileFlagsV4.UNICODE)) { - length++; - } - if (length != nameSize) - { - length++; - FileName = FileNameDecoder.Decode(fileNameBytes, length); + var length = 0; + while (length < fileNameBytes.Length && fileNameBytes[length] != 0) + { + length++; + } + if (length != nameSize) + { + length++; + FileName = FileNameDecoder.Decode(fileNameBytes, length); + } + else + { + FileName = ArchiveEncoding.Decode(fileNameBytes); + } } else { FileName = ArchiveEncoding.Decode(fileNameBytes); } + FileName = ConvertPathV4(FileName); } - else - { - FileName = ArchiveEncoding.Decode(fileNameBytes); - } - FileName = ConvertPathV4(FileName); - } - break; + break; case HeaderCodeV.RAR4_NEW_SUB_HEADER: - { - var datasize = HeaderSize - newLhdSize - nameSize; - if (HasFlag(FileFlagsV4.SALT)) { - datasize -= saltSize; - } - if (datasize > 0) - { - SubData = reader.ReadBytes(datasize); - } + var datasize = HeaderSize - newLhdSize - nameSize; + if (HasFlag(FileFlagsV4.SALT)) + { + datasize -= saltSize; + } + if (datasize > 0) + { + SubData = reader.ReadBytes(datasize); + } - if (NewSubHeaderType.SUBHEAD_TYPE_RR.Equals(fileNameBytes)) - { - RecoverySectors = - SubData[8] - + (SubData[9] << 8) - + (SubData[10] << 16) - + (SubData[11] << 24); + if (NewSubHeaderType.SUBHEAD_TYPE_RR.Equals(fileNameBytes)) + { + RecoverySectors = + SubData[8] + + (SubData[9] << 8) + + (SubData[10] << 16) + + (SubData[11] << 24); + } } - } - break; + break; } if (HasFlag(FileFlagsV4.SALT)) diff --git a/src/SharpCompress/Common/Rar/Headers/FileNameDecoder.cs b/src/SharpCompress/Common/Rar/Headers/FileNameDecoder.cs index c6b85001..d6447b49 100644 --- a/src/SharpCompress/Common/Rar/Headers/FileNameDecoder.cs +++ b/src/SharpCompress/Common/Rar/Headers/FileNameDecoder.cs @@ -66,11 +66,7 @@ internal static class FileNameDecoder } else { - for ( - length += 2; - length > 0 && decPos < name.Length; - length--, decPos++ - ) + for (length += 2; length > 0 && decPos < name.Length; length--, decPos++) { buf.Append((char)(GetChar(name, decPos))); } diff --git a/src/SharpCompress/Common/Rar/Headers/RarHeaderFactory.cs b/src/SharpCompress/Common/Rar/Headers/RarHeaderFactory.cs index 37a59d2d..d371166d 100644 --- a/src/SharpCompress/Common/Rar/Headers/RarHeaderFactory.cs +++ b/src/SharpCompress/Common/Rar/Headers/RarHeaderFactory.cs @@ -21,11 +21,7 @@ public class RarHeaderFactory public IEnumerable ReadHeaders(Stream stream) { - var markHeader = MarkHeader.Read( - stream, - Options.LeaveStreamOpen, - Options.LookForHeader - ); + var markHeader = MarkHeader.Read(stream, Options.LeaveStreamOpen, Options.LookForHeader); _isRar5 = markHeader.IsRar5; yield return markHeader; @@ -87,16 +83,16 @@ public class RarHeaderFactory { case StreamingMode.Seekable: - { - reader.BaseStream.Position += ph.DataSize; - } - break; + { + reader.BaseStream.Position += ph.DataSize; + } + break; case StreamingMode.Streaming: - { - reader.BaseStream.Skip(ph.DataSize); - } - break; + { + reader.BaseStream.Skip(ph.DataSize); + } + break; default: { throw new InvalidFormatException("Invalid StreamingMode"); @@ -128,32 +124,29 @@ public class RarHeaderFactory { case StreamingMode.Seekable: - { - fh.DataStartPosition = reader.BaseStream.Position; - reader.BaseStream.Position += fh.CompressedSize; - } - break; + { + 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) { - fh.PackedStream = ms; + var ms = new ReadOnlySubStream(reader.BaseStream, fh.CompressedSize); + if (fh.R4Salt is null) + { + fh.PackedStream = ms; + } + else + { + fh.PackedStream = new RarCryptoWrapper( + ms, + Options.Password!, + fh.R4Salt + ); + } } - else - { - fh.PackedStream = new RarCryptoWrapper( - ms, - Options.Password!, - fh.R4Salt - ); - } - } - break; + break; default: { throw new InvalidFormatException("Invalid StreamingMode"); @@ -185,18 +178,18 @@ public class RarHeaderFactory { case StreamingMode.Seekable: - { - fh.DataStartPosition = reader.BaseStream.Position; - reader.BaseStream.Position += fh.CompressedSize; - } - break; + { + 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); - } - break; + { + //skip the data because it's useless? + reader.BaseStream.Skip(fh.CompressedSize); + } + break; default: { throw new InvalidFormatException("Invalid StreamingMode"); diff --git a/src/SharpCompress/Common/Rar/RarVolume.cs b/src/SharpCompress/Common/Rar/RarVolume.cs index eac09e33..49c04698 100644 --- a/src/SharpCompress/Common/Rar/RarVolume.cs +++ b/src/SharpCompress/Common/Rar/RarVolume.cs @@ -42,45 +42,45 @@ public abstract class RarVolume : Volume { case HeaderType.Mark: - { - lastMarkHeader = (MarkHeader)header; - } - break; + { + lastMarkHeader = (MarkHeader)header; + } + break; case HeaderType.Archive: - { - ArchiveHeader = (ArchiveHeader)header; - } - break; + { + ArchiveHeader = (ArchiveHeader)header; + } + break; case HeaderType.File: - { - var fh = (FileHeader)header; - if (_maxCompressionAlgorithm < fh.CompressionAlgorithm) { - _maxCompressionAlgorithm = fh.CompressionAlgorithm; - } + var fh = (FileHeader)header; + if (_maxCompressionAlgorithm < fh.CompressionAlgorithm) + { + _maxCompressionAlgorithm = fh.CompressionAlgorithm; + } - yield return CreateFilePart(lastMarkHeader!, fh); - } - break; + yield return CreateFilePart(lastMarkHeader!, fh); + } + 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 - ); + 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 + ); + } } - } - break; + break; } } } diff --git a/src/SharpCompress/Common/SevenZip/ArchiveReader.cs b/src/SharpCompress/Common/SevenZip/ArchiveReader.cs index 908fb453..543b5323 100644 --- a/src/SharpCompress/Common/SevenZip/ArchiveReader.cs +++ b/src/SharpCompress/Common/SevenZip/ArchiveReader.cs @@ -154,11 +154,7 @@ internal class ArchiveReader return ReadBitVector(length); } - private void ReadNumberVector( - List dataVector, - int numFiles, - Action action - ) + private void ReadNumberVector(List dataVector, int numFiles, Action action) { var defined = ReadOptionalBitVector(numFiles); @@ -877,9 +873,7 @@ internal class ArchiveReader outStream.ReadExact(data, 0, data.Length); if (outStream.ReadByte() >= 0) { - throw new InvalidOperationException( - "Decoded stream is longer than expected." - ); + throw new InvalidOperationException("Decoded stream is longer than expected."); } dataVector.Add(data); @@ -1030,7 +1024,7 @@ internal class ArchiveReader ReadAttributeVector( dataVector, numFiles, - delegate (int i, uint? attr) + delegate(int i, uint? attr) { // Some third party implementations established an unofficial extension // of the 7z archive format by placing posix file attributes in the high @@ -1124,17 +1118,12 @@ internal class ArchiveReader ReadNumberVector( dataVector, numFiles, - delegate (int i, long? startPos) + delegate(int i, long? startPos) { db._files[i].StartPos = startPos; #if DEBUG Log.Write( - " " - + ( - startPos.HasValue - ? startPos.Value.ToString() - : "n/a" - ) + " " + (startPos.HasValue ? startPos.Value.ToString() : "n/a") ); #endif } @@ -1150,13 +1139,11 @@ internal class ArchiveReader ReadDateTimeVector( dataVector, numFiles, - delegate (int i, DateTime? time) + delegate(int i, DateTime? time) { db._files[i].CTime = time; #if DEBUG - Log.Write( - " " + (time.HasValue ? time.Value.ToString() : "n/a") - ); + Log.Write(" " + (time.HasValue ? time.Value.ToString() : "n/a")); #endif } ); @@ -1171,13 +1158,11 @@ internal class ArchiveReader ReadDateTimeVector( dataVector, numFiles, - delegate (int i, DateTime? time) + delegate(int i, DateTime? time) { db._files[i].ATime = time; #if DEBUG - Log.Write( - " " + (time.HasValue ? time.Value.ToString() : "n/a") - ); + Log.Write(" " + (time.HasValue ? time.Value.ToString() : "n/a")); #endif } ); @@ -1192,13 +1177,11 @@ internal class ArchiveReader ReadDateTimeVector( dataVector, numFiles, - delegate (int i, DateTime? time) + delegate(int i, DateTime? time) { db._files[i].MTime = time; #if DEBUG - Log.Write( - " " + (time.HasValue ? time.Value.ToString() : "n/a") - ); + Log.Write(" " + (time.HasValue ? time.Value.ToString() : "n/a")); #endif } ); @@ -1276,7 +1259,7 @@ internal class ArchiveReader // TODO: Check Signature! _header = new byte[0x20]; - for (var offset = 0; offset < 0x20;) + for (var offset = 0; offset < 0x20; ) { var delta = stream.Read(_header, offset, 0x20 - offset); if (delta == 0) @@ -1625,11 +1608,7 @@ internal class ArchiveReader var efi = extractFolderInfoVector.Last(); var startIndex = db._folderStartFileIndex[folderIndex]; - for ( - var index = efi._extractStatuses.Count; - index <= fileIndex - startIndex; - index++ - ) + for (var index = efi._extractStatuses.Count; index <= fileIndex - startIndex; index++) { efi._extractStatuses.Add(index == fileIndex - startIndex); } diff --git a/src/SharpCompress/Common/SevenZip/SevenZipFilePart.cs b/src/SharpCompress/Common/SevenZip/SevenZipFilePart.cs index 234d4a1d..92e375aa 100644 --- a/src/SharpCompress/Common/SevenZip/SevenZipFilePart.cs +++ b/src/SharpCompress/Common/SevenZip/SevenZipFilePart.cs @@ -45,15 +45,9 @@ internal class SevenZipFilePart : FilePart { return null!; } - var folderStream = _database.GetFolderStream( - _stream, - Folder!, - _database.PasswordProvider - ); + var folderStream = _database.GetFolderStream(_stream, Folder!, _database.PasswordProvider); - var firstFileIndex = _database._folderStartFileIndex[ - _database._folders.IndexOf(Folder!) - ]; + var firstFileIndex = _database._folderStartFileIndex[_database._folders.IndexOf(Folder!)]; var skipCount = Index - firstFileIndex; long skipSize = 0; for (var i = 0; i < skipCount; i++) diff --git a/src/SharpCompress/Common/Tar/Headers/TarHeader.cs b/src/SharpCompress/Common/Tar/Headers/TarHeader.cs index 78c2e0d9..5ae1b806 100644 --- a/src/SharpCompress/Common/Tar/Headers/TarHeader.cs +++ b/src/SharpCompress/Common/Tar/Headers/TarHeader.cs @@ -9,15 +9,7 @@ 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 DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); public TarHeader(ArchiveEncoding archiveEncoding) { diff --git a/src/SharpCompress/Common/Tar/TarHeaderFactory.cs b/src/SharpCompress/Common/Tar/TarHeaderFactory.cs index 0edb7463..85eec5b4 100644 --- a/src/SharpCompress/Common/Tar/TarHeaderFactory.cs +++ b/src/SharpCompress/Common/Tar/TarHeaderFactory.cs @@ -29,19 +29,19 @@ internal static class TarHeaderFactory { case StreamingMode.Seekable: - { - header.DataStartPosition = reader.BaseStream.Position; + { + header.DataStartPosition = reader.BaseStream.Position; - //skip to nearest 512 - reader.BaseStream.Position += PadTo512(header.Size); - } - break; + //skip to nearest 512 + reader.BaseStream.Position += PadTo512(header.Size); + } + break; case StreamingMode.Streaming: - { - header.PackedStream = new TarReadOnlySubStream(stream, header.Size); - } - break; + { + header.PackedStream = new TarReadOnlySubStream(stream, header.Size); + } + break; default: { throw new InvalidFormatException("Invalid StreamingMode"); diff --git a/src/SharpCompress/Common/Zip/Headers/DirectoryEntryHeader.cs b/src/SharpCompress/Common/Zip/Headers/DirectoryEntryHeader.cs index dc566482..fc2cb262 100644 --- a/src/SharpCompress/Common/Zip/Headers/DirectoryEntryHeader.cs +++ b/src/SharpCompress/Common/Zip/Headers/DirectoryEntryHeader.cs @@ -60,9 +60,7 @@ internal class DirectoryEntryHeader : ZipFileEntry Name = ((ExtraUnicodePathExtraField)unicodePathExtra).UnicodeName; } - var zip64ExtraData = Extra - .OfType() - .FirstOrDefault(); + var zip64ExtraData = Extra.OfType().FirstOrDefault(); if (zip64ExtraData != null) { zip64ExtraData.Process( diff --git a/src/SharpCompress/Common/Zip/Headers/LocalEntryHeader.cs b/src/SharpCompress/Common/Zip/Headers/LocalEntryHeader.cs index 3cd8ce46..93cc55ac 100644 --- a/src/SharpCompress/Common/Zip/Headers/LocalEntryHeader.cs +++ b/src/SharpCompress/Common/Zip/Headers/LocalEntryHeader.cs @@ -50,9 +50,7 @@ internal class LocalEntryHeader : ZipFileEntry Name = ((ExtraUnicodePathExtraField)unicodePathExtra).UnicodeName; } - var zip64ExtraData = Extra - .OfType() - .FirstOrDefault(); + var zip64ExtraData = Extra.OfType().FirstOrDefault(); if (zip64ExtraData != null) { zip64ExtraData.Process(UncompressedSize, CompressedSize, 0, 0); diff --git a/src/SharpCompress/Common/Zip/Headers/LocalEntryHeaderExtraFactory.cs b/src/SharpCompress/Common/Zip/Headers/LocalEntryHeaderExtraFactory.cs index 4920ca36..b230e9cc 100644 --- a/src/SharpCompress/Common/Zip/Headers/LocalEntryHeaderExtraFactory.cs +++ b/src/SharpCompress/Common/Zip/Headers/LocalEntryHeaderExtraFactory.cs @@ -61,11 +61,8 @@ internal sealed class ExtraUnicodePathExtraField : ExtraData internal sealed class Zip64ExtendedInformationExtraField : ExtraData { - public Zip64ExtendedInformationExtraField( - ExtraDataType type, - ushort length, - byte[] dataBytes - ) : base(type, length, dataBytes) { } + public Zip64ExtendedInformationExtraField(ExtraDataType type, ushort length, byte[] dataBytes) + : base(type, length, dataBytes) { } // From the spec, values are only in the extradata if the standard // value is set to 0xFFFFFFFF (or 0xFFFF for the Disk Start Number). @@ -105,9 +102,7 @@ internal sealed class Zip64ExtendedInformationExtraField : ExtraData if (compressedFileSize == uint.MaxValue) { - CompressedSize = BinaryPrimitives.ReadInt64LittleEndian( - DataBytes.AsSpan(currentIndex) - ); + CompressedSize = BinaryPrimitives.ReadInt64LittleEndian(DataBytes.AsSpan(currentIndex)); currentIndex += 8; } @@ -121,9 +116,7 @@ internal sealed class Zip64ExtendedInformationExtraField : ExtraData if (diskNumber == ushort.MaxValue) { - VolumeNumber = BinaryPrimitives.ReadUInt32LittleEndian( - DataBytes.AsSpan(currentIndex) - ); + VolumeNumber = BinaryPrimitives.ReadUInt32LittleEndian(DataBytes.AsSpan(currentIndex)); } } diff --git a/src/SharpCompress/Common/Zip/Headers/ZipFileEntry.cs b/src/SharpCompress/Common/Zip/Headers/ZipFileEntry.cs index 7ac43a07..79347014 100644 --- a/src/SharpCompress/Common/Zip/Headers/ZipFileEntry.cs +++ b/src/SharpCompress/Common/Zip/Headers/ZipFileEntry.cs @@ -59,8 +59,7 @@ internal abstract class ZipFileEntry : ZipHeader var buffer = new byte[12]; archiveStream.ReadFully(buffer); - var encryptionData = - PkwareTraditionalEncryptionData.ForRead(Password!, this, buffer); + var encryptionData = PkwareTraditionalEncryptionData.ForRead(Password!, this, buffer); return encryptionData; } @@ -75,10 +74,9 @@ internal abstract class ZipFileEntry : ZipHeader protected void LoadExtra(byte[] extra) { - for (var i = 0; i < extra.Length - 4;) + for (var i = 0; i < extra.Length - 4; ) { - var type = (ExtraDataType) - BinaryPrimitives.ReadUInt16LittleEndian(extra.AsSpan(i)); + var type = (ExtraDataType)BinaryPrimitives.ReadUInt16LittleEndian(extra.AsSpan(i)); if (!Enum.IsDefined(typeof(ExtraDataType), type)) { type = ExtraDataType.NotImplementedExtraData; diff --git a/src/SharpCompress/Common/Zip/StreamingZipHeaderFactory.cs b/src/SharpCompress/Common/Zip/StreamingZipHeaderFactory.cs index 485ad901..3e5cd808 100644 --- a/src/SharpCompress/Common/Zip/StreamingZipHeaderFactory.cs +++ b/src/SharpCompress/Common/Zip/StreamingZipHeaderFactory.cs @@ -30,10 +30,8 @@ internal class StreamingZipHeaderFactory : ZipHeaderFactory if ( _lastEntryHeader != null && ( - FlagUtility.HasFlag( - _lastEntryHeader.Flags, - HeaderFlags.UsePostDataDescriptor - ) || _lastEntryHeader.IsZip64 + FlagUtility.HasFlag(_lastEntryHeader.Flags, HeaderFlags.UsePostDataDescriptor) + || _lastEntryHeader.IsZip64 ) ) { diff --git a/src/SharpCompress/Common/Zip/ZipFilePart.cs b/src/SharpCompress/Common/Zip/ZipFilePart.cs index 54c64d16..4a8dbc2a 100644 --- a/src/SharpCompress/Common/Zip/ZipFilePart.cs +++ b/src/SharpCompress/Common/Zip/ZipFilePart.cs @@ -105,9 +105,7 @@ internal abstract class ZipFilePart : FilePart } case ZipCompressionMethod.WinzipAes: { - var data = Header.Extra.SingleOrDefault( - x => x.Type == ExtraDataType.WinZipAes - ); + var data = Header.Extra.SingleOrDefault(x => x.Type == ExtraDataType.WinZipAes); if (data is null) { throw new InvalidFormatException("No Winzip AES extra data found."); @@ -116,9 +114,7 @@ internal abstract class ZipFilePart : FilePart { throw new InvalidFormatException("Winzip data length is not 7."); } - var compressedMethod = BinaryPrimitives.ReadUInt16LittleEndian( - data.DataBytes - ); + var compressedMethod = BinaryPrimitives.ReadUInt16LittleEndian(data.DataBytes); if (compressedMethod != 0x01 && compressedMethod != 0x02) { @@ -127,9 +123,7 @@ internal abstract class ZipFilePart : FilePart ); } - var vendorId = BinaryPrimitives.ReadUInt16LittleEndian( - data.DataBytes.AsSpan(2) - ); + var vendorId = BinaryPrimitives.ReadUInt16LittleEndian(data.DataBytes.AsSpan(2)); if (vendorId != 0x4541) { throw new InvalidFormatException( @@ -144,9 +138,7 @@ internal abstract class ZipFilePart : FilePart } default: { - throw new NotSupportedException( - "CompressionMethod: " + Header.CompressionMethod - ); + throw new NotSupportedException("CompressionMethod: " + Header.CompressionMethod); } } } diff --git a/src/SharpCompress/Common/Zip/ZipHeaderFactory.cs b/src/SharpCompress/Common/Zip/ZipHeaderFactory.cs index e7737cec..8a58e220 100644 --- a/src/SharpCompress/Common/Zip/ZipHeaderFactory.cs +++ b/src/SharpCompress/Common/Zip/ZipHeaderFactory.cs @@ -55,12 +55,7 @@ internal class ZipHeaderFactory } case POST_DATA_DESCRIPTOR: { - if ( - FlagUtility.HasFlag( - _lastEntryHeader!.Flags, - HeaderFlags.UsePostDataDescriptor - ) - ) + if (FlagUtility.HasFlag(_lastEntryHeader!.Flags, HeaderFlags.UsePostDataDescriptor)) { _lastEntryHeader.Crc = reader.ReadUInt32(); _lastEntryHeader.CompressedSize = zip64 diff --git a/src/SharpCompress/Compressors/ADC/ADCStream.cs b/src/SharpCompress/Compressors/ADC/ADCStream.cs index 9d57d1d7..313583db 100644 --- a/src/SharpCompress/Compressors/ADC/ADCStream.cs +++ b/src/SharpCompress/Compressors/ADC/ADCStream.cs @@ -1,4 +1,4 @@ -// +// // ADC.cs // // Author: @@ -66,10 +66,7 @@ public sealed class ADCStream : Stream /// /// Stream that contains the compressed data /// Must be set to because compression is not implemented - public ADCStream( - Stream stream, - CompressionMode compressionMode = CompressionMode.Decompress - ) + public ADCStream(Stream stream, CompressionMode compressionMode = CompressionMode.Decompress) { if (compressionMode == CompressionMode.Compress) { diff --git a/src/SharpCompress/Compressors/BZip2/BZip2Stream.cs b/src/SharpCompress/Compressors/BZip2/BZip2Stream.cs index 1c7aaeb4..852adc1e 100644 --- a/src/SharpCompress/Compressors/BZip2/BZip2Stream.cs +++ b/src/SharpCompress/Compressors/BZip2/BZip2Stream.cs @@ -14,11 +14,7 @@ public sealed class BZip2Stream : Stream /// The stream to read from /// Compression Mode /// Decompress Concatenated - public BZip2Stream( - Stream stream, - CompressionMode compressionMode, - bool decompressConcatenated - ) + public BZip2Stream(Stream stream, CompressionMode compressionMode, bool decompressConcatenated) { Mode = compressionMode; if (Mode == CompressionMode.Compress) diff --git a/src/SharpCompress/Compressors/BZip2/CBZip2InputStream.cs b/src/SharpCompress/Compressors/BZip2/CBZip2InputStream.cs index 5f58b363..f53f48dc 100644 --- a/src/SharpCompress/Compressors/BZip2/CBZip2InputStream.cs +++ b/src/SharpCompress/Compressors/BZip2/CBZip2InputStream.cs @@ -342,8 +342,7 @@ internal class CBZip2InputStream : Stream CrcError(); } - computedCombinedCRC = - (computedCombinedCRC << 1) | (int)(((uint)computedCombinedCRC) >> 31); + computedCombinedCRC = (computedCombinedCRC << 1) | (int)(((uint)computedCombinedCRC) >> 31); computedCombinedCRC ^= computedBlockCRC; } @@ -631,15 +630,7 @@ internal class CBZip2InputStream : Stream minLen = len[t][i]; } } - HbCreateDecodeTables( - limit[t], - basev[t], - perm[t], - len[t], - minLen, - maxLen, - alphaSize - ); + HbCreateDecodeTables(limit[t], basev[t], perm[t], len[t], minLen, maxLen, alphaSize); minLens[t] = minLen; } } diff --git a/src/SharpCompress/Compressors/BZip2/CBZip2OutputStream.cs b/src/SharpCompress/Compressors/BZip2/CBZip2OutputStream.cs index d2bf3448..2e79312e 100644 --- a/src/SharpCompress/Compressors/BZip2/CBZip2OutputStream.cs +++ b/src/SharpCompress/Compressors/BZip2/CBZip2OutputStream.cs @@ -1275,15 +1275,15 @@ internal sealed class CBZip2OutputStream : Stream unLo = ltLo = lo; unHi = gtHi = hi; + while (true) + { while (true) { - while (true) + if (unLo > unHi) { - if (unLo > unHi) - { - break; - } - n = block[zptr[unLo] + d + 1] - med; + break; + } + n = block[zptr[unLo] + d + 1] - med; if (n == 0) { var temp = 0; @@ -1311,30 +1311,30 @@ internal sealed class CBZip2OutputStream : Stream if (n == 0) { var temp = 0; - temp = zptr[unHi]; - zptr[unHi] = zptr[gtHi]; - zptr[gtHi] = temp; - gtHi--; - unHi--; - continue; - } - ; - if (n < 0) - { - break; - } + temp = zptr[unHi]; + zptr[unHi] = zptr[gtHi]; + zptr[gtHi] = temp; + gtHi--; unHi--; + continue; } - if (unLo > unHi) + ; + if (n < 0) { break; } - var tempx = zptr[unLo]; - zptr[unLo] = zptr[unHi]; - zptr[unHi] = tempx; - unLo++; unHi--; } + if (unLo > unHi) + { + break; + } + var tempx = zptr[unLo]; + zptr[unLo] = zptr[unHi]; + zptr[unHi] = tempx; + unLo++; + unHi--; + } if (gtHi < ltLo) { diff --git a/src/SharpCompress/Compressors/Deflate/DeflateManager.cs b/src/SharpCompress/Compressors/Deflate/DeflateManager.cs index f424b1a0..a7dff8b5 100644 --- a/src/SharpCompress/Compressors/Deflate/DeflateManager.cs +++ b/src/SharpCompress/Compressors/Deflate/DeflateManager.cs @@ -1150,19 +1150,12 @@ internal sealed partial class DeflateManager else if (static_lenb == opt_lenb) { send_bits((STATIC_TREES << 1) + (eof ? 1 : 0), 3); - send_compressed_block( - StaticTree.lengthAndLiteralsTreeCodes, - StaticTree.distTreeCodes - ); + send_compressed_block(StaticTree.lengthAndLiteralsTreeCodes, StaticTree.distTreeCodes); } else { send_bits((DYN_TREES << 1) + (eof ? 1 : 0), 3); - send_all_trees( - treeLiterals.max_code + 1, - treeDistances.max_code + 1, - max_blindex + 1 - ); + send_all_trees(treeLiterals.max_code + 1, treeDistances.max_code + 1, max_blindex + 1); send_compressed_block(dyn_ltree, dyn_dtree); } @@ -1352,10 +1345,8 @@ internal sealed partial class DeflateManager strstart++; ins_h = - ( - (ins_h << hash_shift) - ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff) - ) & hash_mask; + ((ins_h << hash_shift) ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff)) + & hash_mask; // prev[strstart&w_mask]=hash_head=head[ins_h]; hash_head = (head[ins_h] & 0xffff); @@ -1373,8 +1364,7 @@ internal sealed partial class DeflateManager match_length = 0; ins_h = window[strstart] & 0xff; - ins_h = - (((ins_h) << hash_shift) ^ (window[strstart + 1] & 0xff)) & hash_mask; + ins_h = (((ins_h) << hash_shift) ^ (window[strstart + 1] & 0xff)) & hash_mask; // If lookahead < MIN_MATCH, ins_h is garbage, but it does not // matter since it will be recomputed at next deflate call. @@ -1595,8 +1585,7 @@ internal sealed partial class DeflateManager int match; // matched string int len; // length of current match var best_len = prev_length; // best match length so far - var limit = - strstart > (w_size - MIN_LOOKAHEAD) ? strstart - (w_size - MIN_LOOKAHEAD) : 0; + var limit = strstart > (w_size - MIN_LOOKAHEAD) ? strstart - (w_size - MIN_LOOKAHEAD) : 0; var niceLength = config.NiceLength; @@ -1651,8 +1640,7 @@ internal sealed partial class DeflateManager // We check for insufficient lookahead only every 8th comparison; // the 256th check will be made at strstart+258. - do - { } while ( + do { } while ( window[++scan] == window[++match] && window[++scan] == window[++match] && window[++scan] == window[++match] @@ -1678,9 +1666,7 @@ internal sealed partial class DeflateManager scan_end1 = window[scan + best_len - 1]; scan_end = window[scan + best_len]; } - } while ( - (cur_match = (prev[cur_match & wmask] & 0xffff)) > limit && --chain_length != 0 - ); + } while ((cur_match = (prev[cur_match & wmask] & 0xffff)) > limit && --chain_length != 0); if (best_len <= lookahead) { @@ -1890,8 +1876,7 @@ internal sealed partial class DeflateManager for (var n = 0; n <= length - MIN_MATCH; n++) { - ins_h = - (((ins_h) << hash_shift) ^ (window[(n) + (MIN_MATCH - 1)] & 0xff)) & hash_mask; + ins_h = (((ins_h) << hash_shift) ^ (window[(n) + (MIN_MATCH - 1)] & 0xff)) & hash_mask; prev[n & w_mask] = head[ins_h]; head[ins_h] = (short)n; } @@ -1917,9 +1902,7 @@ internal sealed partial class DeflateManager } if (_codec.AvailableBytesOut == 0) { - _codec.Message = _ErrorMessage[ - ZlibConstants.Z_NEED_DICT - (ZlibConstants.Z_BUF_ERROR) - ]; + _codec.Message = _ErrorMessage[ZlibConstants.Z_NEED_DICT - (ZlibConstants.Z_BUF_ERROR)]; throw new ZlibException("OutputBuffer is full (AvailableBytesOut == 0)"); //return ZlibConstants.Z_BUF_ERROR; @@ -2006,9 +1989,7 @@ internal sealed partial class DeflateManager // User must not provide more input after the first FINISH: if (status == FINISH_STATE && _codec.AvailableBytesIn != 0) { - _codec.Message = _ErrorMessage[ - ZlibConstants.Z_NEED_DICT - (ZlibConstants.Z_BUF_ERROR) - ]; + _codec.Message = _ErrorMessage[ZlibConstants.Z_NEED_DICT - (ZlibConstants.Z_BUF_ERROR)]; throw new ZlibException("status == FINISH_STATE && _codec.AvailableBytesIn != 0"); } diff --git a/src/SharpCompress/Compressors/Deflate/InfTree.cs b/src/SharpCompress/Compressors/Deflate/InfTree.cs index 89f02d7a..74f4069d 100644 --- a/src/SharpCompress/Compressors/Deflate/InfTree.cs +++ b/src/SharpCompress/Compressors/Deflate/InfTree.cs @@ -2187,13 +2187,7 @@ internal sealed class InfTree return Z_OK; } - internal static int inflate_trees_fixed( - int[] bl, - int[] bd, - int[][] tl, - int[][] td, - ZlibCodec z - ) + internal static int inflate_trees_fixed(int[] bl, int[] bd, int[][] tl, int[][] td, ZlibCodec z) { bl[0] = fixed_bl; bd[0] = fixed_bd; diff --git a/src/SharpCompress/Compressors/Deflate/Inflate.cs b/src/SharpCompress/Compressors/Deflate/Inflate.cs index 91bea79e..abeebb32 100644 --- a/src/SharpCompress/Compressors/Deflate/Inflate.cs +++ b/src/SharpCompress/Compressors/Deflate/Inflate.cs @@ -562,10 +562,7 @@ internal sealed class InflateBlocks i = index; t = table; - if ( - i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) - || (c == 16 && i < 1) - ) + if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) || (c == 16 && i < 1)) { blens = null; mode = InflateBlockMode.BAD; @@ -781,10 +778,7 @@ internal sealed class InflateBlocks // update check information if (checkfn != null) { - _codec._adler32 = check = Adler32.Calculate( - check, - window.AsSpan(readAt, nBytes) - ); + _codec._adler32 = check = Adler32.Calculate(check, window.AsSpan(readAt, nBytes)); } // copy as far as end of window @@ -983,8 +977,7 @@ internal sealed class InflateCodes { // Handling missing trailing bit(s) var tmp_tindex = - (tree_index + (b & InternalInflateConstants.InflateMask[k])) - * 3; + (tree_index + (b & InternalInflateConstants.InflateMask[k])) * 3; if (k >= tree[tmp_tindex + 1]) { break; @@ -1098,8 +1091,7 @@ internal sealed class InflateCodes { // Handling missing trailing bit(s) var tmp_tindex = - (tree_index + (b & InternalInflateConstants.InflateMask[k])) - * 3; + (tree_index + (b & InternalInflateConstants.InflateMask[k])) * 3; if (k >= tree[tmp_tindex + 1]) { break; @@ -1209,10 +1201,7 @@ internal sealed class InflateCodes if (q == blocks.end && blocks.readAt != 0) { q = 0; - m = - q < blocks.readAt - ? blocks.readAt - q - 1 - : blocks.end - q; + m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q; } if (m == 0) diff --git a/src/SharpCompress/Compressors/Deflate/Tree.cs b/src/SharpCompress/Compressors/Deflate/Tree.cs index 7056e7a0..25f8ada3 100644 --- a/src/SharpCompress/Compressors/Deflate/Tree.cs +++ b/src/SharpCompress/Compressors/Deflate/Tree.cs @@ -960,9 +960,7 @@ internal sealed partial class DeflateManager ///
internal static int DistanceCode(int dist) { - return (dist < 256) - ? _dist_code[dist] - : _dist_code[256 + SharedUtils.URShift(dist, 7)]; + return (dist < 256) ? _dist_code[dist] : _dist_code[256 + SharedUtils.URShift(dist, 7)]; } // Compute the optimal bit lengths for a tree and update the total bit length diff --git a/src/SharpCompress/Compressors/Deflate/Zlib.cs b/src/SharpCompress/Compressors/Deflate/Zlib.cs index 0c5865fb..00336548 100644 --- a/src/SharpCompress/Compressors/Deflate/Zlib.cs +++ b/src/SharpCompress/Compressors/Deflate/Zlib.cs @@ -234,12 +234,7 @@ internal class SharedUtils /// count depending on the data available in the source TextReader. Returns -1 /// if the end of the stream is reached. /// - public static int ReadInput( - TextReader sourceTextReader, - byte[] target, - int start, - int count - ) + public static int ReadInput(TextReader sourceTextReader, byte[] target, int start, int count) { // Returns 0 bytes if not enough space in target if (target.Length == 0) diff --git a/src/SharpCompress/Compressors/Deflate64/DeflateInput.cs b/src/SharpCompress/Compressors/Deflate64/DeflateInput.cs index f539e3bb..b4e8fc82 100644 --- a/src/SharpCompress/Compressors/Deflate64/DeflateInput.cs +++ b/src/SharpCompress/Compressors/Deflate64/DeflateInput.cs @@ -34,7 +34,7 @@ internal sealed class DeflateInput } internal /*readonly */ -readonly struct InputState + readonly struct InputState { internal readonly int _count; internal readonly int _startIndex; diff --git a/src/SharpCompress/Compressors/Deflate64/InflaterManaged.cs b/src/SharpCompress/Compressors/Deflate64/InflaterManaged.cs index a4890899..7b11812e 100644 --- a/src/SharpCompress/Compressors/Deflate64/InflaterManaged.cs +++ b/src/SharpCompress/Compressors/Deflate64/InflaterManaged.cs @@ -468,8 +468,7 @@ internal sealed class InflaterManaged _blockLengthBuffer[_state - InflaterState.UncompressedByte1] = (byte)bits; if (_state == InflaterState.UncompressedByte4) { - _blockLength = - _blockLengthBuffer[0] + (_blockLengthBuffer[1] * 256); + _blockLength = _blockLengthBuffer[0] + (_blockLengthBuffer[1] * 256); var blockLengthComplement = _blockLengthBuffer[2] + (_blockLengthBuffer[3] * 256); diff --git a/src/SharpCompress/Compressors/Filters/BranchExecFilter.cs b/src/SharpCompress/Compressors/Filters/BranchExecFilter.cs index 8dffc4d5..83260180 100644 --- a/src/SharpCompress/Compressors/Filters/BranchExecFilter.cs +++ b/src/SharpCompress/Compressors/Filters/BranchExecFilter.cs @@ -64,11 +64,7 @@ public sealed class BranchExecFilter mask >>= (int)d; if ( mask != 0 - && ( - mask > 4 - || mask == 3 - || (((((data[(mask >> 1) + 1])) + 1) & 0xFE) == 0) - ) + && (mask > 4 || mask == 3 || (((((data[(mask >> 1) + 1])) + 1) & 0xFE) == 0)) ) { mask = (mask >> 1) | 4; @@ -253,10 +249,8 @@ public sealed class BranchExecFilter var iterator = (i + (m * 5) - 8); if ( ((data[iterator + 3] >> (int)m) & 15) == 5 - && ( - ((data[iterator - 1] | ((uint)data[iterator] << 8)) >> (int)m) - & 0x70 - ) == 0 + && (((data[iterator - 1] | ((uint)data[iterator] << 8)) >> (int)m) & 0x70) + == 0 ) { var raw = BitConverter.ToUInt32(data, (int)iterator); diff --git a/src/SharpCompress/Compressors/LZMA/DecoderStream.cs b/src/SharpCompress/Compressors/LZMA/DecoderStream.cs index 11c62528..2b2e20b4 100644 --- a/src/SharpCompress/Compressors/LZMA/DecoderStream.cs +++ b/src/SharpCompress/Compressors/LZMA/DecoderStream.cs @@ -145,10 +145,7 @@ internal static class DecoderStreamHelper ); } - var otherCoderIndex = FindCoderIndexForOutStreamIndex( - folderInfo, - pairedOutIndex - ); + var otherCoderIndex = FindCoderIndexForOutStreamIndex(folderInfo, pairedOutIndex); inStreams[i] = CreateDecoderStream( packStreams, packSizes, @@ -215,7 +212,11 @@ internal static class DecoderStreamHelper var outStreams = new Stream[folderInfo._unpackSizes.Count]; - FindPrimaryOutStreamIndex(folderInfo, out var primaryCoderIndex, out var primaryOutStreamIndex); + FindPrimaryOutStreamIndex( + folderInfo, + out var primaryCoderIndex, + out var primaryOutStreamIndex + ); return CreateDecoderStream( inStreams, packSizes, diff --git a/src/SharpCompress/Compressors/LZMA/ICoder.cs b/src/SharpCompress/Compressors/LZMA/ICoder.cs index c0fd198b..569568f5 100644 --- a/src/SharpCompress/Compressors/LZMA/ICoder.cs +++ b/src/SharpCompress/Compressors/LZMA/ICoder.cs @@ -53,13 +53,7 @@ internal interface ICoder /// /// callback progress reference. /// - void Code( - Stream inStream, - Stream outStream, - long inSize, - long outSize, - ICodeProgress progress - ); + void Code(Stream inStream, Stream outStream, long inSize, long outSize, ICodeProgress progress); } /* diff --git a/src/SharpCompress/Compressors/LZMA/LZipStream.cs b/src/SharpCompress/Compressors/LZMA/LZipStream.cs index 5d799619..d55f8d7e 100644 --- a/src/SharpCompress/Compressors/LZMA/LZipStream.cs +++ b/src/SharpCompress/Compressors/LZMA/LZipStream.cs @@ -124,8 +124,7 @@ public sealed class LZipStream : Stream public override int ReadByte() => _stream.ReadByte(); - public override long Seek(long offset, SeekOrigin origin) => - throw new NotSupportedException(); + public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException(); public override void SetLength(long value) => throw new NotImplementedException(); diff --git a/src/SharpCompress/Compressors/LZMA/LzmaDecoder.cs b/src/SharpCompress/Compressors/LZMA/LzmaDecoder.cs index 8889dd68..e22fbaf3 100644 --- a/src/SharpCompress/Compressors/LZMA/LzmaDecoder.cs +++ b/src/SharpCompress/Compressors/LZMA/LzmaDecoder.cs @@ -13,12 +13,8 @@ public class Decoder : ICoder, ISetDecoderProperties // ,System.IO.Stream { private BitDecoder _choice = new BitDecoder(); private BitDecoder _choice2 = new BitDecoder(); - 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 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 uint _numPosStates; @@ -163,10 +159,7 @@ public class Decoder : ICoder, ISetDecoderProperties // ,System.IO.Stream byte matchByte ) { - return _coders[GetState(pos, prevByte)].DecodeWithMatchByte( - rangeDecoder, - matchByte - ); + return _coders[GetState(pos, prevByte)].DecodeWithMatchByte(rangeDecoder, matchByte); } } @@ -413,9 +406,7 @@ public class Decoder : ICoder, ISetDecoderProperties // ,System.IO.Stream _rep1 = _rep0; len = Base.K_MATCH_MIN_LEN + _lenDecoder.Decode(rangeDecoder, posState); _state.UpdateMatch(); - var posSlot = _posSlotDecoder[Base.GetLenToPosState(len)].Decode( - rangeDecoder - ); + var posSlot = _posSlotDecoder[Base.GetLenToPosState(len)].Decode(rangeDecoder); if (posSlot >= Base.K_START_POS_MODEL_INDEX) { var numDirectBits = (int)((posSlot >> 1) - 1); @@ -432,9 +423,8 @@ public class Decoder : ICoder, ISetDecoderProperties // ,System.IO.Stream else { _rep0 += ( - rangeDecoder.DecodeDirectBits( - numDirectBits - Base.K_NUM_ALIGN_BITS - ) << Base.K_NUM_ALIGN_BITS + rangeDecoder.DecodeDirectBits(numDirectBits - Base.K_NUM_ALIGN_BITS) + << Base.K_NUM_ALIGN_BITS ); _rep0 += _posAlignDecoder.ReverseDecode(rangeDecoder); } diff --git a/src/SharpCompress/Compressors/LZMA/LzmaEncoder.cs b/src/SharpCompress/Compressors/LZMA/LzmaEncoder.cs index be1e8a08..1495ec2c 100644 --- a/src/SharpCompress/Compressors/LZMA/LzmaEncoder.cs +++ b/src/SharpCompress/Compressors/LZMA/LzmaEncoder.cs @@ -108,11 +108,7 @@ internal class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties } } - public void EncodeMatched( - RangeCoder.Encoder rangeEncoder, - byte matchByte, - byte symbol - ) + public void EncodeMatched(RangeCoder.Encoder rangeEncoder, byte matchByte, byte symbol) { uint context = 1; var same = true; @@ -278,8 +274,7 @@ internal class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties { return; } - prices[st + i] = - b0 + _midCoder[posState].GetPrice(i - Base.K_NUM_LOW_LEN_SYMBOLS); + prices[st + i] = b0 + _midCoder[posState].GetPrice(i - Base.K_NUM_LOW_LEN_SYMBOLS); } for (; i < numSymbols; i++) { @@ -569,9 +564,7 @@ internal class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties private uint GetRepLen1Price(Base.State state, uint posState) { return _isRepG0[state._index].GetPrice0() - + _isRep0Long[ - (state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState - ].GetPrice0(); + + _isRep0Long[(state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState].GetPrice0(); } private uint GetPureRepPrice(uint repIndex, Base.State state, uint posState) @@ -786,8 +779,7 @@ internal class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties var price = repMatchPrice + GetPureRepPrice(i, _state, posState); do { - var curAndLenPrice = - price + _repMatchLenEncoder.GetPrice(repLen - 2, posState); + var curAndLenPrice = price + _repMatchLenEncoder.GetPrice(repLen - 2, posState); var optimum = _optimum[repLen]; if (curAndLenPrice < optimum._price) { @@ -812,8 +804,7 @@ internal class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties for (; ; len++) { var distance = _matchDistances[offs + 1]; - var curAndLenPrice = - normalMatchPrice + GetPosLenPrice(distance, len, posState); + var curAndLenPrice = normalMatchPrice + GetPosLenPrice(distance, len, posState); var optimum = _optimum[len]; if (curAndLenPrice < optimum._price) { @@ -964,9 +955,7 @@ internal class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties var curAnd1Price = curPrice - + _isMatch[ - (state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState - ].GetPrice0() + + _isMatch[(state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState].GetPrice0() + _literalEncoder .GetSubCoder(position, _matchFinder.GetIndexByte(0 - 2)) .GetPrice(!state.IsCharState(), matchByte, currentByte); @@ -984,9 +973,7 @@ internal class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties matchPrice = curPrice - + _isMatch[ - (state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState - ].GetPrice1(); + + _isMatch[(state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState].GetPrice1(); repMatchPrice = matchPrice + _isRep[state._index].GetPrice1(); if ( @@ -1057,11 +1044,7 @@ internal class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties for (uint repIndex = 0; repIndex < Base.K_NUM_REP_DISTANCES; repIndex++) { - var lenTest = _matchFinder.GetMatchLen( - 0 - 1, - _reps[repIndex], - numAvailableBytes - ); + var lenTest = _matchFinder.GetMatchLen(0 - 1, _reps[repIndex], numAvailableBytes); if (lenTest < 2) { continue; @@ -1095,11 +1078,7 @@ internal class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties if (lenTest < numAvailableBytesFull) { var t = Math.Min(numAvailableBytesFull - 1 - lenTest, _numFastBytes); - var lenTest2 = _matchFinder.GetMatchLen( - (int)lenTest, - _reps[repIndex], - t - ); + var lenTest2 = _matchFinder.GetMatchLen((int)lenTest, _reps[repIndex], t); if (lenTest2 >= 2) { var state2 = state; @@ -1130,8 +1109,7 @@ internal class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties + _isMatch[ (state2._index << Base.K_NUM_POS_STATES_BITS_MAX) + posStateNext ].GetPrice1(); - var nextRepMatchPrice = - nextMatchPrice + _isRep[state2._index].GetPrice1(); + var nextRepMatchPrice = nextMatchPrice + _isRep[state2._index].GetPrice1(); // for(; lenTest2 >= 2; lenTest2--) { @@ -1141,8 +1119,7 @@ internal class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties _optimum[++lenEnd]._price = K_IFINITY_PRICE; } var curAndLenPrice = - nextRepMatchPrice - + GetRepPrice(0, lenTest2, state2, posStateNext); + nextRepMatchPrice + GetRepPrice(0, lenTest2, state2, posStateNext); var optimum = _optimum[cur + offset]; if (curAndLenPrice < optimum._price) { @@ -1205,15 +1182,8 @@ internal class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties { if (lenTest < numAvailableBytesFull) { - var t = Math.Min( - numAvailableBytesFull - 1 - lenTest, - _numFastBytes - ); - var lenTest2 = _matchFinder.GetMatchLen( - (int)lenTest, - curBack, - t - ); + var t = Math.Min(numAvailableBytesFull - 1 - lenTest, _numFastBytes); + var lenTest2 = _matchFinder.GetMatchLen((int)lenTest, curBack, t); if (lenTest2 >= 2) { var state2 = state; @@ -1410,10 +1380,7 @@ internal class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties { _isMatch[complexState].Encode(_rangeEncoder, 0); var curByte = _matchFinder.GetIndexByte((int)(0 - _additionalOffset)); - var subCoder = _literalEncoder.GetSubCoder( - (uint)_nowPos64, - _previousByte - ); + var subCoder = _literalEncoder.GetSubCoder((uint)_nowPos64, _previousByte); if (!_state.IsCharState()) { var matchByte = _matchFinder.GetIndexByte( @@ -1729,11 +1696,7 @@ internal class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties ); } - for ( - uint lenToPosState = 0; - lenToPosState < Base.K_NUM_LEN_TO_POS_STATES; - lenToPosState++ - ) + for (uint lenToPosState = 0; lenToPosState < Base.K_NUM_LEN_TO_POS_STATES; lenToPosState++) { uint posSlot; var encoder = _posSlotEncoder[lenToPosState]; @@ -1858,11 +1821,7 @@ internal class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties } _dictionarySize = (uint)dictionarySize; int dicLogSize; - for ( - dicLogSize = 0; - dicLogSize < (uint)kDicLogSizeMaxCompress; - dicLogSize++ - ) + for (dicLogSize = 0; dicLogSize < (uint)kDicLogSizeMaxCompress; dicLogSize++) { if (dictionarySize <= ((uint)(1) << dicLogSize)) { diff --git a/src/SharpCompress/Compressors/LZMA/LzmaStream.cs b/src/SharpCompress/Compressors/LZMA/LzmaStream.cs index 108381e5..aa7a42c9 100644 --- a/src/SharpCompress/Compressors/LZMA/LzmaStream.cs +++ b/src/SharpCompress/Compressors/LZMA/LzmaStream.cs @@ -194,9 +194,7 @@ public class LzmaStream : Stream { _inputPosition += _outWindow.CopyStream(_inputStream, toProcess); } - else if ( - _decoder.Code(_dictionarySize, _outWindow, _rangeDecoder) && _outputSize < 0 - ) + else if (_decoder.Code(_dictionarySize, _outWindow, _rangeDecoder) && _outputSize < 0) { _availableBytes = _outWindow.AvailableBytes; } diff --git a/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoderBit.cs b/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoderBit.cs index 15827a54..2123f204 100644 --- a/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoderBit.cs +++ b/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoderBit.cs @@ -135,8 +135,7 @@ internal struct BitDecoder _prob -= (_prob) >> K_NUM_MOVE_BITS; if (rangeDecoder._range < Decoder.K_TOP_VALUE) { - rangeDecoder._code = - (rangeDecoder._code << 8) | (byte)rangeDecoder._stream.ReadByte(); + rangeDecoder._code = (rangeDecoder._code << 8) | (byte)rangeDecoder._stream.ReadByte(); rangeDecoder._range <<= 8; rangeDecoder._total++; } diff --git a/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoderBitTree.cs b/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoderBitTree.cs index cef8872c..b6a66e82 100644 --- a/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoderBitTree.cs +++ b/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoderBitTree.cs @@ -22,7 +22,7 @@ internal readonly struct BitTreeEncoder public void Encode(Encoder rangeEncoder, uint symbol) { uint m = 1; - for (var bitIndex = _numBitLevels; bitIndex > 0;) + for (var bitIndex = _numBitLevels; bitIndex > 0; ) { bitIndex--; var bit = (symbol >> bitIndex) & 1; @@ -47,7 +47,7 @@ internal readonly struct BitTreeEncoder { uint price = 0; uint m = 1; - for (var bitIndex = _numBitLevels; bitIndex > 0;) + for (var bitIndex = _numBitLevels; bitIndex > 0; ) { bitIndex--; var bit = (symbol >> bitIndex) & 1; diff --git a/src/SharpCompress/Compressors/PPMd/H/ModelPPM.cs b/src/SharpCompress/Compressors/PPMd/H/ModelPPM.cs index 1eb8ae3d..1675acf7 100644 --- a/src/SharpCompress/Compressors/PPMd/H/ModelPPM.cs +++ b/src/SharpCompress/Compressors/PPMd/H/ModelPPM.cs @@ -367,10 +367,7 @@ internal class ModelPpm { _orderFall++; _minContext.Address = _minContext.GetSuffix(); // =MinContext->Suffix; - if ( - _minContext.Address <= SubAlloc.PText - || _minContext.Address > SubAlloc.HeapEnd - ) + if (_minContext.Address <= SubAlloc.PText || _minContext.Address > SubAlloc.HeapEnd) { return (-1); } @@ -683,11 +680,10 @@ internal class ModelPpm // .getSummFreq() <= 8 * ns1) ? 1 : 0)); var sum = ((2 * ns1 < ns) ? 1 : 0) - + (2 - * ( - ((4 * ns1 <= ns) ? 1 : 0) - & ((pc.FreqData.SummFreq <= 8 * ns1) ? 1 : 0) - )); + + ( + 2 + * (((4 * ns1 <= ns) ? 1 : 0) & ((pc.FreqData.SummFreq <= 8 * ns1) ? 1 : 0)) + ); pc.FreqData.IncrementSummFreq(sum); } else @@ -719,11 +715,7 @@ internal class ModelPpm } else { - cf = - 4 - + (cf >= 9 * sf ? 1 : 0) - + (cf >= 12 * sf ? 1 : 0) - + (cf >= 15 * sf ? 1 : 0); + cf = 4 + (cf >= 9 * sf ? 1 : 0) + (cf >= 12 * sf ? 1 : 0) + (cf >= 15 * sf ? 1 : 0); pc.FreqData.IncrementSummFreq(cf); } p.Address = pc.FreqData.GetStats() + (ns1 * State.SIZE); @@ -926,10 +918,7 @@ internal class ModelPpm { _orderFall++; _minContext.Address = _minContext.GetSuffix(); - if ( - _minContext.Address <= SubAlloc.PText - || _minContext.Address > SubAlloc.HeapEnd - ) + if (_minContext.Address <= SubAlloc.PText || _minContext.Address > SubAlloc.HeapEnd) { return -1; } diff --git a/src/SharpCompress/Compressors/PPMd/H/PPMContext.cs b/src/SharpCompress/Compressors/PPMd/H/PPMContext.cs index 52768984..b27da093 100644 --- a/src/SharpCompress/Compressors/PPMd/H/PPMContext.cs +++ b/src/SharpCompress/Compressors/PPMd/H/PPMContext.cs @@ -24,8 +24,7 @@ internal class PpmContext : Pointer { if (Memory != null) { - _numStats = - BinaryPrimitives.ReadInt16LittleEndian(Memory.AsSpan(Address)) & 0xffff; + _numStats = BinaryPrimitives.ReadInt16LittleEndian(Memory.AsSpan(Address)) & 0xffff; } return _numStats; } @@ -61,25 +60,7 @@ internal class PpmContext : Pointer private int _suffix; // pointer ppmcontext //UPGRADE_NOTE: Final was removed from the declaration of 'ExpEscape'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly int[] EXP_ESCAPE = - { - 25, - 14, - 9, - 7, - 5, - 5, - 4, - 4, - 4, - 3, - 3, - 3, - 2, - 2, - 2, - 2 - }; + public static readonly int[] EXP_ESCAPE = { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 }; // Temp fields //UPGRADE_NOTE: Final was removed from the declaration of 'tempState1 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" diff --git a/src/SharpCompress/Compressors/PPMd/H/RarMemBlock.cs b/src/SharpCompress/Compressors/PPMd/H/RarMemBlock.cs index f3f7b147..cdf8cef8 100644 --- a/src/SharpCompress/Compressors/PPMd/H/RarMemBlock.cs +++ b/src/SharpCompress/Compressors/PPMd/H/RarMemBlock.cs @@ -21,8 +21,7 @@ internal class RarMemBlock : Pointer { if (Memory != null) { - _stamp = - BinaryPrimitives.ReadInt16LittleEndian(Memory.AsSpan(Address)) & 0xffff; + _stamp = BinaryPrimitives.ReadInt16LittleEndian(Memory.AsSpan(Address)) & 0xffff; } return _stamp; } diff --git a/src/SharpCompress/Compressors/PPMd/H/State.cs b/src/SharpCompress/Compressors/PPMd/H/State.cs index 3aa9b20f..186476c3 100644 --- a/src/SharpCompress/Compressors/PPMd/H/State.cs +++ b/src/SharpCompress/Compressors/PPMd/H/State.cs @@ -71,17 +71,17 @@ internal sealed class State : Pointer return this; } - internal static void PpmdSwap(State ptr1, State ptr2) + internal static void PpmdSwap(State ptr1, State ptr2) + { + byte[] mem1 = ptr1.Memory, + mem2 = ptr2.Memory; + for (int i = 0, pos1 = ptr1.Address, pos2 = ptr2.Address; i < SIZE; i++, pos1++, pos2++) { - byte[] mem1 = ptr1.Memory, - mem2 = ptr2.Memory; - for (int i = 0, pos1 = ptr1.Address, pos2 = ptr2.Address; i < SIZE; i++, pos1++, pos2++) - { - var temp = mem1[pos1]; - mem1[pos1] = mem2[pos2]; - mem2[pos2] = temp; - } + var temp = mem1[pos1]; + mem1[pos1] = mem2[pos2]; + mem2[pos2] = temp; } + } public override string ToString() { diff --git a/src/SharpCompress/Compressors/PPMd/H/SubAllocator.cs b/src/SharpCompress/Compressors/PPMd/H/SubAllocator.cs index a3757715..43aaeca2 100644 --- a/src/SharpCompress/Compressors/PPMd/H/SubAllocator.cs +++ b/src/SharpCompress/Compressors/PPMd/H/SubAllocator.cs @@ -247,11 +247,7 @@ internal class SubAllocator p.Address = s0.GetNext(); while (p.Address != s0.Address) { - for ( - p.Remove(), sz = p.GetNu(); - sz > 128; - sz -= 128, p.Address = MbPtr(p.Address, 128) - ) + for (p.Remove(), sz = p.GetNu(); sz > 128; sz -= 128, p.Address = MbPtr(p.Address, 128)) { InsertNode(p.Address, N_INDEXES - 1); } diff --git a/src/SharpCompress/Compressors/PPMd/I1/Allocator.cs b/src/SharpCompress/Compressors/PPMd/I1/Allocator.cs index 6f66e310..ac270a3d 100644 --- a/src/SharpCompress/Compressors/PPMd/I1/Allocator.cs +++ b/src/SharpCompress/Compressors/PPMd/I1/Allocator.cs @@ -338,11 +338,7 @@ internal class Allocator for (uint index = 0; index < INDEX_COUNT; index++) { - for ( - memoryNode = _memoryNodes[index]; - counts[index] != 0; - memoryNode = memoryNode.Next - ) + for (memoryNode = _memoryNodes[index]; counts[index] != 0; memoryNode = memoryNode.Next) { while (memoryNode.Next.Stamp == 0) { @@ -435,8 +431,7 @@ internal class Allocator if (memoryNode0.UnitCount != 0) { while ( - (memoryNode2 = memoryNode0 + memoryNode0.UnitCount).Stamp - == uint.MaxValue + (memoryNode2 = memoryNode0 + memoryNode0.UnitCount).Stamp == uint.MaxValue ) { memoryNode0.UnitCount += memoryNode2.UnitCount; diff --git a/src/SharpCompress/Compressors/PPMd/I1/Coder.cs b/src/SharpCompress/Compressors/PPMd/I1/Coder.cs index c1644521..75a4e65b 100644 --- a/src/SharpCompress/Compressors/PPMd/I1/Coder.cs +++ b/src/SharpCompress/Compressors/PPMd/I1/Coder.cs @@ -35,8 +35,7 @@ internal class Coder { while ( (_low ^ (_low + _range)) < RANGE_TOP - || _range < RANGE_BOTTOM - && ((_range = (uint)-_low & (RANGE_BOTTOM - 1)) != 0 || true) + || _range < RANGE_BOTTOM && ((_range = (uint)-_low & (RANGE_BOTTOM - 1)) != 0 || true) ) { stream.WriteByte((byte)(_low >> 24)); @@ -81,8 +80,7 @@ internal class Coder { while ( (_low ^ (_low + _range)) < RANGE_TOP - || _range < RANGE_BOTTOM - && ((_range = (uint)-_low & (RANGE_BOTTOM - 1)) != 0 || true) + || _range < RANGE_BOTTOM && ((_range = (uint)-_low & (RANGE_BOTTOM - 1)) != 0 || true) ) { _code = (_code << 8) | (byte)stream.ReadByte(); diff --git a/src/SharpCompress/Compressors/PPMd/I1/Model.cs b/src/SharpCompress/Compressors/PPMd/I1/Model.cs index aebfcae8..f630aced 100644 --- a/src/SharpCompress/Compressors/PPMd/I1/Model.cs +++ b/src/SharpCompress/Compressors/PPMd/I1/Model.cs @@ -853,11 +853,7 @@ internal partial class Model } else { - Refresh( - (uint)((currentContext.NumberStatistics + 3) >> 1), - false, - currentContext - ); + Refresh((uint)((currentContext.NumberStatistics + 3) >> 1), false, currentContext); } } @@ -870,24 +866,17 @@ internal partial class Model ); } else if ( - (currentContext.SummaryFrequency += 4) - > 128 + (4 * currentContext.NumberStatistics) + (currentContext.SummaryFrequency += 4) > 128 + (4 * currentContext.NumberStatistics) ) { - Refresh( - (uint)((currentContext.NumberStatistics + 2) >> 1), - true, - currentContext - ); + Refresh((uint)((currentContext.NumberStatistics + 2) >> 1), true, currentContext); } } if (_method > ModelRestorationMethod.Freeze) { _maximumContext = foundStateSuccessor; - _allocator._glueCount += (uint)( - ((_allocator._memoryNodes[1].Stamp & 1) == 0) ? 1 : 0 - ); + _allocator._glueCount += (uint)(((_allocator._memoryNodes[1].Stamp & 1) == 0) ? 1 : 0); } else if (_method == ModelRestorationMethod.Freeze) { diff --git a/src/SharpCompress/Compressors/PPMd/I1/Pointer.cs b/src/SharpCompress/Compressors/PPMd/I1/Pointer.cs index 791a556d..48fa7fff 100644 --- a/src/SharpCompress/Compressors/PPMd/I1/Pointer.cs +++ b/src/SharpCompress/Compressors/PPMd/I1/Pointer.cs @@ -46,9 +46,7 @@ internal struct Pointer #if DEBUG if (_address == 0) { - throw new InvalidOperationException( - "The pointer being indexed is a null pointer." - ); + throw new InvalidOperationException("The pointer being indexed is a null pointer."); } #endif return _memory[_address + offset]; @@ -58,9 +56,7 @@ internal struct Pointer #if DEBUG if (_address == 0) { - throw new InvalidOperationException( - "The pointer being indexed is a null pointer." - ); + throw new InvalidOperationException("The pointer being indexed is a null pointer."); } #endif _memory[_address + offset] = value; @@ -143,9 +139,7 @@ internal struct Pointer #if DEBUG if (pointer._address == 0) { - throw new InvalidOperationException( - "The pointer being incremented is a null pointer." - ); + throw new InvalidOperationException("The pointer being incremented is a null pointer."); } #endif pointer._address++; @@ -198,9 +192,7 @@ internal struct Pointer #if DEBUG if (pointer._address == 0) { - throw new InvalidOperationException( - "The pointer being decremented is a null pointer." - ); + throw new InvalidOperationException("The pointer being decremented is a null pointer."); } #endif pointer._address--; diff --git a/src/SharpCompress/Compressors/PPMd/I1/PpmContext.cs b/src/SharpCompress/Compressors/PPMd/I1/PpmContext.cs index 3e122032..9df07688 100644 --- a/src/SharpCompress/Compressors/PPMd/I1/PpmContext.cs +++ b/src/SharpCompress/Compressors/PPMd/I1/PpmContext.cs @@ -402,7 +402,7 @@ internal partial class Model _coder._lowCount = lowCount; lowCount += state.Frequency; _coder._highCount = lowCount; - for (var p1 = state; --index != 0;) + for (var p1 = state; --index != 0; ) { do { diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack.cs index 08ba47f2..08f0ddeb 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack.cs @@ -555,11 +555,7 @@ internal sealed partial class Unpack : BitInput, IRarUnpack } // memcpy(&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],&Prg->GlobalData[VM_FIXEDGLOBALSIZE],Prg->GlobalData.Size()-VM_FIXEDGLOBALSIZE); - for ( - var i = 0; - i < Prg.GlobalData.Count - RarVM.VM_FIXEDGLOBALSIZE; - i++ - ) + for (var i = 0; i < Prg.GlobalData.Count - RarVM.VM_FIXEDGLOBALSIZE; i++) { ParentPrg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i] = Prg.GlobalData[ RarVM.VM_FIXEDGLOBALSIZE + i @@ -621,8 +617,9 @@ internal sealed partial class Unpack : BitInput, IRarUnpack i++ ) { - NextPrg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i] = - pPrg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i]; + NextPrg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i] = pPrg.GlobalData[ + RarVM.VM_FIXEDGLOBALSIZE + i + ]; } } @@ -643,8 +640,9 @@ internal sealed partial class Unpack : BitInput, IRarUnpack i++ ) { - pPrg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i] = - NextPrg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i]; + pPrg.GlobalData[RarVM.VM_FIXEDGLOBALSIZE + i] = NextPrg.GlobalData[ + RarVM.VM_FIXEDGLOBALSIZE + i + ]; } } else @@ -758,11 +756,7 @@ internal sealed partial class Unpack : BitInput, IRarUnpack var destPtr = unpPtr - distance; // System.out.println(unpPtr+":"+distance); - if ( - destPtr >= 0 - && destPtr < PackDef.MAXWINSIZE - 260 - && unpPtr < PackDef.MAXWINSIZE - 260 - ) + if (destPtr >= 0 && destPtr < PackDef.MAXWINSIZE - 260 && unpPtr < PackDef.MAXWINSIZE - 260) { window[unpPtr++] = window[destPtr++]; @@ -931,7 +925,7 @@ internal sealed partial class Unpack : BitInput, IRarUnpack var TableSize = PackDef.HUFF_TABLE_SIZE; - for (var i = 0; i < TableSize;) + for (var i = 0; i < TableSize; ) { if (inAddr > readTop - 5) { diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack15.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack15.cs index c0257809..bac545db 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack15.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack15.cs @@ -181,25 +181,7 @@ internal partial class Unpack private static readonly int[] PosHf4 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0 }; - private static readonly int[] ShortLen1 = - { - 1, - 3, - 4, - 4, - 5, - 6, - 7, - 8, - 8, - 4, - 4, - 5, - 6, - 6, - 4, - 0 - }; + private static readonly int[] ShortLen1 = { 1, 3, 4, 4, 5, 6, 7, 8, 8, 4, 4, 5, 6, 6, 4, 0 }; private static readonly int[] ShortXor1 = { @@ -220,25 +202,7 @@ internal partial class Unpack 0xb0 }; - private static readonly int[] ShortLen2 = - { - 2, - 3, - 3, - 3, - 4, - 4, - 5, - 6, - 6, - 4, - 4, - 5, - 6, - 6, - 4, - 0 - }; + private static readonly int[] ShortLen2 = { 2, 3, 3, 3, 4, 4, 5, 6, 6, 4, 4, 5, 6, 6, 4, 0 }; private static readonly int[] ShortXor2 = { diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack20.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack20.cs index 1b882545..15b980da 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack20.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack20.cs @@ -492,12 +492,7 @@ internal partial class Unpack { UnpackUtility.makeDecodeTables(Table, 0, LD, PackDef.NC20); UnpackUtility.makeDecodeTables(Table, PackDef.NC20, DD, PackDef.DC20); - UnpackUtility.makeDecodeTables( - Table, - PackDef.NC20 + PackDef.DC20, - RD, - PackDef.RC20 - ); + UnpackUtility.makeDecodeTables(Table, PackDef.NC20 + PackDef.DC20, RD, PackDef.RC20); } // memcpy(UnpOldTable20,Table,sizeof(UnpOldTable20)); diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack50.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack50.cs index 553e1896..52757e12 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack50.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack50.cs @@ -430,8 +430,7 @@ internal partial class Unpack // If distance to filter start is that large that due to circular dictionary // mode now it points to old not written yet data, then we set 'NextWindow' // flag and process this filter only after processing that older data. - Filter.NextWindow = - WrPtr != UnpPtr && ((WrPtr - UnpPtr) & MaxWinMask) <= Filter.BlockStart; + Filter.NextWindow = WrPtr != UnpPtr && ((WrPtr - UnpPtr) & MaxWinMask) <= Filter.BlockStart; Filter.uBlockStart = (uint)((Filter.BlockStart + UnpPtr) & MaxWinMask); Filters.Add(Filter); @@ -490,10 +489,7 @@ internal partial class Unpack { // We may need to quit from main extraction loop and read new block header // and trees earlier than data in input buffer ends. - ReadBorder = Math.Min( - ReadBorder, - BlockHeader.BlockStart + BlockHeader.BlockSize - 1 - ); + ReadBorder = Math.Min(ReadBorder, BlockHeader.BlockStart + BlockHeader.BlockSize - 1); } return ReadCode != -1; } @@ -821,9 +817,7 @@ internal partial class Unpack } Header.BlockSize = BlockSize; - var CheckSum = (byte)( - 0x5a ^ BlockFlags ^ BlockSize ^ (BlockSize >> 8) ^ (BlockSize >> 16) - ); + var CheckSum = (byte)(0x5a ^ BlockFlags ^ BlockSize ^ (BlockSize >> 8) ^ (BlockSize >> 16)); if (CheckSum != SavedCheckSum) { return false; diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/UnpackUtility.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/UnpackUtility.cs index 1db60c89..563ca47b 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/UnpackUtility.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/UnpackUtility.cs @@ -184,12 +184,7 @@ internal static class UnpackUtility return (dec.DecodeNum[N]); } - internal static void makeDecodeTables( - byte[] lenTab, - int offset, - Decode.Decode dec, - int size - ) + internal static void makeDecodeTables(byte[] lenTab, int offset, Decode.Decode dec, int size) { Span lenCount = stackalloc int[16]; Span tmpPos = stackalloc int[16]; @@ -204,11 +199,7 @@ internal static class UnpackUtility lenCount[lenTab[offset + i] & 0xF]++; } lenCount[0] = 0; - for ( - tmpPos[0] = 0, dec.DecodePos[0] = 0, dec.DecodeLen[0] = 0, N = 0, i = 1; - i < 16; - i++ - ) + for (tmpPos[0] = 0, dec.DecodePos[0] = 0, dec.DecodeLen[0] = 0, N = 0, i = 1; i < 16; i++) { N = 2 * (N + lenCount[i]); M = N << (15 - i); diff --git a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack15_cpp.cs b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack15_cpp.cs index 80c2d03c..4be34b90 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack15_cpp.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack15_cpp.cs @@ -321,10 +321,7 @@ internal partial class Unpack { for (Length = 0; ; Length++) { - if ( - ((BitField ^ ShortXor1[Length]) & (~(0xff >> (int)GetShortLen1(Length)))) - == 0 - ) + if (((BitField ^ ShortXor1[Length]) & (~(0xff >> (int)GetShortLen1(Length)))) == 0) { break; } @@ -336,10 +333,7 @@ internal partial class Unpack { for (Length = 0; ; Length++) { - if ( - ((BitField ^ ShortXor2[Length]) & (~(0xff >> (int)GetShortLen2(Length)))) - == 0 - ) + if (((BitField ^ ShortXor2[Length]) & (~(0xff >> (int)GetShortLen2(Length)))) == 0) { break; } @@ -734,8 +728,6 @@ internal partial class Unpack } Inp.faddbits(StartPos); - return ( - ((Num - (I != 0 ? DecTab[I - 1] : 0)) >> (int)(16 - StartPos)) + PosTab[StartPos] - ); + return (((Num - (I != 0 ? DecTab[I - 1] : 0)) >> (int)(16 - StartPos)) + PosTab[StartPos]); } } diff --git a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack20_cpp.cs b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack20_cpp.cs index d43a4ff2..b92af290 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack20_cpp.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack20_cpp.cs @@ -414,7 +414,7 @@ internal partial class Unpack Inp.addbits(4); } MakeDecodeTables(BitLength, 0, BlockTables.BD, BC20); - for (uint I = 0; I < TableSize;) + for (uint I = 0; I < TableSize; ) { if (Inp.InAddr > ReadTop - 5) { diff --git a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack50_cpp.cs b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack50_cpp.cs index 08f58601..5f7bf613 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack50_cpp.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack50_cpp.cs @@ -77,10 +77,7 @@ internal partial class Unpack } } - if ( - ((WriteBorder - UnpPtr) & MaxWinMask) < MAX_LZ_MATCH + 3 - && WriteBorder != UnpPtr - ) + if (((WriteBorder - UnpPtr) & MaxWinMask) < MAX_LZ_MATCH + 3 && WriteBorder != UnpPtr) { UnpWriteBuf(); if (WrittenFileSize > DestUnpSize) @@ -284,8 +281,7 @@ internal partial class Unpack // If distance to filter start is that large that due to circular dictionary // mode now it points to old not written yet data, then we set 'NextWindow' // flag and process this filter only after processing that older data. - Filter.NextWindow = - WrPtr != UnpPtr && ((WrPtr - UnpPtr) & MaxWinMask) <= Filter.BlockStart; + Filter.NextWindow = WrPtr != UnpPtr && ((WrPtr - UnpPtr) & MaxWinMask) <= Filter.BlockStart; Filter.BlockStart = (Filter.BlockStart + UnpPtr) & MaxWinMask; Filters.Add(Filter); @@ -340,10 +336,7 @@ internal partial class Unpack { // We may need to quit from main extraction loop and read new block header // and trees earlier than data in input buffer ends. - ReadBorder = Math.Min( - ReadBorder, - BlockHeader.BlockStart + BlockHeader.BlockSize - 1 - ); + ReadBorder = Math.Min(ReadBorder, BlockHeader.BlockStart + BlockHeader.BlockSize - 1); } return ReadCode != -1; } @@ -539,66 +532,66 @@ internal partial class Unpack case FILTER_E8: case FILTER_E8E9: - { - var FileOffset = (uint)WrittenFileSize; - - const uint FileSize = 0x1000000; - var CmpByte2 = Flt.Type == FILTER_E8E9 ? (byte)0xe9 : (byte)0xe8; - // DataSize is unsigned, so we use "CurPos+4" and not "DataSize-4" - // to avoid overflow for DataSize<4. - for (uint CurPos = 0; CurPos + 4 < DataSize;) { - //x byte CurByte=*(Data++); - var CurByte = __d[Data++]; - CurPos++; - if (CurByte == 0xe8 || CurByte == CmpByte2) + var FileOffset = (uint)WrittenFileSize; + + const uint FileSize = 0x1000000; + var CmpByte2 = Flt.Type == FILTER_E8E9 ? (byte)0xe9 : (byte)0xe8; + // DataSize is unsigned, so we use "CurPos+4" and not "DataSize-4" + // to avoid overflow for DataSize<4. + for (uint CurPos = 0; CurPos + 4 < DataSize; ) { - var Offset = (CurPos + FileOffset) % FileSize; - var Addr = RawGet4(__d, Data); - - // We check 0x80000000 bit instead of '< 0' comparison - // not assuming int32 presence or uint size and endianness. - if ((Addr & 0x80000000) != 0) // Addr<0 + //x byte CurByte=*(Data++); + var CurByte = __d[Data++]; + CurPos++; + if (CurByte == 0xe8 || CurByte == CmpByte2) { - if (((Addr + Offset) & 0x80000000) == 0) // Addr+Offset>=0 + var Offset = (CurPos + FileOffset) % FileSize; + var Addr = RawGet4(__d, Data); + + // We check 0x80000000 bit instead of '< 0' comparison + // not assuming int32 presence or uint size and endianness. + if ((Addr & 0x80000000) != 0) // Addr<0 { - RawPut4(Addr + FileSize, __d, Data); + if (((Addr + Offset) & 0x80000000) == 0) // Addr+Offset>=0 + { + RawPut4(Addr + FileSize, __d, Data); + } + } + else if (((Addr - FileSize) & 0x80000000) != 0) // Addr> 8); - __d[D + 2] = (byte)(Offset >> 16); + var D = Data + CurPos; + if (__d[D + 3] == 0xeb) // BL command with '1110' (Always) condition. + { + var Offset = + __d[D] + + ((uint)(__d[D + 1]) * 0x100) + + ((uint)(__d[D + 2]) * 0x10000); + Offset -= (FileOffset + CurPos) / 4; + __d[D] = (byte)Offset; + __d[D + 1] = (byte)(Offset >> 8); + __d[D + 2] = (byte)(Offset >> 16); + } } } - } - return SrcData; + return SrcData; case FILTER_DELTA: { // Unlike RAR3, we do not need to reject excessive channel @@ -727,9 +720,7 @@ internal partial class Unpack } Header.BlockSize = BlockSize; - var CheckSum = (byte)( - 0x5a ^ BlockFlags ^ BlockSize ^ (BlockSize >> 8) ^ (BlockSize >> 16) - ); + var CheckSum = (byte)(0x5a ^ BlockFlags ^ BlockSize ^ (BlockSize >> 8) ^ (BlockSize >> 16)); if (CheckSum != SavedCheckSum) { return false; @@ -796,7 +787,7 @@ internal partial class Unpack var Table = new byte[HUFF_TABLE_SIZE]; const uint TableSize = HUFF_TABLE_SIZE; - for (uint I = 0; I < TableSize;) + for (uint I = 0; I < TableSize; ) { if (!Inp.ExternalBuffer && Inp.InAddr > ReadTop - 5) { diff --git a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack_cpp.cs b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack_cpp.cs index 69b35200..f9a74440 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack_cpp.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack_cpp.cs @@ -372,9 +372,7 @@ internal sealed partial class Unpack : BitInput // Find the upper limit for current bit field and adjust the bit length // accordingly if necessary. - while ( - CurBitLength < Dec.DecodeLen.Length && BitField >= Dec.DecodeLen[CurBitLength] - ) + while (CurBitLength < Dec.DecodeLen.Length && BitField >= Dec.DecodeLen[CurBitLength]) { CurBitLength++; } diff --git a/src/SharpCompress/Compressors/Rar/VM/RarVM.cs b/src/SharpCompress/Compressors/Rar/VM/RarVM.cs index 612f56ff..07d406cb 100644 --- a/src/SharpCompress/Compressors/Rar/VM/RarVM.cs +++ b/src/SharpCompress/Compressors/Rar/VM/RarVM.cs @@ -143,8 +143,7 @@ internal sealed class RarVM : BitInput Mem[VM_GLOBALMEMADDR + i] = prg.GlobalData[i]; } } - var staticSize = - Math.Min(prg.StaticData.Count, VM_GLOBALMEMSIZE - globalSize) & 0xffFFffFF; + var staticSize = Math.Min(prg.StaticData.Count, VM_GLOBALMEMSIZE - globalSize) & 0xffFFffFF; if (staticSize != 0) { for (var i = 0; i < staticSize; i++) @@ -157,8 +156,7 @@ internal sealed class RarVM : BitInput flags = 0; //UPGRADE_NOTE: There is an untranslated Statement. Please refer to original code. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1153'" - var preparedCode = - prg.AltCommands.Count != 0 ? prg.AltCommands : prg.Commands; + var preparedCode = prg.AltCommands.Count != 0 ? prg.AltCommands : prg.Commands; if (!ExecuteCode(preparedCode, prg.CommandCount)) { @@ -239,104 +237,100 @@ internal sealed class RarVM : BitInput case VMCommands.VM_CMP: - { - var value1 = (VMFlags)GetValue(cmd.IsByteMode, Mem, op1); - var result = value1 - GetValue(cmd.IsByteMode, Mem, op2); + { + var value1 = (VMFlags)GetValue(cmd.IsByteMode, Mem, op1); + var result = value1 - GetValue(cmd.IsByteMode, Mem, op2); - if (result == 0) - { - flags = VMFlags.VM_FZ; + if (result == 0) + { + flags = VMFlags.VM_FZ; + } + else + { + flags = (VMFlags)( + (result > value1) ? 1 : 0 | (int)(result & VMFlags.VM_FS) + ); + } } - else - { - flags = (VMFlags)( - (result > value1) ? 1 : 0 | (int)(result & VMFlags.VM_FS) - ); - } - } - break; + break; case VMCommands.VM_CMPB: - { - var value1 = (VMFlags)GetValue(true, Mem, op1); - var result = value1 - GetValue(true, Mem, op2); - if (result == 0) { - flags = VMFlags.VM_FZ; + var value1 = (VMFlags)GetValue(true, Mem, op1); + var result = value1 - GetValue(true, Mem, op2); + if (result == 0) + { + flags = VMFlags.VM_FZ; + } + else + { + flags = (VMFlags)( + (result > value1) ? 1 : 0 | (int)(result & VMFlags.VM_FS) + ); + } } - else - { - flags = (VMFlags)( - (result > value1) ? 1 : 0 | (int)(result & VMFlags.VM_FS) - ); - } - } - break; + break; case VMCommands.VM_CMPD: - { - var value1 = (VMFlags)GetValue(false, Mem, op1); - var result = value1 - GetValue(false, Mem, op2); - if (result == 0) { - flags = VMFlags.VM_FZ; + var value1 = (VMFlags)GetValue(false, Mem, op1); + var result = value1 - GetValue(false, Mem, op2); + if (result == 0) + { + flags = VMFlags.VM_FZ; + } + else + { + flags = (VMFlags)( + (result > value1) ? 1 : 0 | (int)(result & VMFlags.VM_FS) + ); + } } - else - { - flags = (VMFlags)( - (result > value1) ? 1 : 0 | (int)(result & VMFlags.VM_FS) - ); - } - } - break; + break; case VMCommands.VM_ADD: - { - var value1 = GetValue(cmd.IsByteMode, Mem, op1); - var result = (int)( - ((value1 + (long)GetValue(cmd.IsByteMode, Mem, op2))) - & unchecked((int)0xffffffff) - ); - if (cmd.IsByteMode) { - result &= 0xff; - flags = (VMFlags)( - (result < value1) - ? 1 - : 0 - | ( - result == 0 - ? (int)VMFlags.VM_FZ - : ( - ((result & 0x80) != 0) - ? (int)VMFlags.VM_FS - : 0 - ) - ) + var value1 = GetValue(cmd.IsByteMode, Mem, op1); + var result = (int)( + ((value1 + (long)GetValue(cmd.IsByteMode, Mem, op2))) + & unchecked((int)0xffffffff) ); + if (cmd.IsByteMode) + { + result &= 0xff; + flags = (VMFlags)( + (result < value1) + ? 1 + : 0 + | ( + result == 0 + ? (int)VMFlags.VM_FZ + : (((result & 0x80) != 0) ? (int)VMFlags.VM_FS : 0) + ) + ); - // Flags=(Result value1) ? 1 : 0 | (result & (int)VMFlags.VM_FS)) - ); - SetValue(cmd.IsByteMode, Mem, op1, result); // (Cmd->ByteMode,Op1,Result); - } - break; + { + var value1 = GetValue(cmd.IsByteMode, Mem, op1); + var result = (int)( + value1 + & (0xffFFffFF - GetValue(cmd.IsByteMode, Mem, op2)) + & unchecked((int)0xFFffFFff) + ); + flags = (VMFlags)( + (result == 0) + ? (int)VMFlags.VM_FZ + : ((result > value1) ? 1 : 0 | (result & (int)VMFlags.VM_FS)) + ); + SetValue(cmd.IsByteMode, Mem, op1, result); // (Cmd->ByteMode,Op1,Result); + } + break; case VMCommands.VM_SUBB: SetValue( @@ -426,29 +420,22 @@ internal sealed class RarVM : BitInput case VMCommands.VM_INC: - { - var result = (int)( - GetValue(cmd.IsByteMode, Mem, op1) & (0xFFffFFffL + 1L) - ); - if (cmd.IsByteMode) { - result &= 0xff; - } + var result = (int)(GetValue(cmd.IsByteMode, Mem, op1) & (0xFFffFFffL + 1L)); + if (cmd.IsByteMode) + { + result &= 0xff; + } - SetValue(cmd.IsByteMode, Mem, op1, result); - flags = (VMFlags)( - result == 0 ? (int)VMFlags.VM_FZ : result & (int)VMFlags.VM_FS - ); - } - break; + SetValue(cmd.IsByteMode, Mem, op1, result); + flags = (VMFlags)( + result == 0 ? (int)VMFlags.VM_FZ : result & (int)VMFlags.VM_FS + ); + } + break; case VMCommands.VM_INCB: - SetValue( - true, - Mem, - op1, - (int)(GetValue(true, Mem, op1) & (0xFFffFFffL + 1L)) - ); + SetValue(true, Mem, op1, (int)(GetValue(true, Mem, op1) & (0xFFffFFffL + 1L))); break; case VMCommands.VM_INCD: @@ -462,26 +449,21 @@ internal sealed class RarVM : BitInput case VMCommands.VM_DEC: - { - var result = (int)(GetValue(cmd.IsByteMode, Mem, op1) & (0xFFffFFff - 1)); - SetValue(cmd.IsByteMode, Mem, op1, result); - flags = (VMFlags)( - result == 0 ? (int)VMFlags.VM_FZ : result & (int)VMFlags.VM_FS - ); - } - break; + { + var result = (int)(GetValue(cmd.IsByteMode, Mem, op1) & (0xFFffFFff - 1)); + SetValue(cmd.IsByteMode, Mem, op1, result); + flags = (VMFlags)( + result == 0 ? (int)VMFlags.VM_FZ : result & (int)VMFlags.VM_FS + ); + } + break; case VMCommands.VM_DECB: SetValue(true, Mem, op1, (int)(GetValue(true, Mem, op1) & (0xFFffFFff - 1))); break; case VMCommands.VM_DECD: - SetValue( - false, - Mem, - op1, - (int)(GetValue(false, Mem, op1) & (0xFFffFFff - 1)) - ); + SetValue(false, Mem, op1, (int)(GetValue(false, Mem, op1) & (0xFFffFFff - 1))); break; case VMCommands.VM_JMP: @@ -490,54 +472,50 @@ internal sealed class RarVM : BitInput case VMCommands.VM_XOR: - { - var result = - GetValue(cmd.IsByteMode, Mem, op1) - ^ GetValue(cmd.IsByteMode, Mem, op2); - flags = (VMFlags)( - result == 0 ? (int)VMFlags.VM_FZ : result & (int)VMFlags.VM_FS - ); - SetValue(cmd.IsByteMode, Mem, op1, result); - } - break; + { + var result = + GetValue(cmd.IsByteMode, Mem, op1) ^ GetValue(cmd.IsByteMode, Mem, op2); + flags = (VMFlags)( + result == 0 ? (int)VMFlags.VM_FZ : result & (int)VMFlags.VM_FS + ); + SetValue(cmd.IsByteMode, Mem, op1, result); + } + break; case VMCommands.VM_AND: - { - var result = - GetValue(cmd.IsByteMode, Mem, op1) - & GetValue(cmd.IsByteMode, Mem, op2); - flags = (VMFlags)( - result == 0 ? (int)VMFlags.VM_FZ : result & (int)VMFlags.VM_FS - ); - SetValue(cmd.IsByteMode, Mem, op1, result); - } - break; + { + var result = + GetValue(cmd.IsByteMode, Mem, op1) & GetValue(cmd.IsByteMode, Mem, op2); + flags = (VMFlags)( + result == 0 ? (int)VMFlags.VM_FZ : result & (int)VMFlags.VM_FS + ); + SetValue(cmd.IsByteMode, Mem, op1, result); + } + break; case VMCommands.VM_OR: - { - var result = - GetValue(cmd.IsByteMode, Mem, op1) - | GetValue(cmd.IsByteMode, Mem, op2); - flags = (VMFlags)( - result == 0 ? (int)VMFlags.VM_FZ : result & (int)VMFlags.VM_FS - ); - SetValue(cmd.IsByteMode, Mem, op1, result); - } - break; + { + var result = + GetValue(cmd.IsByteMode, Mem, op1) | GetValue(cmd.IsByteMode, Mem, op2); + flags = (VMFlags)( + result == 0 ? (int)VMFlags.VM_FZ : result & (int)VMFlags.VM_FS + ); + SetValue(cmd.IsByteMode, Mem, op1, result); + } + break; case VMCommands.VM_TEST: - { - var result = - GetValue(cmd.IsByteMode, Mem, op1) - & GetValue(cmd.IsByteMode, Mem, op2); - flags = (VMFlags)( - result == 0 ? (int)VMFlags.VM_FZ : result & (int)VMFlags.VM_FS - ); - } - break; + { + var result = + GetValue(cmd.IsByteMode, Mem, op1) & GetValue(cmd.IsByteMode, Mem, op2); + flags = (VMFlags)( + result == 0 ? (int)VMFlags.VM_FZ : result & (int)VMFlags.VM_FS + ); + } + break; case VMCommands.VM_JS: if ((flags & VMFlags.VM_FS) != 0) @@ -609,62 +587,62 @@ internal sealed class RarVM : BitInput case VMCommands.VM_SHL: - { - var value1 = GetValue(cmd.IsByteMode, Mem, op1); - var value2 = GetValue(cmd.IsByteMode, Mem, op2); - var result = value1 << value2; - flags = (VMFlags)( - (result == 0 ? (int)VMFlags.VM_FZ : (result & (int)VMFlags.VM_FS)) - | ( - ((value1 << (value2 - 1)) & unchecked((int)0x80000000)) != 0 - ? (int)VMFlags.VM_FC - : 0 - ) - ); - SetValue(cmd.IsByteMode, Mem, op1, result); - } - break; + { + var value1 = GetValue(cmd.IsByteMode, Mem, op1); + var value2 = GetValue(cmd.IsByteMode, Mem, op2); + var result = value1 << value2; + flags = (VMFlags)( + (result == 0 ? (int)VMFlags.VM_FZ : (result & (int)VMFlags.VM_FS)) + | ( + ((value1 << (value2 - 1)) & unchecked((int)0x80000000)) != 0 + ? (int)VMFlags.VM_FC + : 0 + ) + ); + SetValue(cmd.IsByteMode, Mem, op1, result); + } + break; case VMCommands.VM_SHR: - { - var value1 = GetValue(cmd.IsByteMode, Mem, op1); - var value2 = GetValue(cmd.IsByteMode, Mem, op2); - var result = Utility.URShift(value1, value2); - flags = (VMFlags)( - (result == 0 ? (int)VMFlags.VM_FZ : (result & (int)VMFlags.VM_FS)) - | ((Utility.URShift(value1, (value2 - 1))) & (int)VMFlags.VM_FC) - ); - SetValue(cmd.IsByteMode, Mem, op1, result); - } - break; + { + var value1 = GetValue(cmd.IsByteMode, Mem, op1); + var value2 = GetValue(cmd.IsByteMode, Mem, op2); + var result = Utility.URShift(value1, value2); + flags = (VMFlags)( + (result == 0 ? (int)VMFlags.VM_FZ : (result & (int)VMFlags.VM_FS)) + | ((Utility.URShift(value1, (value2 - 1))) & (int)VMFlags.VM_FC) + ); + SetValue(cmd.IsByteMode, Mem, op1, result); + } + break; case VMCommands.VM_SAR: - { - var value1 = GetValue(cmd.IsByteMode, Mem, op1); - var value2 = GetValue(cmd.IsByteMode, Mem, op2); - var result = value1 >> value2; - flags = (VMFlags)( - (result == 0 ? (int)VMFlags.VM_FZ : (result & (int)VMFlags.VM_FS)) - | ((value1 >> (value2 - 1)) & (int)VMFlags.VM_FC) - ); - SetValue(cmd.IsByteMode, Mem, op1, result); - } - break; + { + var value1 = GetValue(cmd.IsByteMode, Mem, op1); + var value2 = GetValue(cmd.IsByteMode, Mem, op2); + var result = value1 >> value2; + flags = (VMFlags)( + (result == 0 ? (int)VMFlags.VM_FZ : (result & (int)VMFlags.VM_FS)) + | ((value1 >> (value2 - 1)) & (int)VMFlags.VM_FC) + ); + SetValue(cmd.IsByteMode, Mem, op1, result); + } + break; case VMCommands.VM_NEG: - { - var result = -GetValue(cmd.IsByteMode, Mem, op1); - flags = (VMFlags)( - result == 0 - ? (int)VMFlags.VM_FZ - : (int)VMFlags.VM_FC | (result & (int)VMFlags.VM_FS) - ); - SetValue(cmd.IsByteMode, Mem, op1, result); - } - break; + { + var result = -GetValue(cmd.IsByteMode, Mem, op1); + flags = (VMFlags)( + result == 0 + ? (int)VMFlags.VM_FZ + : (int)VMFlags.VM_FC | (result & (int)VMFlags.VM_FS) + ); + SetValue(cmd.IsByteMode, Mem, op1, result); + } + break; case VMCommands.VM_NEGB: SetValue(true, Mem, op1, -GetValue(true, Mem, op1)); @@ -676,24 +654,24 @@ internal sealed class RarVM : BitInput case VMCommands.VM_PUSHA: - { - for (int i = 0, SP = R[7] - 4; i < regCount; i++, SP -= 4) { - SetValue(false, Mem, SP & VM_MEMMASK, R[i]); + for (int i = 0, SP = R[7] - 4; i < regCount; i++, SP -= 4) + { + SetValue(false, Mem, SP & VM_MEMMASK, R[i]); + } + R[7] -= regCount * 4; } - R[7] -= regCount * 4; - } - break; + break; case VMCommands.VM_POPA: - { - for (int i = 0, SP = R[7]; i < regCount; i++, SP += 4) { - R[7 - i] = GetValue(false, Mem, SP & VM_MEMMASK); + for (int i = 0, SP = R[7]; i < regCount; i++, SP += 4) + { + R[7 - i] = GetValue(false, Mem, SP & VM_MEMMASK); + } } - } - break; + break; case VMCommands.VM_PUSHF: R[7] -= 4; @@ -715,97 +693,97 @@ internal sealed class RarVM : BitInput case VMCommands.VM_XCHG: - { - var value1 = GetValue(cmd.IsByteMode, Mem, op1); - SetValue(cmd.IsByteMode, Mem, op1, GetValue(cmd.IsByteMode, Mem, op2)); - SetValue(cmd.IsByteMode, Mem, op2, value1); - } - break; + { + var value1 = GetValue(cmd.IsByteMode, Mem, op1); + SetValue(cmd.IsByteMode, Mem, op1, GetValue(cmd.IsByteMode, Mem, op2)); + SetValue(cmd.IsByteMode, Mem, op2, value1); + } + break; case VMCommands.VM_MUL: - { - var result = (int)( - ( - GetValue(cmd.IsByteMode, Mem, op1) - & (0xFFffFFff * GetValue(cmd.IsByteMode, Mem, op2)) - & unchecked((int)0xFFffFFff) - ) & unchecked((int)0xFFffFFff) - ); - SetValue(cmd.IsByteMode, Mem, op1, result); - } - break; + { + var result = (int)( + ( + GetValue(cmd.IsByteMode, Mem, op1) + & (0xFFffFFff * GetValue(cmd.IsByteMode, Mem, op2)) + & unchecked((int)0xFFffFFff) + ) & unchecked((int)0xFFffFFff) + ); + SetValue(cmd.IsByteMode, Mem, op1, result); + } + break; case VMCommands.VM_DIV: - { - var divider = GetValue(cmd.IsByteMode, Mem, op2); - if (divider != 0) { - var result = GetValue(cmd.IsByteMode, Mem, op1) / divider; - SetValue(cmd.IsByteMode, Mem, op1, result); + var divider = GetValue(cmd.IsByteMode, Mem, op2); + if (divider != 0) + { + var result = GetValue(cmd.IsByteMode, Mem, op1) / divider; + SetValue(cmd.IsByteMode, Mem, op1, result); + } } - } - break; + break; case VMCommands.VM_ADC: - { - var value1 = GetValue(cmd.IsByteMode, Mem, op1); - var FC = (int)(flags & VMFlags.VM_FC); - var result = (int)( - value1 - & (0xFFffFFff + GetValue(cmd.IsByteMode, Mem, op2)) - & (0xFFffFFff + FC) - & unchecked((int)0xFFffFFff) - ); - if (cmd.IsByteMode) { - result &= 0xff; - } + var value1 = GetValue(cmd.IsByteMode, Mem, op1); + var FC = (int)(flags & VMFlags.VM_FC); + var result = (int)( + value1 + & (0xFFffFFff + GetValue(cmd.IsByteMode, Mem, op2)) + & (0xFFffFFff + FC) + & unchecked((int)0xFFffFFff) + ); + if (cmd.IsByteMode) + { + result &= 0xff; + } - flags = (VMFlags)( - (result < value1 || result == value1 && FC != 0) - ? 1 - : 0 - | ( - result == 0 - ? (int)VMFlags.VM_FZ - : (result & (int)VMFlags.VM_FS) - ) - ); - SetValue(cmd.IsByteMode, Mem, op1, result); - } - break; + flags = (VMFlags)( + (result < value1 || result == value1 && FC != 0) + ? 1 + : 0 + | ( + result == 0 + ? (int)VMFlags.VM_FZ + : (result & (int)VMFlags.VM_FS) + ) + ); + SetValue(cmd.IsByteMode, Mem, op1, result); + } + break; case VMCommands.VM_SBB: - { - var value1 = GetValue(cmd.IsByteMode, Mem, op1); - var FC = (int)(flags & VMFlags.VM_FC); - var result = (int)( - value1 - & (0xFFffFFff - GetValue(cmd.IsByteMode, Mem, op2)) - & (0xFFffFFff - FC) - & unchecked((int)0xFFffFFff) - ); - if (cmd.IsByteMode) { - result &= 0xff; + var value1 = GetValue(cmd.IsByteMode, Mem, op1); + var FC = (int)(flags & VMFlags.VM_FC); + var result = (int)( + value1 + & (0xFFffFFff - GetValue(cmd.IsByteMode, Mem, op2)) + & (0xFFffFFff - FC) + & unchecked((int)0xFFffFFff) + ); + if (cmd.IsByteMode) + { + result &= 0xff; + } + flags = (VMFlags)( + (result > value1 || result == value1 && FC != 0) + ? 1 + : 0 + | ( + result == 0 + ? (int)VMFlags.VM_FZ + : (result & (int)VMFlags.VM_FS) + ) + ); + SetValue(cmd.IsByteMode, Mem, op1, result); } - flags = (VMFlags)( - (result > value1 || result == value1 && FC != 0) - ? 1 - : 0 - | ( - result == 0 - ? (int)VMFlags.VM_FZ - : (result & (int)VMFlags.VM_FS) - ) - ); - SetValue(cmd.IsByteMode, Mem, op1, result); - } - break; + break; case VMCommands.VM_RET: if (R[7] >= VM_MEMSIZE) @@ -898,9 +876,7 @@ internal sealed class RarVM : BitInput curCmd.OpCode = (VMCommands)((data >> 10) - 24); AddBits(6); } - if ( - (VMCmdFlags.VM_CmdFlags[(int)curCmd.OpCode] & VMCmdFlags.VMCF_BYTEMODE) != 0 - ) + if ((VMCmdFlags.VM_CmdFlags[(int)curCmd.OpCode] & VMCmdFlags.VMCF_BYTEMODE) != 0) { curCmd.IsByteMode = (GetBits() >> 15) == 1; AddBits(1); @@ -912,9 +888,7 @@ internal sealed class RarVM : BitInput curCmd.Op1.Type = VMOpType.VM_OPNONE; curCmd.Op2.Type = VMOpType.VM_OPNONE; - var opNum = ( - VMCmdFlags.VM_CmdFlags[(int)curCmd.OpCode] & VMCmdFlags.VMCF_OPMASK - ); + var opNum = (VMCmdFlags.VM_CmdFlags[(int)curCmd.OpCode] & VMCmdFlags.VMCF_OPMASK); // TODO >>> CurCmd->Op1.Addr=CurCmd->Op2.Addr=NULL; << 0) @@ -1082,11 +1056,7 @@ internal sealed class RarVM : BitInput if ( ( flags - & ( - VMCmdFlags.VMCF_JUMP - | VMCmdFlags.VMCF_PROC - | VMCmdFlags.VMCF_USEFLAGS - ) + & (VMCmdFlags.VMCF_JUMP | VMCmdFlags.VMCF_PROC | VMCmdFlags.VMCF_USEFLAGS) ) != 0 ) { @@ -1195,368 +1165,368 @@ internal sealed class RarVM : BitInput case VMStandardFilters.VMSF_E8: case VMStandardFilters.VMSF_E8E9: - { - var dataSize = R[4]; - long fileOffset = R[6] & unchecked((int)0xFFffFFff); + { + var dataSize = R[4]; + long fileOffset = R[6] & unchecked((int)0xFFffFFff); - if (dataSize >= VM_GLOBALMEMADDR) - { - break; - } - var fileSize = 0x1000000; - var cmpByte2 = (byte)( - (filterType == VMStandardFilters.VMSF_E8E9) ? 0xe9 : 0xe8 - ); - for (var curPos = 0; curPos < dataSize - 4;) - { - var curByte = Mem[curPos++]; - if (curByte == 0xe8 || curByte == cmpByte2) + if (dataSize >= VM_GLOBALMEMADDR) { - // #ifdef PRESENT_INT32 - // sint32 Offset=CurPos+FileOffset; - // sint32 Addr=GET_VALUE(false,Data); - // if (Addr<0) - // { - // if (Addr+Offset>=0) - // SET_VALUE(false,Data,Addr+FileSize); - // } - // else - // if (Addr= VM_GLOBALMEMADDR) - { - break; - } - var curPos = 0; - - //UPGRADE_NOTE: Final was removed from the declaration of 'Masks '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - byte[] Masks = { 4, 4, 6, 6, 0, 0, 7, 7, 4, 4, 0, 0, 4, 4, 0, 0 }; - fileOffset = Utility.URShift(fileOffset, 4); - - while (curPos < dataSize - 21) - { - var Byte = (Mem[curPos] & 0x1f) - 0x10; - if (Byte >= 0) + var fileSize = 0x1000000; + var cmpByte2 = (byte)( + (filterType == VMStandardFilters.VMSF_E8E9) ? 0xe9 : 0xe8 + ); + for (var curPos = 0; curPos < dataSize - 4; ) { - var cmdMask = Masks[Byte]; - if (cmdMask != 0) + var curByte = Mem[curPos++]; + if (curByte == 0xe8 || curByte == cmpByte2) { - for (var i = 0; i <= 2; i++) + // #ifdef PRESENT_INT32 + // sint32 Offset=CurPos+FileOffset; + // sint32 Addr=GET_VALUE(false,Data); + // if (Addr<0) + // { + // if (Addr+Offset>=0) + // SET_VALUE(false,Data,Addr+FileSize); + // } + // else + // if (Addr= VM_GLOBALMEMADDR / 2) - { - break; - } - - // bytes from same channels are grouped to continual data blocks, - // so we need to place them back to their interleaving positions - - for (var curChannel = 0; curChannel < channels; curChannel++) - { - byte PrevByte = 0; - for ( - var destPos = dataSize + curChannel; - destPos < border; - destPos += channels - ) - { - Mem[destPos] = (PrevByte = (byte)(PrevByte - Mem[srcPos++])); - } - } - } - break; - - case VMStandardFilters.VMSF_RGB: - - { - // byte *SrcData=Mem,*DestData=SrcData+DataSize; - int dataSize = R[4], - width = R[0] - 3, - posR = R[1]; - var channels = 3; - var srcPos = 0; - var destDataPos = dataSize; - SetValue(false, Mem, VM_GLOBALMEMADDR + 0x20, dataSize); - if (dataSize >= VM_GLOBALMEMADDR / 2 || posR < 0) - { - break; - } - for (var curChannel = 0; curChannel < channels; curChannel++) - { - long prevByte = 0; - - for (var i = curChannel; i < dataSize; i += channels) - { - long predicted; - var upperPos = i - width; - if (upperPos >= 3) - { - var upperDataPos = destDataPos + upperPos; - var upperByte = Mem[upperDataPos] & 0xff; - var upperLeftByte = Mem[upperDataPos - 3] & 0xff; - predicted = prevByte + upperByte - upperLeftByte; - var pa = Math.Abs((int)(predicted - prevByte)); - var pb = Math.Abs((int)(predicted - upperByte)); - var pc = Math.Abs((int)(predicted - upperLeftByte)); - if (pa <= pb && pa <= pc) - { - predicted = prevByte; - } else { - if (pb <= pc) + if (((Addr - fileSize) & unchecked((int)0x80000000)) != 0) { - predicted = upperByte; + SetValue(false, Mem, curPos, (int)(Addr - offset)); + } + } + + // #endif + curPos += 4; + } + } + } + break; + + case VMStandardFilters.VMSF_ITANIUM: + + { + var dataSize = R[4]; + long fileOffset = R[6] & unchecked((int)0xFFffFFff); + + if (dataSize >= VM_GLOBALMEMADDR) + { + break; + } + var curPos = 0; + + //UPGRADE_NOTE: Final was removed from the declaration of 'Masks '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + byte[] Masks = { 4, 4, 6, 6, 0, 0, 7, 7, 4, 4, 0, 0, 4, 4, 0, 0 }; + fileOffset = Utility.URShift(fileOffset, 4); + + while (curPos < dataSize - 21) + { + var Byte = (Mem[curPos] & 0x1f) - 0x10; + if (Byte >= 0) + { + var cmdMask = Masks[Byte]; + if (cmdMask != 0) + { + for (var i = 0; i <= 2; i++) + { + if ((cmdMask & (1 << i)) != 0) + { + var startPos = (i * 41) + 5; + var opType = filterItanium_GetBits( + curPos, + startPos + 37, + 4 + ); + if (opType == 5) + { + var offset = filterItanium_GetBits( + curPos, + startPos + 13, + 20 + ); + filterItanium_SetBits( + curPos, + (int)(offset - fileOffset) & 0xfffff, + startPos + 13, + 20 + ); + } + } + } + } + } + curPos += 16; + fileOffset++; + } + } + break; + + case VMStandardFilters.VMSF_DELTA: + + { + var dataSize = R[4] & unchecked((int)0xFFffFFff); + var channels = R[0] & unchecked((int)0xFFffFFff); + var srcPos = 0; + var border = (dataSize * 2) & unchecked((int)0xFFffFFff); + SetValue(false, Mem, VM_GLOBALMEMADDR + 0x20, dataSize); + if (dataSize >= VM_GLOBALMEMADDR / 2) + { + break; + } + + // bytes from same channels are grouped to continual data blocks, + // so we need to place them back to their interleaving positions + + for (var curChannel = 0; curChannel < channels; curChannel++) + { + byte PrevByte = 0; + for ( + var destPos = dataSize + curChannel; + destPos < border; + destPos += channels + ) + { + Mem[destPos] = (PrevByte = (byte)(PrevByte - Mem[srcPos++])); + } + } + } + break; + + case VMStandardFilters.VMSF_RGB: + + { + // byte *SrcData=Mem,*DestData=SrcData+DataSize; + int dataSize = R[4], + width = R[0] - 3, + posR = R[1]; + var channels = 3; + var srcPos = 0; + var destDataPos = dataSize; + SetValue(false, Mem, VM_GLOBALMEMADDR + 0x20, dataSize); + if (dataSize >= VM_GLOBALMEMADDR / 2 || posR < 0) + { + break; + } + for (var curChannel = 0; curChannel < channels; curChannel++) + { + long prevByte = 0; + + for (var i = curChannel; i < dataSize; i += channels) + { + long predicted; + var upperPos = i - width; + if (upperPos >= 3) + { + var upperDataPos = destDataPos + upperPos; + var upperByte = Mem[upperDataPos] & 0xff; + var upperLeftByte = Mem[upperDataPos - 3] & 0xff; + predicted = prevByte + upperByte - upperLeftByte; + var pa = Math.Abs((int)(predicted - prevByte)); + var pb = Math.Abs((int)(predicted - upperByte)); + var pc = Math.Abs((int)(predicted - upperLeftByte)); + if (pa <= pb && pa <= pc) + { + predicted = prevByte; } else { - predicted = upperLeftByte; + if (pb <= pc) + { + predicted = upperByte; + } + else + { + predicted = upperLeftByte; + } } } - } - else - { - predicted = prevByte; - } + else + { + predicted = prevByte; + } - prevByte = ((predicted - Mem[srcPos++]) & 0xff) & 0xff; - Mem[destDataPos + i] = (byte)(prevByte & 0xff); + prevByte = ((predicted - Mem[srcPos++]) & 0xff) & 0xff; + Mem[destDataPos + i] = (byte)(prevByte & 0xff); + } + } + for (int i = posR, border = dataSize - 2; i < border; i += 3) + { + var G = Mem[destDataPos + i + 1]; + Mem[destDataPos + i] = (byte)(Mem[destDataPos + i] + G); + Mem[destDataPos + i + 2] = (byte)(Mem[destDataPos + i + 2] + G); } } - for (int i = posR, border = dataSize - 2; i < border; i += 3) - { - var G = Mem[destDataPos + i + 1]; - Mem[destDataPos + i] = (byte)(Mem[destDataPos + i] + G); - Mem[destDataPos + i + 2] = (byte)(Mem[destDataPos + i + 2] + G); - } - } - break; + break; case VMStandardFilters.VMSF_AUDIO: - { - int dataSize = R[4], - channels = R[0]; - var srcPos = 0; - var destDataPos = dataSize; - - //byte *SrcData=Mem,*DestData=SrcData+DataSize; - SetValue(false, Mem, VM_GLOBALMEMADDR + 0x20, dataSize); - if (dataSize >= VM_GLOBALMEMADDR / 2) { - break; - } - for (var curChannel = 0; curChannel < channels; curChannel++) - { - long prevByte = 0; - long prevDelta = 0; - var Dif = new long[7]; - int D1 = 0, - D2 = 0, - D3; - int K1 = 0, - K2 = 0, - K3 = 0; + int dataSize = R[4], + channels = R[0]; + var srcPos = 0; + var destDataPos = dataSize; - for ( - int i = curChannel, byteCount = 0; - i < dataSize; - i += channels, byteCount++ - ) + //byte *SrcData=Mem,*DestData=SrcData+DataSize; + SetValue(false, Mem, VM_GLOBALMEMADDR + 0x20, dataSize); + if (dataSize >= VM_GLOBALMEMADDR / 2) { - D3 = D2; - D2 = (int)(prevDelta - D1); - D1 = (int)prevDelta; + break; + } + for (var curChannel = 0; curChannel < channels; curChannel++) + { + long prevByte = 0; + long prevDelta = 0; + var Dif = new long[7]; + int D1 = 0, + D2 = 0, + D3; + int K1 = 0, + K2 = 0, + K3 = 0; - var predicted = (8 * prevByte) + (K1 * D1) + (K2 * D2) + (K3 * D3); - predicted = Utility.URShift(predicted, 3) & 0xff; - - long curByte = Mem[srcPos++]; - - predicted -= curByte; - Mem[destDataPos + i] = (byte)predicted; - prevDelta = (byte)(predicted - prevByte); - - //fix java byte - if (prevDelta >= 128) + for ( + int i = curChannel, byteCount = 0; + i < dataSize; + i += channels, byteCount++ + ) { - prevDelta = 0 - (256 - prevDelta); - } - prevByte = predicted; + D3 = D2; + D2 = (int)(prevDelta - D1); + D1 = (int)prevDelta; - //fix java byte - if (curByte >= 128) - { - curByte = 0 - (256 - curByte); - } - var D = ((int)curByte) << 3; + var predicted = (8 * prevByte) + (K1 * D1) + (K2 * D2) + (K3 * D3); + predicted = Utility.URShift(predicted, 3) & 0xff; - Dif[0] += Math.Abs(D); - Dif[1] += Math.Abs(D - D1); - Dif[2] += Math.Abs(D + D1); - Dif[3] += Math.Abs(D - D2); - Dif[4] += Math.Abs(D + D2); - Dif[5] += Math.Abs(D - D3); - Dif[6] += Math.Abs(D + D3); + long curByte = Mem[srcPos++]; - if ((byteCount & 0x1f) == 0) - { - long minDif = Dif[0], - numMinDif = 0; - Dif[0] = 0; - for (var j = 1; j < Dif.Length; j++) + predicted -= curByte; + Mem[destDataPos + i] = (byte)predicted; + prevDelta = (byte)(predicted - prevByte); + + //fix java byte + if (prevDelta >= 128) { - if (Dif[j] < minDif) - { - minDif = Dif[j]; - numMinDif = j; - } - Dif[j] = 0; + prevDelta = 0 - (256 - prevDelta); } - switch ((int)numMinDif) + prevByte = predicted; + + //fix java byte + if (curByte >= 128) { - case 1: - if (K1 >= -16) - { - K1--; - } - break; + curByte = 0 - (256 - curByte); + } + var D = ((int)curByte) << 3; - case 2: - if (K1 < 16) - { - K1++; - } - break; + Dif[0] += Math.Abs(D); + Dif[1] += Math.Abs(D - D1); + Dif[2] += Math.Abs(D + D1); + Dif[3] += Math.Abs(D - D2); + Dif[4] += Math.Abs(D + D2); + Dif[5] += Math.Abs(D - D3); + Dif[6] += Math.Abs(D + D3); - case 3: - if (K2 >= -16) + if ((byteCount & 0x1f) == 0) + { + long minDif = Dif[0], + numMinDif = 0; + Dif[0] = 0; + for (var j = 1; j < Dif.Length; j++) + { + if (Dif[j] < minDif) { - K2--; + minDif = Dif[j]; + numMinDif = j; } - break; + Dif[j] = 0; + } + switch ((int)numMinDif) + { + case 1: + if (K1 >= -16) + { + K1--; + } + break; - case 4: - if (K2 < 16) - { - K2++; - } - break; + case 2: + if (K1 < 16) + { + K1++; + } + break; - case 5: - if (K3 >= -16) - { - K3--; - } - break; + case 3: + if (K2 >= -16) + { + K2--; + } + break; - case 6: - if (K3 < 16) - { - K3++; - } - break; + case 4: + if (K2 < 16) + { + K2++; + } + break; + + case 5: + if (K3 >= -16) + { + K3--; + } + break; + + case 6: + if (K3 < 16) + { + K3++; + } + break; + } } } } } - } - break; + break; case VMStandardFilters.VMSF_UPCASE: - { - int dataSize = R[4], - srcPos = 0, - destPos = dataSize; - if (dataSize >= VM_GLOBALMEMADDR / 2) { - break; - } - while (srcPos < dataSize) - { - var curByte = Mem[srcPos++]; - if (curByte == 2 && (curByte = Mem[srcPos++]) != 2) + int dataSize = R[4], + srcPos = 0, + destPos = dataSize; + if (dataSize >= VM_GLOBALMEMADDR / 2) { - curByte = (byte)(curByte - 32); + break; } - Mem[destPos++] = curByte; + while (srcPos < dataSize) + { + var curByte = Mem[srcPos++]; + if (curByte == 2 && (curByte = Mem[srcPos++]) != 2) + { + curByte = (byte)(curByte - 32); + } + Mem[destPos++] = curByte; + } + SetValue(false, Mem, VM_GLOBALMEMADDR + 0x1c, destPos - dataSize); + SetValue(false, Mem, VM_GLOBALMEMADDR + 0x20, dataSize); } - SetValue(false, Mem, VM_GLOBALMEMADDR + 0x1c, destPos - dataSize); - SetValue(false, Mem, VM_GLOBALMEMADDR + 0x20, dataSize); - } - break; + break; } } diff --git a/src/SharpCompress/Compressors/Xz/Filters/BlockFilter.cs b/src/SharpCompress/Compressors/Xz/Filters/BlockFilter.cs index f141f4f2..ecfe7ae0 100644 --- a/src/SharpCompress/Compressors/Xz/Filters/BlockFilter.cs +++ b/src/SharpCompress/Compressors/Xz/Filters/BlockFilter.cs @@ -45,9 +45,7 @@ public abstract class BlockFilter : ReadOnlyStream var filterType = (FilterTypes)reader.ReadXZInteger(); if (!FilterMap.ContainsKey(filterType)) { - throw new NotImplementedException( - $"Filter {filterType} has not yet been implemented" - ); + throw new NotImplementedException($"Filter {filterType} has not yet been implemented"); } var filter = (BlockFilter)Activator.CreateInstance(FilterMap[filterType])!; diff --git a/src/SharpCompress/Compressors/Xz/XZStream.cs b/src/SharpCompress/Compressors/Xz/XZStream.cs index f1157182..b95b5081 100644 --- a/src/SharpCompress/Compressors/Xz/XZStream.cs +++ b/src/SharpCompress/Compressors/Xz/XZStream.cs @@ -33,9 +33,7 @@ public sealed class XZStream : XZReadOnlyStream case CheckType.SHA256: throw new NotImplementedException(); default: - throw new NotSupportedException( - "Check Type unknown to this version of decoder." - ); + throw new NotSupportedException("Check Type unknown to this version of decoder."); } } diff --git a/src/SharpCompress/Crypto/Crc32Stream.cs b/src/SharpCompress/Crypto/Crc32Stream.cs index 827b1fad..66d9f3c5 100644 --- a/src/SharpCompress/Crypto/Crc32Stream.cs +++ b/src/SharpCompress/Crypto/Crc32Stream.cs @@ -37,8 +37,7 @@ public sealed class Crc32Stream : Stream public override int Read(byte[] buffer, int offset, int count) => throw new NotSupportedException(); - public override long Seek(long offset, SeekOrigin origin) => - throw new NotSupportedException(); + public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException(); public override void SetLength(long value) => throw new NotSupportedException(); diff --git a/src/SharpCompress/Crypto/DataLengthException.cs b/src/SharpCompress/Crypto/DataLengthException.cs index f751adf5..bc6cd183 100644 --- a/src/SharpCompress/Crypto/DataLengthException.cs +++ b/src/SharpCompress/Crypto/DataLengthException.cs @@ -18,6 +18,5 @@ public class DataLengthException : CryptoException public DataLengthException(string message) : base(message) { } - public DataLengthException(string message, Exception exception) : base(message, exception) - { } + public DataLengthException(string message, Exception exception) : base(message, exception) { } } diff --git a/src/SharpCompress/Factories/GZipFactory.cs b/src/SharpCompress/Factories/GZipFactory.cs index e504e577..1c90a88f 100644 --- a/src/SharpCompress/Factories/GZipFactory.cs +++ b/src/SharpCompress/Factories/GZipFactory.cs @@ -126,9 +126,7 @@ public class GZipFactory { if (writerOptions.CompressionType != CompressionType.GZip) { - throw new InvalidFormatException( - "GZip archives only support GZip compression type." - ); + throw new InvalidFormatException("GZip archives only support GZip compression type."); } return new GZipWriter(stream, new GZipWriterOptions(writerOptions)); } diff --git a/src/SharpCompress/IO/ListeningStream.cs b/src/SharpCompress/IO/ListeningStream.cs index 0cccdc6b..4aeb5347 100644 --- a/src/SharpCompress/IO/ListeningStream.cs +++ b/src/SharpCompress/IO/ListeningStream.cs @@ -48,10 +48,7 @@ internal class ListeningStream : Stream { var read = Stream.Read(buffer, offset, count); currentEntryTotalReadBytes += read; - listener.FireCompressedBytesRead( - currentEntryTotalReadBytes, - currentEntryTotalReadBytes - ); + listener.FireCompressedBytesRead(currentEntryTotalReadBytes, currentEntryTotalReadBytes); return read; } @@ -64,10 +61,7 @@ internal class ListeningStream : Stream } ++currentEntryTotalReadBytes; - listener.FireCompressedBytesRead( - currentEntryTotalReadBytes, - currentEntryTotalReadBytes - ); + listener.FireCompressedBytesRead(currentEntryTotalReadBytes, currentEntryTotalReadBytes); return value; } diff --git a/src/SharpCompress/IO/ReadOnlySubStream.cs b/src/SharpCompress/IO/ReadOnlySubStream.cs index acdb6e4a..ce8709d2 100644 --- a/src/SharpCompress/IO/ReadOnlySubStream.cs +++ b/src/SharpCompress/IO/ReadOnlySubStream.cs @@ -5,8 +5,7 @@ namespace SharpCompress.IO; internal class ReadOnlySubStream : NonDisposingStream { - public ReadOnlySubStream(Stream stream, long bytesToRead) : this(stream, null, bytesToRead) - { } + public ReadOnlySubStream(Stream stream, long bytesToRead) : this(stream, null, bytesToRead) { } public ReadOnlySubStream(Stream stream, long? origin, long bytesToRead) : base(stream, throwOnDispose: false) diff --git a/src/SharpCompress/IO/SourceStream.cs b/src/SharpCompress/IO/SourceStream.cs index 5f722b65..d02770c4 100644 --- a/src/SharpCompress/IO/SourceStream.cs +++ b/src/SharpCompress/IO/SourceStream.cs @@ -58,8 +58,7 @@ public class SourceStream : Stream public void LoadAllParts() { - for (var i = 1; SetStream(i); i++) - { } + for (var i = 1; SetStream(i); i++) { } SetStream(0); } diff --git a/src/SharpCompress/Readers/AbstractReader.cs b/src/SharpCompress/Readers/AbstractReader.cs index 5c383cb2..10cebc12 100644 --- a/src/SharpCompress/Readers/AbstractReader.cs +++ b/src/SharpCompress/Readers/AbstractReader.cs @@ -157,9 +157,7 @@ public abstract class AbstractReader : IReader, IReaderExtracti { if (wroteCurrentEntry) { - throw new ArgumentException( - "WriteEntryTo or OpenEntryStream can only be called once." - ); + throw new ArgumentException("WriteEntryTo or OpenEntryStream can only be called once."); } if (writableStream is null) @@ -188,9 +186,7 @@ public abstract class AbstractReader : IReader, IReaderExtracti { if (wroteCurrentEntry) { - throw new ArgumentException( - "WriteEntryTo or OpenEntryStream can only be called once." - ); + throw new ArgumentException("WriteEntryTo or OpenEntryStream can only be called once."); } var stream = GetEntryStream(); wroteCurrentEntry = true; diff --git a/src/SharpCompress/Readers/Rar/NonSeekableStreamFilePart.cs b/src/SharpCompress/Readers/Rar/NonSeekableStreamFilePart.cs index 99db4583..344ca994 100644 --- a/src/SharpCompress/Readers/Rar/NonSeekableStreamFilePart.cs +++ b/src/SharpCompress/Readers/Rar/NonSeekableStreamFilePart.cs @@ -14,6 +14,5 @@ internal class NonSeekableStreamFilePart : RarFilePart return FileHeader.PackedStream; } - internal override string FilePartName => - "Unknown Stream - File Entry: " + FileHeader.FileName; + internal override string FilePartName => "Unknown Stream - File Entry: " + FileHeader.FileName; } diff --git a/src/SharpCompress/Readers/Rar/RarReader.cs b/src/SharpCompress/Readers/Rar/RarReader.cs index b665ddf9..6eb49b2d 100644 --- a/src/SharpCompress/Readers/Rar/RarReader.cs +++ b/src/SharpCompress/Readers/Rar/RarReader.cs @@ -71,9 +71,7 @@ public abstract class RarReader : AbstractReader ); if (Entry.IsRarV3) { - return CreateEntryStream( - new RarCrcStream(UnpackV1.Value, Entry.FileHeader, stream) - ); + return CreateEntryStream(new RarCrcStream(UnpackV1.Value, Entry.FileHeader, stream)); } return CreateEntryStream(new RarCrcStream(UnpackV2017.Value, Entry.FileHeader, stream)); } diff --git a/src/SharpCompress/Readers/ReaderFactory.cs b/src/SharpCompress/Readers/ReaderFactory.cs index 3fcb2dcd..a079c235 100644 --- a/src/SharpCompress/Readers/ReaderFactory.cs +++ b/src/SharpCompress/Readers/ReaderFactory.cs @@ -23,10 +23,7 @@ public static class ReaderFactory foreach (var factory in Factories.Factory.Factories.OfType()) { - if ( - factory.TryOpenReader(rewindableStream, options, out var reader) - && reader != null - ) + if (factory.TryOpenReader(rewindableStream, options, out var reader) && reader != null) { return reader; } diff --git a/src/SharpCompress/Readers/Zip/ZipReader.cs b/src/SharpCompress/Readers/Zip/ZipReader.cs index 2f0e34bb..616e8057 100644 --- a/src/SharpCompress/Readers/Zip/ZipReader.cs +++ b/src/SharpCompress/Readers/Zip/ZipReader.cs @@ -13,10 +13,7 @@ public class ZipReader : AbstractReader private ZipReader(Stream stream, ReaderOptions options) : base(options, ArchiveType.Zip) { Volume = new ZipVolume(stream, options); - _headerFactory = new StreamingZipHeaderFactory( - options.Password, - options.ArchiveEncoding - ); + _headerFactory = new StreamingZipHeaderFactory(options.Password, options.ArchiveEncoding); } public override ZipVolume Volume { get; } @@ -47,12 +44,12 @@ public class ZipReader : AbstractReader { case ZipHeaderType.LocalEntry: - { - yield return new ZipEntry( - new StreamingZipFilePart((LocalEntryHeader)h, stream) - ); - } - break; + { + yield return new ZipEntry( + new StreamingZipFilePart((LocalEntryHeader)h, stream) + ); + } + break; case ZipHeaderType.DirectoryEnd: { yield break; diff --git a/src/SharpCompress/Utility.cs b/src/SharpCompress/Utility.cs index a40da612..99b5d8e9 100644 --- a/src/SharpCompress/Utility.cs +++ b/src/SharpCompress/Utility.cs @@ -166,8 +166,7 @@ public static class Utility var buffer = GetTransferByteArray(); try { - do - { } while (source.Read(buffer, 0, buffer.Length) == buffer.Length); + do { } while (source.Read(buffer, 0, buffer.Length) == buffer.Length); } finally { diff --git a/src/SharpCompress/Writers/Tar/TarWriter.cs b/src/SharpCompress/Writers/Tar/TarWriter.cs index 223e6303..8151c3f3 100644 --- a/src/SharpCompress/Writers/Tar/TarWriter.cs +++ b/src/SharpCompress/Writers/Tar/TarWriter.cs @@ -14,8 +14,7 @@ public class TarWriter : AbstractWriter { private readonly bool finalizeArchiveOnClose; - public TarWriter(Stream destination, TarWriterOptions options) - : base(ArchiveType.Tar, options) + public TarWriter(Stream destination, TarWriterOptions options) : base(ArchiveType.Tar, options) { finalizeArchiveOnClose = options.FinalizeArchiveOnClose; @@ -33,22 +32,22 @@ public class TarWriter : AbstractWriter break; case CompressionType.BZip2: - { - destination = new BZip2Stream(destination, CompressionMode.Compress, false); - } - break; + { + destination = new BZip2Stream(destination, CompressionMode.Compress, false); + } + break; case CompressionType.GZip: - { - destination = new GZipStream(destination, CompressionMode.Compress); - } - break; + { + destination = new GZipStream(destination, CompressionMode.Compress); + } + break; case CompressionType.LZip: - { - destination = new LZipStream(destination, CompressionMode.Compress); - } - break; + { + destination = new LZipStream(destination, CompressionMode.Compress); + } + break; default: { throw new InvalidFormatException( diff --git a/src/SharpCompress/Writers/WriterFactory.cs b/src/SharpCompress/Writers/WriterFactory.cs index fc4f1319..fcbf2d68 100644 --- a/src/SharpCompress/Writers/WriterFactory.cs +++ b/src/SharpCompress/Writers/WriterFactory.cs @@ -8,11 +8,7 @@ namespace SharpCompress.Writers; public static class WriterFactory { - public static IWriter Open( - Stream stream, - ArchiveType archiveType, - WriterOptions writerOptions - ) + public static IWriter Open(Stream stream, ArchiveType archiveType, WriterOptions writerOptions) { var factory = Factories.Factory.Factories .OfType() diff --git a/src/SharpCompress/Writers/Zip/ZipWriter.cs b/src/SharpCompress/Writers/Zip/ZipWriter.cs index afc34800..b5d8a300 100644 --- a/src/SharpCompress/Writers/Zip/ZipWriter.cs +++ b/src/SharpCompress/Writers/Zip/ZipWriter.cs @@ -19,8 +19,7 @@ public class ZipWriter : AbstractWriter { private readonly CompressionType compressionType; private readonly CompressionLevel compressionLevel; - private readonly List entries = - new List(); + private readonly List entries = new List(); private readonly string zipComment; private long streamPosition; private PpmdProperties? ppmdProps; @@ -90,9 +89,7 @@ public class ZipWriter : AbstractWriter return ZipCompressionMethod.PPMd; } default: - throw new InvalidFormatException( - "Invalid compression method: " + compressionType - ); + throw new InvalidFormatException("Invalid compression method: " + compressionType); } } @@ -105,11 +102,7 @@ public class ZipWriter : AbstractWriter ); } - public void Write( - string entryPath, - Stream source, - ZipWriterEntryOptions zipWriterEntryOptions - ) + public void Write(string entryPath, Stream source, ZipWriterEntryOptions zipWriterEntryOptions) { using var output = WriteToStream(entryPath, zipWriterEntryOptions); source.TransferTo(output); @@ -245,9 +238,7 @@ public class ZipWriter : AbstractWriter if (extralength != 0) { OutputStream.Write(new byte[extralength], 0, extralength); // reserve space for zip64 data - entry.Zip64HeaderOffset = (ushort)( - 6 + 2 + 2 + 4 + 12 + 2 + 2 + encodedFilename.Length - ); + entry.Zip64HeaderOffset = (ushort)(6 + 2 + 2 + 4 + 12 + 2 + 2 + encodedFilename.Length); } return 6 + 2 + 2 + 4 + 12 + 2 + 2 + encodedFilename.Length + extralength; @@ -392,11 +383,7 @@ public class ZipWriter : AbstractWriter } case ZipCompressionMethod.Deflate: { - return new DeflateStream( - counting, - CompressionMode.Compress, - compressionLevel - ); + return new DeflateStream(counting, CompressionMode.Compress, compressionLevel); } case ZipCompressionMethod.BZip2: { @@ -424,9 +411,7 @@ public class ZipWriter : AbstractWriter } default: { - throw new NotSupportedException( - "CompressionMethod: " + zipCompressionMethod - ); + throw new NotSupportedException("CompressionMethod: " + zipCompressionMethod); } } } diff --git a/tests/SharpCompress.Test/ADCTest.cs b/tests/SharpCompress.Test/ADCTest.cs index ae131ceb..11bb2fb0 100644 --- a/tests/SharpCompress.Test/ADCTest.cs +++ b/tests/SharpCompress.Test/ADCTest.cs @@ -1,4 +1,4 @@ -// +// // ADC.cs // // Author: @@ -37,15 +37,11 @@ public class ADCTest : TestBase [Fact] public void TestBuffer() { - using var decFs = File.OpenRead( - Path.Combine(TEST_ARCHIVES_PATH, "adc_decompressed.bin") - ); + using var decFs = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "adc_decompressed.bin")); var decompressed = new byte[decFs.Length]; decFs.Read(decompressed, 0, decompressed.Length); - using var cmpFs = File.OpenRead( - Path.Combine(TEST_ARCHIVES_PATH, "adc_compressed.bin") - ); + using var cmpFs = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "adc_compressed.bin")); var compressed = new byte[cmpFs.Length]; cmpFs.Read(compressed, 0, compressed.Length); @@ -57,15 +53,11 @@ public class ADCTest : TestBase [Fact] public void TestBaseStream() { - using var decFs = File.OpenRead( - Path.Combine(TEST_ARCHIVES_PATH, "adc_decompressed.bin") - ); + using var decFs = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "adc_decompressed.bin")); var decompressed = new byte[decFs.Length]; decFs.Read(decompressed, 0, decompressed.Length); - using var cmpFs = File.OpenRead( - Path.Combine(TEST_ARCHIVES_PATH, "adc_compressed.bin") - ); + using var cmpFs = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "adc_compressed.bin")); ADCBase.Decompress(cmpFs, out var test); @@ -75,15 +67,11 @@ public class ADCTest : TestBase [Fact] public void TestADCStreamWholeChunk() { - using var decFs = File.OpenRead( - Path.Combine(TEST_ARCHIVES_PATH, "adc_decompressed.bin") - ); + using var decFs = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "adc_decompressed.bin")); var decompressed = new byte[decFs.Length]; decFs.Read(decompressed, 0, decompressed.Length); - using var cmpFs = File.OpenRead( - Path.Combine(TEST_ARCHIVES_PATH, "adc_compressed.bin") - ); + using var cmpFs = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "adc_compressed.bin")); using var decStream = new ADCStream(cmpFs, CompressionMode.Decompress); var test = new byte[262144]; @@ -95,15 +83,11 @@ public class ADCTest : TestBase [Fact] public void TestADCStream() { - using var decFs = File.OpenRead( - Path.Combine(TEST_ARCHIVES_PATH, "adc_decompressed.bin") - ); + using var decFs = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "adc_decompressed.bin")); var decompressed = new byte[decFs.Length]; decFs.Read(decompressed, 0, decompressed.Length); - using var cmpFs = File.OpenRead( - Path.Combine(TEST_ARCHIVES_PATH, "adc_compressed.bin") - ); + using var cmpFs = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "adc_compressed.bin")); using var decStream = new ADCStream(cmpFs, CompressionMode.Decompress); using var decMs = new MemoryStream(); var test = new byte[512]; diff --git a/tests/SharpCompress.Test/ArchiveTests.cs b/tests/SharpCompress.Test/ArchiveTests.cs index 8b9a4c2d..e12ac339 100644 --- a/tests/SharpCompress.Test/ArchiveTests.cs +++ b/tests/SharpCompress.Test/ArchiveTests.cs @@ -53,17 +53,11 @@ public class ArchiveTests : ReaderTests stream.ThrowOnDispose = false; return; } - foreach ( - var entry in archive.Entries.Where(entry => !entry.IsDirectory) - ) + foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) { entry.WriteToDirectory( SCRATCH_FILES_PATH, - new ExtractionOptions - { - ExtractFullPath = true, - Overwrite = true - } + new ExtractionOptions { ExtractFullPath = true, Overwrite = true } ); } stream.ThrowOnDispose = false; @@ -96,10 +90,7 @@ public class ArchiveTests : ReaderTests ); } - protected void ArchiveStreamRead( - ReaderOptions? readerOptions, - IEnumerable testArchives - ) + protected void ArchiveStreamRead(ReaderOptions? readerOptions, IEnumerable testArchives) { foreach (var path in testArchives) { @@ -231,9 +222,9 @@ public class ArchiveTests : ReaderTests { var src = testArchives.ToArray(); using var archive = ArchiveFactory.Open( - testArchives.Select(f => new FileInfo(f)), - readerOptions - ); + testArchives.Select(f => new FileInfo(f)), + readerOptions + ); try { var idx = 0; diff --git a/tests/SharpCompress.Test/GZip/GZipArchiveTests.cs b/tests/SharpCompress.Test/GZip/GZipArchiveTests.cs index 51ffd019..46270985 100644 --- a/tests/SharpCompress.Test/GZip/GZipArchiveTests.cs +++ b/tests/SharpCompress.Test/GZip/GZipArchiveTests.cs @@ -64,9 +64,7 @@ public class GZipArchiveTests : ArchiveTests var jpg = Path.Combine(ORIGINAL_FILES_PATH, "jpg", "test.jpg"); using Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz")); using var archive = GZipArchive.Open(stream); - Assert.Throws( - () => archive.AddEntry("jpg\\test.jpg", jpg) - ); + Assert.Throws(() => archive.AddEntry("jpg\\test.jpg", jpg)); archive.SaveTo(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz")); } diff --git a/tests/SharpCompress.Test/GZip/GZipReaderTests.cs b/tests/SharpCompress.Test/GZip/GZipReaderTests.cs index ed65c2a7..6890d4c6 100644 --- a/tests/SharpCompress.Test/GZip/GZipReaderTests.cs +++ b/tests/SharpCompress.Test/GZip/GZipReaderTests.cs @@ -23,9 +23,7 @@ public class GZipReaderTests : ReaderTests { //read only as GZip itme using Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz")); - using var reader = Readers.GZip.GZipReader.Open( - new RewindableStream(stream) - ); + using var reader = Readers.GZip.GZipReader.Open(new RewindableStream(stream)); while (reader.MoveToNextEntry()) // Crash here { Assert.NotEqual(0, reader.Entry.Size); diff --git a/tests/SharpCompress.Test/Mocks/TestStream.cs b/tests/SharpCompress.Test/Mocks/TestStream.cs index 3af53901..bd49ebc3 100644 --- a/tests/SharpCompress.Test/Mocks/TestStream.cs +++ b/tests/SharpCompress.Test/Mocks/TestStream.cs @@ -6,8 +6,8 @@ public class TestStream : Stream { private readonly Stream stream; - public TestStream(Stream stream) - : this(stream, stream.CanRead, stream.CanWrite, stream.CanSeek) { } + public TestStream(Stream stream) : this(stream, stream.CanRead, stream.CanWrite, stream.CanSeek) + { } public bool IsDisposed { get; private set; } diff --git a/tests/SharpCompress.Test/Rar/RarArchiveTests.cs b/tests/SharpCompress.Test/Rar/RarArchiveTests.cs index af184c77..686eb708 100644 --- a/tests/SharpCompress.Test/Rar/RarArchiveTests.cs +++ b/tests/SharpCompress.Test/Rar/RarArchiveTests.cs @@ -168,12 +168,7 @@ public class RarArchiveTests : ArchiveTests public void Rar_Jpg_ArchiveStreamRead() { using var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Rar.jpeg.jpg")); - using ( - var archive = RarArchive.Open( - stream, - new ReaderOptions() { LookForHeader = true } - ) - ) + using (var archive = RarArchive.Open(stream, new ReaderOptions() { LookForHeader = true })) { foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) { @@ -219,7 +214,10 @@ public class RarArchiveTests : ArchiveTests public void QuickTest() { var textItems = new List(); - using var reader = new RarFactory().OpenReader(new FileInfo("/Users/adam/Downloads/Kuuki_Aether_chinesevcv_1.0.rar").OpenRead(), null); + using var reader = new RarFactory().OpenReader( + new FileInfo("/Users/adam/Downloads/Kuuki_Aether_chinesevcv_1.0.rar").OpenRead(), + null + ); textItems.Clear(); while (reader.MoveToNextEntry()) { @@ -344,8 +342,8 @@ public class RarArchiveTests : ArchiveTests private void DoRar_Multi_ArchiveStreamRead(string[] archives, bool isSolid) { using var archive = RarArchive.Open( - archives.Select(s => Path.Combine(TEST_ARCHIVES_PATH, s)).Select(File.OpenRead) - ); + archives.Select(s => Path.Combine(TEST_ARCHIVES_PATH, s)).Select(File.OpenRead) + ); Assert.Equal(archive.IsSolid, isSolid); foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) { diff --git a/tests/SharpCompress.Test/Rar/RarHeaderFactoryTest.cs b/tests/SharpCompress.Test/Rar/RarHeaderFactoryTest.cs index 7e4f013a..2bf90768 100644 --- a/tests/SharpCompress.Test/Rar/RarHeaderFactoryTest.cs +++ b/tests/SharpCompress.Test/Rar/RarHeaderFactoryTest.cs @@ -48,16 +48,13 @@ public class RarHeaderFactoryTest : TestBase private void ReadEncryptedFlag(string testArchive, bool isEncrypted) { using var stream = new FileStream( - Path.Combine(TEST_ARCHIVES_PATH, testArchive), - FileMode.Open, - FileAccess.Read - ); + Path.Combine(TEST_ARCHIVES_PATH, testArchive), + FileMode.Open, + FileAccess.Read + ); foreach (var header in rarHeaderFactory.ReadHeaders(stream)) { - if ( - header.HeaderType == HeaderType.Archive - || header.HeaderType == HeaderType.Crypt - ) + if (header.HeaderType == HeaderType.Archive || header.HeaderType == HeaderType.Crypt) { Assert.Equal(isEncrypted, rarHeaderFactory.IsEncrypted); break; diff --git a/tests/SharpCompress.Test/Rar/RarReaderTests.cs b/tests/SharpCompress.Test/Rar/RarReaderTests.cs index 15266d6c..5e98eee0 100644 --- a/tests/SharpCompress.Test/Rar/RarReaderTests.cs +++ b/tests/SharpCompress.Test/Rar/RarReaderTests.cs @@ -282,15 +282,10 @@ public class RarReaderTests : ReaderTests public void Rar_Reader_Audio_program() { using ( - var stream = File.OpenRead( - Path.Combine(TEST_ARCHIVES_PATH, "Rar.Audio_program.rar") - ) + var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Rar.Audio_program.rar")) ) using ( - var reader = ReaderFactory.Open( - stream, - new ReaderOptions() { LookForHeader = true } - ) + var reader = ReaderFactory.Open(stream, new ReaderOptions() { LookForHeader = true }) ) { while (reader.MoveToNextEntry()) @@ -312,9 +307,7 @@ public class RarReaderTests : ReaderTests public void Rar_Jpg_Reader() { using (var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Rar.jpeg.jpg"))) - using ( - var reader = RarReader.Open(stream, new ReaderOptions() { LookForHeader = true }) - ) + using (var reader = RarReader.Open(stream, new ReaderOptions() { LookForHeader = true })) { while (reader.MoveToNextEntry()) { @@ -355,10 +348,7 @@ public class RarReaderTests : ReaderTests private void DoRar_Solid_Skip_Reader(string filename) { using var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, filename)); - using var reader = ReaderFactory.Open( - stream, - new ReaderOptions() { LookForHeader = true } - ); + using var reader = ReaderFactory.Open(stream, new ReaderOptions() { LookForHeader = true }); while (reader.MoveToNextEntry()) { if (reader.Entry.Key.Contains("jpg")) @@ -387,10 +377,7 @@ public class RarReaderTests : ReaderTests private void DoRar_Reader_Skip(string filename) { using var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, filename)); - using var reader = ReaderFactory.Open( - stream, - new ReaderOptions() { LookForHeader = true } - ); + using var reader = ReaderFactory.Open(stream, new ReaderOptions() { LookForHeader = true }); while (reader.MoveToNextEntry()) { if (reader.Entry.Key.Contains("jpg")) diff --git a/tests/SharpCompress.Test/ReaderTests.cs b/tests/SharpCompress.Test/ReaderTests.cs index eb0de103..be1dbe07 100644 --- a/tests/SharpCompress.Test/ReaderTests.cs +++ b/tests/SharpCompress.Test/ReaderTests.cs @@ -35,18 +35,15 @@ public abstract class ReaderTests : TestBase { using var file = File.OpenRead(testArchive); using var protectedStream = NonDisposingStream.Create( - new ForwardOnlyStream(file), - throwOnDispose: true - ); + new ForwardOnlyStream(file), + throwOnDispose: true + ); using var testStream = new TestStream(protectedStream); using (var reader = ReaderFactory.Open(testStream, options)) { UseReader(reader, expectedCompression); protectedStream.ThrowOnDispose = false; - Assert.False( - testStream.IsDisposed, - "{nameof(testStream)} prematurely closed" - ); + Assert.False(testStream.IsDisposed, "{nameof(testStream)} prematurely closed"); } // Boolean XOR -- If the stream should be left open (true), then the stream should not be diposed (false) diff --git a/tests/SharpCompress.Test/SevenZip/SevenZipArchiveTests.cs b/tests/SharpCompress.Test/SevenZip/SevenZipArchiveTests.cs index c988d1c2..23b99a1a 100644 --- a/tests/SharpCompress.Test/SevenZip/SevenZipArchiveTests.cs +++ b/tests/SharpCompress.Test/SevenZip/SevenZipArchiveTests.cs @@ -34,10 +34,7 @@ public class SevenZipArchiveTests : ArchiveTests [Fact] public void SevenZipArchive_LZMAAES_StreamRead() { - ArchiveStreamRead( - "7Zip.LZMA.Aes.7z", - new ReaderOptions() { Password = "testpassword" } - ); + ArchiveStreamRead("7Zip.LZMA.Aes.7z", new ReaderOptions() { Password = "testpassword" }); } [Fact] diff --git a/tests/SharpCompress.Test/Streams/ZlibBaseStreamTests.cs b/tests/SharpCompress.Test/Streams/ZlibBaseStreamTests.cs index 44f6843c..56f934d6 100644 --- a/tests/SharpCompress.Test/Streams/ZlibBaseStreamTests.cs +++ b/tests/SharpCompress.Test/Streams/ZlibBaseStreamTests.cs @@ -80,10 +80,10 @@ public class ZLibBaseStreamTests private void Compress(Stream input, Stream output, int compressionLevel) { using var zlibStream = new ZlibStream( - NonDisposingStream.Create(output), - CompressionMode.Compress, - (CompressionLevel)compressionLevel - ); + NonDisposingStream.Create(output), + CompressionMode.Compress, + (CompressionLevel)compressionLevel + ); zlibStream.FlushMode = FlushType.Sync; input.CopyTo(zlibStream); } @@ -91,9 +91,9 @@ public class ZLibBaseStreamTests private void Decompress(Stream input, Stream output) { using var zlibStream = new ZlibStream( - NonDisposingStream.Create(input), - CompressionMode.Decompress - ); + NonDisposingStream.Create(input), + CompressionMode.Decompress + ); zlibStream.CopyTo(output); } diff --git a/tests/SharpCompress.Test/Tar/TarWriterTests.cs b/tests/SharpCompress.Test/Tar/TarWriterTests.cs index 197e7ba3..98ed2e19 100644 --- a/tests/SharpCompress.Test/Tar/TarWriterTests.cs +++ b/tests/SharpCompress.Test/Tar/TarWriterTests.cs @@ -50,12 +50,7 @@ public class TarWriterTests : WriterTests public void Tar_Rar_Write() { Assert.Throws( - () => - Write( - CompressionType.Rar, - "Zip.ppmd.noEmptyDirs.zip", - "Zip.ppmd.noEmptyDirs.zip" - ) + () => Write(CompressionType.Rar, "Zip.ppmd.noEmptyDirs.zip", "Zip.ppmd.noEmptyDirs.zip") ); } diff --git a/tests/SharpCompress.Test/WriterTests.cs b/tests/SharpCompress.Test/WriterTests.cs index 7134ea9e..db2c4911 100644 --- a/tests/SharpCompress.Test/WriterTests.cs +++ b/tests/SharpCompress.Test/WriterTests.cs @@ -25,10 +25,7 @@ public class WriterTests : TestBase { using (Stream stream = File.OpenWrite(Path.Combine(SCRATCH2_FILES_PATH, archive))) { - var writerOptions = new WriterOptions(compressionType) - { - LeaveStreamOpen = true, - }; + var writerOptions = new WriterOptions(compressionType) { LeaveStreamOpen = true, }; writerOptions.ArchiveEncoding.Default = encoding ?? Encoding.Default; @@ -46,10 +43,7 @@ public class WriterTests : TestBase readerOptions.ArchiveEncoding.Default = encoding ?? Encoding.Default; - using var reader = ReaderFactory.Open( - NonDisposingStream.Create(stream), - readerOptions - ); + using var reader = ReaderFactory.Open(NonDisposingStream.Create(stream), readerOptions); reader.WriteAllToDirectory( SCRATCH_FILES_PATH, new ExtractionOptions() { ExtractFullPath = true } diff --git a/tests/SharpCompress.Test/Zip/Zip64Tests.cs b/tests/SharpCompress.Test/Zip/Zip64Tests.cs index d19913e1..039411a7 100644 --- a/tests/SharpCompress.Test/Zip/Zip64Tests.cs +++ b/tests/SharpCompress.Test/Zip/Zip64Tests.cs @@ -108,14 +108,7 @@ public class Zip64Tests : WriterTests if (!File.Exists(filename)) { - CreateZipArchive( - filename, - files, - filesize, - write_chunk_size, - set_zip64, - forward_only - ); + CreateZipArchive(filename, files, filesize, write_chunk_size, set_zip64, forward_only); } var resForward = ReadForwardOnly(filename); @@ -195,8 +188,7 @@ public class Zip64Tests : WriterTests { while (rd.MoveToNextEntry()) { - using (rd.OpenEntryStream()) - { } + using (rd.OpenEntryStream()) { } count++; if (prev != null) diff --git a/tests/SharpCompress.Test/Zip/ZipReaderTests.cs b/tests/SharpCompress.Test/Zip/ZipReaderTests.cs index dab65cc0..62f2e751 100644 --- a/tests/SharpCompress.Test/Zip/ZipReaderTests.cs +++ b/tests/SharpCompress.Test/Zip/ZipReaderTests.cs @@ -77,8 +77,8 @@ public class ZipReaderTests : ReaderTests public void Zip_Deflate_Streamed_Skip() { using Stream stream = new ForwardOnlyStream( - File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.dd.zip")) - ); + File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.dd.zip")) + ); using var reader = ReaderFactory.Open(stream); var x = 0; while (reader.MoveToNextEntry()) @@ -149,9 +149,7 @@ public class ZipReaderTests : ReaderTests public void Zip_BZip2_PkwareEncryption_Read() { using ( - Stream stream = File.OpenRead( - Path.Combine(TEST_ARCHIVES_PATH, "Zip.bzip2.pkware.zip") - ) + Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Zip.bzip2.pkware.zip")) ) using (var reader = ZipReader.Open(stream, new ReaderOptions() { Password = "test" })) { @@ -174,8 +172,8 @@ public class ZipReaderTests : ReaderTests public void Zip_Reader_Disposal_Test() { using var stream = new TestStream( - File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.dd.zip")) - ); + File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.dd.zip")) + ); using (var reader = ReaderFactory.Open(stream)) { while (reader.MoveToNextEntry()) @@ -196,8 +194,8 @@ public class ZipReaderTests : ReaderTests public void Zip_Reader_Disposal_Test2() { using var stream = new TestStream( - File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.dd.zip")) - ); + File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.dd.zip")) + ); var reader = ReaderFactory.Open(stream); while (reader.MoveToNextEntry()) { @@ -222,9 +220,7 @@ public class ZipReaderTests : ReaderTests Path.Combine(TEST_ARCHIVES_PATH, "Zip.lzma.WinzipAES.zip") ) ) - using ( - var reader = ZipReader.Open(stream, new ReaderOptions() { Password = "test" }) - ) + using (var reader = ZipReader.Open(stream, new ReaderOptions() { Password = "test" })) { while (reader.MoveToNextEntry()) { @@ -302,13 +298,7 @@ public class ZipReaderTests : ReaderTests using var memory = new MemoryStream(); Stream stream = new TestStream(memory, read: true, write: true, seek: false); - using ( - var zipWriter = WriterFactory.Open( - stream, - ArchiveType.Zip, - CompressionType.Deflate - ) - ) + using (var zipWriter = WriterFactory.Open(stream, ArchiveType.Zip, CompressionType.Deflate)) { zipWriter.Write(expected[0].Item1, new MemoryStream(expected[0].Item2)); zipWriter.Write(expected[1].Item1, new MemoryStream(expected[1].Item2)); @@ -354,8 +344,8 @@ public class ZipReaderTests : ReaderTests }; using Stream stream = File.OpenRead( - Path.Combine(TEST_ARCHIVES_PATH, "Zip.none.issue86.zip") - ); + Path.Combine(TEST_ARCHIVES_PATH, "Zip.none.issue86.zip") + ); using var reader = ZipReader.Open(stream); foreach (var key in keys) { @@ -407,8 +397,7 @@ public class ZipReaderTests : ReaderTests var zipPath = Path.Combine(TEST_ARCHIVES_PATH, "Zip.uncompressed.zip"); using var stream = File.Open(zipPath, FileMode.Open, FileAccess.Read); using var reader = ReaderFactory.Open(stream); - while (reader.MoveToNextEntry()) - { } + while (reader.MoveToNextEntry()) { } } [Fact] diff --git a/tests/SharpCompress.Test/Zip/ZipWriterTests.cs b/tests/SharpCompress.Test/Zip/ZipWriterTests.cs index c073a8a2..b95efb81 100644 --- a/tests/SharpCompress.Test/Zip/ZipWriterTests.cs +++ b/tests/SharpCompress.Test/Zip/ZipWriterTests.cs @@ -68,12 +68,7 @@ public class ZipWriterTests : WriterTests public void Zip_Rar_Write() { Assert.Throws( - () => - Write( - CompressionType.Rar, - "Zip.ppmd.noEmptyDirs.zip", - "Zip.ppmd.noEmptyDirs.zip" - ) + () => Write(CompressionType.Rar, "Zip.ppmd.noEmptyDirs.zip", "Zip.ppmd.noEmptyDirs.zip") ); } } From b01e97b16869d1f3f16e77f94a128a2415752897 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Tue, 20 Dec 2022 15:20:49 +0000 Subject: [PATCH 7/7] more clean up --- src/SharpCompress/Archives/AbstractArchive.cs | 16 +- .../Archives/AbstractWritableArchive.cs | 26 +- .../Archives/ArchiveVolumeFactory.cs | 44 +- .../Archives/GZip/GZipArchive.cs | 15 +- .../Archives/GZip/GZipArchiveEntry.cs | 6 +- .../Archives/IArchiveEntryExtensions.cs | 8 +- .../Archives/IWritableArchiveExtensions.cs | 7 +- .../Archives/Rar/FileInfoRarArchiveVolume.cs | 17 +- .../Archives/Rar/FileInfoRarFilePart.cs | 11 +- .../Archives/Rar/RarArchive.Extensions.cs | 14 +- src/SharpCompress/Archives/Rar/RarArchive.cs | 11 +- .../Archives/Rar/RarArchiveVolumeFactory.cs | 77 +- .../Archives/Rar/StreamRarArchiveVolume.cs | 11 +- .../Archives/SevenZip/SevenZipArchive.cs | 41 +- .../Archives/SevenZip/SevenZipArchiveEntry.cs | 11 +- src/SharpCompress/Archives/Tar/TarArchive.cs | 16 +- .../Archives/Tar/TarArchiveEntry.cs | 12 +- src/SharpCompress/Archives/Zip/ZipArchive.cs | 25 +- .../Archives/Zip/ZipArchiveEntry.cs | 11 +- .../Archives/Zip/ZipArchiveVolumeFactory.cs | 57 +- src/SharpCompress/Common/ArchiveEncoding.cs | 38 +- .../Common/ArchiveExtractionEventArgs.cs | 7 +- src/SharpCompress/Common/EntryStream.cs | 14 +- src/SharpCompress/Common/ExtractionMethods.cs | 195 ++- src/SharpCompress/Common/FilePart.cs | 5 +- src/SharpCompress/Common/FlagUtility.cs | 41 +- src/SharpCompress/Common/GZip/GZipEntry.cs | 7 +- src/SharpCompress/Common/GZip/GZipFilePart.cs | 11 +- src/SharpCompress/Common/GZip/GZipVolume.cs | 6 +- .../Common/Rar/Headers/ArchiveHeader.cs | 5 +- .../Common/Rar/Headers/EndArchiveHeader.cs | 7 +- .../Common/Rar/Headers/FileHeader.cs | 10 +- .../Common/Rar/Headers/FileNameDecoder.cs | 5 +- .../Common/Rar/Headers/MarkHeader.cs | 5 +- .../Common/Rar/Headers/NewSubHeaderType.cs | 7 +- .../Common/Rar/Headers/RarHeader.cs | 17 +- .../Common/Rar/RarCrcBinaryReader.cs | 20 +- .../Common/Rar/RarCryptoBinaryReader.cs | 12 +- .../Common/Rar/RarCryptoWrapper.cs | 19 +- src/SharpCompress/Common/Rar/RarEntry.cs | 8 +- src/SharpCompress/Common/Rar/RarFilePart.cs | 5 +- src/SharpCompress/Common/Rar/RarVolume.cs | 5 +- .../Common/SevenZip/ArchiveDatabase.cs | 20 +- .../Common/SevenZip/ArchiveReader.cs | 82 +- .../Common/SevenZip/CFileItem.cs | 12 +- .../Common/SevenZip/CMethodId.cs | 32 +- .../Common/SevenZip/DataReader.cs | 39 +- .../Common/SevenZip/SevenZipEntry.cs | 7 +- .../Common/SevenZip/SevenZipFilePart.cs | 5 +- .../Common/Tar/Headers/TarHeader.cs | 12 +- src/SharpCompress/Common/Tar/TarFilePart.cs | 7 +- .../Common/Tar/TarReadOnlySubStream.cs | 177 +- src/SharpCompress/Common/Volume.cs | 5 +- .../Headers/LocalEntryHeaderExtraFactory.cs | 8 +- .../Common/Zip/Headers/SplitHeader.cs | 7 +- .../Zip/PkwareTraditionalCryptoStream.cs | 12 +- .../Common/Zip/StreamingZipFilePart.cs | 5 +- .../Common/Zip/WinzipAesCryptoStream.cs | 43 +- .../Common/Zip/WinzipAesEncryptionData.cs | 11 +- src/SharpCompress/Compressors/ADC/ADCBase.cs | 20 +- .../Compressors/ADC/ADCStream.cs | 14 +- .../Compressors/BZip2/BZip2Stream.cs | 52 +- .../Compressors/BZip2/CBZip2InputStream.cs | 54 +- .../Compressors/BZip2/CBZip2OutputStream.cs | 32 +- src/SharpCompress/Compressors/BZip2/CRC.cs | 27 +- .../Compressors/Deflate/CRC32.cs | 16 +- .../Compressors/Deflate/DeflateManager.cs | 26 +- .../Compressors/Deflate/DeflateStream.cs | 14 +- .../Compressors/Deflate/GZipStream.cs | 10 +- .../Compressors/Deflate/Inflate.cs | 14 +- src/SharpCompress/Compressors/Deflate/Tree.cs | 6 +- src/SharpCompress/Compressors/Deflate/Zlib.cs | 5 +- .../Compressors/Deflate/ZlibBaseStream.cs | 1098 ++++++------ .../Compressors/Deflate/ZlibCodec.cs | 16 +- .../Compressors/Deflate/ZlibStream.cs | 15 +- .../Compressors/Deflate64/Deflate64Stream.cs | 429 +++-- .../Compressors/Deflate64/DeflateInput.cs | 5 +- .../Compressors/Deflate64/InflaterManaged.cs | 4 +- .../Compressors/Filters/BCJ2Filter.cs | 31 +- .../Compressors/Filters/BCJFilter.cs | 11 +- .../Compressors/Filters/Filter.cs | 17 +- .../Compressors/LZMA/AesDecoderStream.cs | 503 +++--- .../Compressors/LZMA/Bcj2DecoderStream.cs | 22 +- src/SharpCompress/Compressors/LZMA/CRC.cs | 23 +- .../Compressors/LZMA/DecoderStream.cs | 21 +- .../Compressors/LZMA/LZ/LzBinTree.cs | 31 +- .../Compressors/LZMA/LZ/LzInWindow.cs | 20 +- .../Compressors/LZMA/LZ/LzOutWindow.cs | 10 +- .../Compressors/LZMA/LZipStream.cs | 10 +- src/SharpCompress/Compressors/LZMA/Log.cs | 12 +- .../Compressors/LZMA/LzmaBase.cs | 25 +- .../Compressors/LZMA/LzmaDecoder.cs | 22 +- .../Compressors/LZMA/LzmaEncoder.cs | 57 +- .../Compressors/LZMA/LzmaStream.cs | 12 +- .../Compressors/LZMA/RangeCoder/RangeCoder.cs | 43 +- .../LZMA/RangeCoder/RangeCoderBit.cs | 26 +- .../LZMA/Utilites/CrcBuilderStream.cs | 16 +- .../LZMA/Utilites/CrcCheckStream.cs | 14 +- .../Compressors/PPMd/H/FreqData.cs | 24 +- .../Compressors/PPMd/H/ModelPPM.cs | 30 +- .../Compressors/PPMd/H/PPMContext.cs | 26 +- .../Compressors/PPMd/H/Pointer.cs | 5 +- .../Compressors/PPMd/H/RangeCoder.cs | 5 +- .../Compressors/PPMd/H/RarMemBlock.cs | 10 +- .../Compressors/PPMd/H/RarNode.cs | 5 +- .../Compressors/PPMd/H/SEE2Context.cs | 5 +- src/SharpCompress/Compressors/PPMd/H/State.cs | 28 +- .../Compressors/PPMd/H/StateRef.cs | 25 +- .../Compressors/PPMd/H/SubAllocator.cs | 50 +- .../Compressors/PPMd/I1/Allocator.cs | 5 +- .../Compressors/PPMd/I1/Coder.cs | 11 +- .../Compressors/PPMd/I1/MemoryNode.cs | 28 +- .../Compressors/PPMd/I1/Model.cs | 6 +- .../Compressors/PPMd/I1/Pointer.cs | 35 +- .../Compressors/PPMd/I1/PpmContext.cs | 35 +- .../Compressors/PPMd/I1/PpmState.cs | 35 +- .../Compressors/PPMd/PpmdStream.cs | 12 +- .../Rar/MultiVolumeReadOnlyStream.cs | 19 +- src/SharpCompress/Compressors/Rar/RarCRC.cs | 6 +- .../Compressors/Rar/RarCrcStream.cs | 10 +- .../Compressors/Rar/RarStream.cs | 10 +- .../Rar/UnpackV1/Decode/AudioVariables.cs | 5 +- .../Compressors/Rar/UnpackV1/Unpack.cs | 12 +- .../Compressors/Rar/UnpackV1/Unpack15.cs | 10 +- .../Compressors/Rar/UnpackV1/Unpack50.cs | 63 +- .../Compressors/Rar/UnpackV1/UnpackFilter.cs | 13 +- .../Compressors/Rar/UnpackV1/UnpackUtility.cs | 8 +- .../Rar/UnpackV2017/BitInput.getbits_cpp.cs | 12 +- .../Rar/UnpackV2017/BitInput.getbits_hpp.cs | 7 +- .../Compressors/Rar/UnpackV2017/Unpack.cs | 23 +- .../Rar/UnpackV2017/Unpack.rawint_hpp.cs | 10 +- .../Rar/UnpackV2017/Unpack.unpack15_cpp.cs | 12 +- .../Rar/UnpackV2017/Unpack.unpack50_cpp.cs | 6 +- .../Compressors/Rar/UnpackV2017/unpack_hpp.cs | 2 +- .../Compressors/Rar/VM/BitInput.cs | 40 +- src/SharpCompress/Compressors/Rar/VM/RarVM.cs | 14 +- .../Compressors/Xz/BinaryUtils.cs | 12 +- src/SharpCompress/Compressors/Xz/Crc32.cs | 17 +- src/SharpCompress/Compressors/Xz/Crc64.cs | 5 +- .../Compressors/Xz/Filters/ArmFilter.cs | 5 +- .../Compressors/Xz/Filters/ArmThumbFilter.cs | 5 +- .../Compressors/Xz/Filters/IA64Filter.cs | 5 +- .../Compressors/Xz/Filters/Lzma2Filter.cs | 15 +- .../Compressors/Xz/Filters/PowerPCFilter.cs | 5 +- .../Compressors/Xz/Filters/SparcFilter.cs | 5 +- .../Compressors/Xz/Filters/X86Filter.cs | 5 +- .../Compressors/Xz/ReadOnlyStream.cs | 21 +- src/SharpCompress/Compressors/Xz/XZFooter.cs | 1 - src/SharpCompress/Compressors/Xz/XZHeader.cs | 6 +- src/SharpCompress/Compressors/Xz/XZStream.cs | 18 +- src/SharpCompress/Crypto/Crc32Stream.cs | 28 +- src/SharpCompress/Crypto/KeyParameter.cs | 7 +- src/SharpCompress/Crypto/RijndaelEngine.cs | 7 +- src/SharpCompress/Factories/Factory.cs | 5 +- src/SharpCompress/Factories/GZipFactory.cs | 41 +- src/SharpCompress/Factories/RarFactory.cs | 42 +- .../Factories/SevenZipFactory.cs | 30 +- src/SharpCompress/Factories/TarFactory.cs | 47 +- src/SharpCompress/Factories/ZipFactory.cs | 47 +- src/SharpCompress/IO/BufferedSubStream.cs | 21 +- .../IO/CountingWritableSubStream.cs | 19 +- src/SharpCompress/IO/ListeningStream.cs | 21 +- src/SharpCompress/IO/MarkingBinaryReader.cs | 111 +- src/SharpCompress/IO/NonDisposingStream.cs | 35 +- src/SharpCompress/IO/ReadOnlySubStream.cs | 19 +- src/SharpCompress/IO/RewindableStream.cs | 24 +- src/SharpCompress/IO/SourceStream.cs | 14 +- src/SharpCompress/Lazy.cs | 5 +- src/SharpCompress/LazyReadOnlyCollection.cs | 46 +- .../Polyfills/StringExtensions.cs | 13 +- src/SharpCompress/ReadOnlyCollection.cs | 40 +- src/SharpCompress/Readers/AbstractReader.cs | 34 +- src/SharpCompress/Readers/GZip/GZipReader.cs | 12 +- .../Readers/IReaderExtensions.cs | 10 +- .../Readers/Rar/MultiVolumeRarReader.cs | 17 +- .../Readers/Rar/NonSeekableStreamFilePart.cs | 5 +- src/SharpCompress/Readers/Rar/RarReader.cs | 6 +- .../Readers/Rar/RarReaderVolume.cs | 11 +- .../Readers/Rar/SingleVolumeRarReader.cs | 11 +- src/SharpCompress/Readers/Tar/TarReader.cs | 213 ++- src/SharpCompress/Utility.cs | 40 +- src/SharpCompress/Writers/AbstractWriter.cs | 7 +- .../Writers/IWriterExtensions.cs | 15 +- src/SharpCompress/Writers/Tar/TarWriter.cs | 4 +- .../Writers/Tar/TarWriterOptions.cs | 9 +- src/SharpCompress/Writers/WriterOptions.cs | 13 +- src/SharpCompress/Writers/Zip/ZipWriter.cs | 27 +- tests/SharpCompress.Test/ArchiveTests.cs | 16 +- .../Filters/BranchExecTests.cs | 4 +- .../GZip/GZipArchiveTests.cs | 5 +- .../GZip/GZipReaderTests.cs | 10 +- .../GZip/GZipWriterTests.cs | 11 +- .../Mocks/FlushOnDisposeStream.cs | 31 +- .../Mocks/ForwardOnlyStream.cs | 32 +- tests/SharpCompress.Test/Mocks/TestStream.cs | 27 +- .../SharpCompress.Test/Rar/RarArchiveTests.cs | 315 +--- .../Rar/RarHeaderFactoryTest.cs | 22 +- .../SharpCompress.Test/Rar/RarReaderTests.cs | 112 +- .../SevenZip/SevenZipArchiveTests.cs | 103 +- .../SharpCompress.Test/Tar/TarArchiveTests.cs | 571 ++++--- .../SharpCompress.Test/Tar/TarReaderTests.cs | 407 +++-- .../SharpCompress.Test/Tar/TarWriterTests.cs | 23 +- tests/SharpCompress.Test/TestBase.cs | 5 +- tests/SharpCompress.Test/WriterTests.cs | 5 +- tests/SharpCompress.Test/Xz/Crc32Tests.cs | 1 - tests/SharpCompress.Test/Xz/Crc64Tests.cs | 1 - .../Xz/Filters/Lzma2Tests.cs | 107 +- tests/SharpCompress.Test/Xz/XZBlockTests.cs | 10 +- tests/SharpCompress.Test/Xz/XZHeaderTests.cs | 153 +- tests/SharpCompress.Test/Xz/XZIndexTests.cs | 180 +- tests/SharpCompress.Test/Xz/XZStreamTests.cs | 53 +- tests/SharpCompress.Test/Xz/XZTestsBase.cs | 17 +- tests/SharpCompress.Test/Zip/Zip64Tests.cs | 20 +- .../SharpCompress.Test/Zip/ZipArchiveTests.cs | 1475 ++++++++--------- .../SharpCompress.Test/Zip/ZipReaderTests.cs | 92 +- .../SharpCompress.Test/Zip/ZipWriterTests.cs | 24 +- 216 files changed, 3764 insertions(+), 6063 deletions(-) diff --git a/src/SharpCompress/Archives/AbstractArchive.cs b/src/SharpCompress/Archives/AbstractArchive.cs index 630cf3c5..cfac55f2 100644 --- a/src/SharpCompress/Archives/AbstractArchive.cs +++ b/src/SharpCompress/Archives/AbstractArchive.cs @@ -47,15 +47,11 @@ public abstract class AbstractArchive : IArchive, IArchiveExtra public ArchiveType Type { get; } - void IArchiveExtractionListener.FireEntryExtractionBegin(IArchiveEntry entry) - { + void IArchiveExtractionListener.FireEntryExtractionBegin(IArchiveEntry entry) => EntryExtractionBegin?.Invoke(this, new ArchiveExtractionEventArgs(entry)); - } - void IArchiveExtractionListener.FireEntryExtractionEnd(IArchiveEntry entry) - { + void IArchiveExtractionListener.FireEntryExtractionEnd(IArchiveEntry entry) => EntryExtractionEnd?.Invoke(this, new ArchiveExtractionEventArgs(entry)); - } private static Stream CheckStreams(Stream stream) { @@ -116,8 +112,7 @@ public abstract class AbstractArchive : IArchive, IArchiveExtra void IExtractionListener.FireCompressedBytesRead( long currentPartCompressedBytes, long compressedReadBytes - ) - { + ) => CompressedBytesRead?.Invoke( this, new CompressedBytesReadEventArgs( @@ -125,14 +120,12 @@ public abstract class AbstractArchive : IArchive, IArchiveExtra compressedBytesRead: compressedReadBytes ) ); - } void IExtractionListener.FireFilePartExtractionBegin( string name, long size, long compressedSize - ) - { + ) => FilePartExtractionBegin?.Invoke( this, new FilePartExtractionBeginEventArgs( @@ -141,7 +134,6 @@ public abstract class AbstractArchive : IArchive, IArchiveExtra name: name ) ); - } /// /// Use this method to extract all entries in an archive in order. diff --git a/src/SharpCompress/Archives/AbstractWritableArchive.cs b/src/SharpCompress/Archives/AbstractWritableArchive.cs index f3f98be8..cf97aff8 100644 --- a/src/SharpCompress/Archives/AbstractWritableArchive.cs +++ b/src/SharpCompress/Archives/AbstractWritableArchive.cs @@ -55,10 +55,7 @@ public abstract class AbstractWritableArchive } } - public IDisposable PauseEntryRebuilding() - { - return new RebuildPauseDisposable(this); - } + public IDisposable PauseEntryRebuilding() => new RebuildPauseDisposable(this); private void RebuildModifiedCollection() { @@ -72,10 +69,7 @@ public abstract class AbstractWritableArchive modifiedEntries.AddRange(OldEntries.Concat(newEntries)); } - private IEnumerable OldEntries - { - get { return base.Entries.Where(x => !removedEntries.Contains(x)); } - } + private IEnumerable OldEntries => base.Entries.Where(x => !removedEntries.Contains(x)); public void RemoveEntry(TEntry entry) { @@ -86,15 +80,10 @@ public abstract class AbstractWritableArchive } } - void IWritableArchive.RemoveEntry(IArchiveEntry entry) - { - RemoveEntry((TEntry)entry); - } + void IWritableArchive.RemoveEntry(IArchiveEntry entry) => RemoveEntry((TEntry)entry); - public TEntry AddEntry(string key, Stream source, long size = 0, DateTime? modified = null) - { - return AddEntry(key, source, false, size, modified); - } + public TEntry AddEntry(string key, Stream source, long size = 0, DateTime? modified = null) => + AddEntry(key, source, false, size, modified); IArchiveEntry IWritableArchive.AddEntry( string key, @@ -102,10 +91,7 @@ public abstract class AbstractWritableArchive bool closeStream, long size, DateTime? modified - ) - { - return AddEntry(key, source, closeStream, size, modified); - } + ) => AddEntry(key, source, closeStream, size, modified); public TEntry AddEntry( string key, diff --git a/src/SharpCompress/Archives/ArchiveVolumeFactory.cs b/src/SharpCompress/Archives/ArchiveVolumeFactory.cs index fc68399b..d8f5535f 100644 --- a/src/SharpCompress/Archives/ArchiveVolumeFactory.cs +++ b/src/SharpCompress/Archives/ArchiveVolumeFactory.cs @@ -1,36 +1,30 @@ using System; -using System.Collections.Generic; using System.IO; -using SharpCompress.Readers; -using System.Linq; -using System.Text; -using SharpCompress.Common.Rar.Headers; using System.Text.RegularExpressions; -namespace SharpCompress.Archives +namespace SharpCompress.Archives; + +internal abstract class ArchiveVolumeFactory { - internal abstract class ArchiveVolumeFactory + internal static FileInfo? GetFilePart(int index, FileInfo part1) //base the name on the first part { - internal static FileInfo? GetFilePart(int index, FileInfo part1) //base the name on the first part - { - FileInfo? item = null; + FileInfo? item = null; - //split 001, 002 ... - Match m = Regex.Match(part1.Name, @"^(.*\.)([0-9]+)$", RegexOptions.IgnoreCase); - if (m.Success) - item = new FileInfo( - Path.Combine( - part1.DirectoryName!, - String.Concat( - m.Groups[1].Value, - (index + 1).ToString().PadLeft(m.Groups[2].Value.Length, '0') - ) + //split 001, 002 ... + Match m = Regex.Match(part1.Name, @"^(.*\.)([0-9]+)$", RegexOptions.IgnoreCase); + if (m.Success) + item = new FileInfo( + Path.Combine( + part1.DirectoryName!, + String.Concat( + m.Groups[1].Value, + (index + 1).ToString().PadLeft(m.Groups[2].Value.Length, '0') ) - ); + ) + ); - if (item != null && item.Exists) - return item; - return null; - } + if (item != null && item.Exists) + return item; + return null; } } diff --git a/src/SharpCompress/Archives/GZip/GZipArchive.cs b/src/SharpCompress/Archives/GZip/GZipArchive.cs index 43a43c00..eea56db0 100644 --- a/src/SharpCompress/Archives/GZip/GZipArchive.cs +++ b/src/SharpCompress/Archives/GZip/GZipArchive.cs @@ -94,10 +94,7 @@ public class GZipArchive : AbstractWritableArchive ); } - public static GZipArchive Create() - { - return new GZipArchive(); - } + public static GZipArchive Create() => new GZipArchive(); /// /// Constructor with a SourceStream able to handle FileInfo and Streams. @@ -113,10 +110,7 @@ public class GZipArchive : AbstractWritableArchive return srcStream.Streams.Select(a => new GZipVolume(a, ReaderOptions, idx++)); } - public static bool IsGZipFile(string filePath) - { - return IsGZipFile(new FileInfo(filePath)); - } + public static bool IsGZipFile(string filePath) => IsGZipFile(new FileInfo(filePath)); public static bool IsGZipFile(FileInfo fileInfo) { @@ -129,10 +123,7 @@ public class GZipArchive : AbstractWritableArchive return IsGZipFile(stream); } - public void SaveTo(string filePath) - { - SaveTo(new FileInfo(filePath)); - } + public void SaveTo(string filePath) => SaveTo(new FileInfo(filePath)); public void SaveTo(FileInfo fileInfo) { diff --git a/src/SharpCompress/Archives/GZip/GZipArchiveEntry.cs b/src/SharpCompress/Archives/GZip/GZipArchiveEntry.cs index 68032131..0109ad98 100644 --- a/src/SharpCompress/Archives/GZip/GZipArchiveEntry.cs +++ b/src/SharpCompress/Archives/GZip/GZipArchiveEntry.cs @@ -1,4 +1,4 @@ -using System.IO; +using System.IO; using System.Linq; using SharpCompress.Common.GZip; @@ -6,10 +6,8 @@ namespace SharpCompress.Archives.GZip; public class GZipArchiveEntry : GZipEntry, IArchiveEntry { - internal GZipArchiveEntry(GZipArchive archive, GZipFilePart part) : base(part) - { + internal GZipArchiveEntry(GZipArchive archive, GZipFilePart part) : base(part) => Archive = archive; - } public virtual Stream OpenEntryStream() { diff --git a/src/SharpCompress/Archives/IArchiveEntryExtensions.cs b/src/SharpCompress/Archives/IArchiveEntryExtensions.cs index cd49cef0..0992f152 100644 --- a/src/SharpCompress/Archives/IArchiveEntryExtensions.cs +++ b/src/SharpCompress/Archives/IArchiveEntryExtensions.cs @@ -41,15 +41,13 @@ public static class IArchiveEntryExtensions this IArchiveEntry entry, string destinationDirectory, ExtractionOptions? options = null - ) - { + ) => ExtractionMethods.WriteEntryToDirectory( entry, destinationDirectory, options, entry.WriteToFile ); - } /// /// Extract to specific file @@ -58,8 +56,7 @@ public static class IArchiveEntryExtensions this IArchiveEntry entry, string destinationFileName, ExtractionOptions? options = null - ) - { + ) => ExtractionMethods.WriteEntryToFile( entry, destinationFileName, @@ -70,5 +67,4 @@ public static class IArchiveEntryExtensions entry.WriteTo(fs); } ); - } } diff --git a/src/SharpCompress/Archives/IWritableArchiveExtensions.cs b/src/SharpCompress/Archives/IWritableArchiveExtensions.cs index 794aea1f..8f531d41 100644 --- a/src/SharpCompress/Archives/IWritableArchiveExtensions.cs +++ b/src/SharpCompress/Archives/IWritableArchiveExtensions.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; using SharpCompress.Writers; @@ -30,10 +30,7 @@ public static class IWritableArchiveExtensions this IWritableArchive writableArchive, string filePath, WriterOptions options - ) - { - writableArchive.SaveTo(new FileInfo(filePath), options); - } + ) => writableArchive.SaveTo(new FileInfo(filePath), options); public static void SaveTo( this IWritableArchive writableArchive, diff --git a/src/SharpCompress/Archives/Rar/FileInfoRarArchiveVolume.cs b/src/SharpCompress/Archives/Rar/FileInfoRarArchiveVolume.cs index 0f1acd3f..3e576db3 100644 --- a/src/SharpCompress/Archives/Rar/FileInfoRarArchiveVolume.cs +++ b/src/SharpCompress/Archives/Rar/FileInfoRarArchiveVolume.cs @@ -31,19 +31,8 @@ internal class FileInfoRarArchiveVolume : RarVolume internal FileInfo FileInfo { get; } - internal override RarFilePart CreateFilePart(MarkHeader markHeader, FileHeader fileHeader) - { - return new FileInfoRarFilePart( - this, - ReaderOptions.Password, - markHeader, - fileHeader, - FileInfo - ); - } + internal override RarFilePart CreateFilePart(MarkHeader markHeader, FileHeader fileHeader) => + new FileInfoRarFilePart(this, ReaderOptions.Password, markHeader, fileHeader, FileInfo); - internal override IEnumerable ReadFileParts() - { - return FileParts; - } + internal override IEnumerable ReadFileParts() => FileParts; } diff --git a/src/SharpCompress/Archives/Rar/FileInfoRarFilePart.cs b/src/SharpCompress/Archives/Rar/FileInfoRarFilePart.cs index 59a21334..b5416f9e 100644 --- a/src/SharpCompress/Archives/Rar/FileInfoRarFilePart.cs +++ b/src/SharpCompress/Archives/Rar/FileInfoRarFilePart.cs @@ -11,15 +11,10 @@ internal sealed class FileInfoRarFilePart : SeekableFilePart MarkHeader mh, FileHeader fh, FileInfo fi - ) : base(mh, fh, volume.Index, volume.Stream, password) - { - FileInfo = fi; - } + ) : base(mh, fh, volume.Index, volume.Stream, password) => FileInfo = fi; internal FileInfo FileInfo { get; } - internal override string FilePartName - { - get { return "Rar File: " + FileInfo.FullName + " File Entry: " + FileHeader.FileName; } - } + internal override string FilePartName => + "Rar File: " + FileInfo.FullName + " File Entry: " + FileHeader.FileName; } diff --git a/src/SharpCompress/Archives/Rar/RarArchive.Extensions.cs b/src/SharpCompress/Archives/Rar/RarArchive.Extensions.cs index b0edf3f5..bf6f0cd4 100644 --- a/src/SharpCompress/Archives/Rar/RarArchive.Extensions.cs +++ b/src/SharpCompress/Archives/Rar/RarArchive.Extensions.cs @@ -1,4 +1,4 @@ -using System.Linq; +using System.Linq; namespace SharpCompress.Archives.Rar; @@ -7,16 +7,12 @@ public static class RarArchiveExtensions /// /// RarArchive is the first volume of a multi-part archive. If MultipartVolume is true and IsFirstVolume is false then the first volume file must be missing. /// - public static bool IsFirstVolume(this RarArchive archive) - { - return archive.Volumes.First().IsFirstVolume; - } + public static bool IsFirstVolume(this RarArchive archive) => + archive.Volumes.First().IsFirstVolume; /// /// RarArchive is part of a multi-part archive. /// - public static bool IsMultipartVolume(this RarArchive archive) - { - return archive.Volumes.First().IsMultiVolume; - } + public static bool IsMultipartVolume(this RarArchive archive) => + archive.Volumes.First().IsMultiVolume; } diff --git a/src/SharpCompress/Archives/Rar/RarArchive.cs b/src/SharpCompress/Archives/Rar/RarArchive.cs index c9d8a6a8..48f4ef45 100644 --- a/src/SharpCompress/Archives/Rar/RarArchive.cs +++ b/src/SharpCompress/Archives/Rar/RarArchive.cs @@ -25,10 +25,8 @@ public class RarArchive : AbstractArchive /// internal RarArchive(SourceStream srcStream) : base(ArchiveType.Rar, srcStream) { } - protected override IEnumerable LoadEntries(IEnumerable volumes) - { - return RarArchiveEntryFactory.GetEntries(this, volumes, ReaderOptions); - } + protected override IEnumerable LoadEntries(IEnumerable volumes) => + RarArchiveEntryFactory.GetEntries(this, volumes, ReaderOptions); protected override IEnumerable LoadVolumes(SourceStream srcStream) { @@ -149,10 +147,7 @@ public class RarArchive : AbstractArchive ); } - public static bool IsRarFile(string filePath) - { - return IsRarFile(new FileInfo(filePath)); - } + public static bool IsRarFile(string filePath) => IsRarFile(new FileInfo(filePath)); public static bool IsRarFile(FileInfo fileInfo) { diff --git a/src/SharpCompress/Archives/Rar/RarArchiveVolumeFactory.cs b/src/SharpCompress/Archives/Rar/RarArchiveVolumeFactory.cs index 58ab96eb..6903bc5f 100644 --- a/src/SharpCompress/Archives/Rar/RarArchiveVolumeFactory.cs +++ b/src/SharpCompress/Archives/Rar/RarArchiveVolumeFactory.cs @@ -1,62 +1,51 @@ using System; -using System.Collections.Generic; using System.IO; -using SharpCompress.Common.Rar; -using SharpCompress.Readers; -using System.Linq; -using System.Text; -using SharpCompress.Common.Rar.Headers; using System.Text.RegularExpressions; -namespace SharpCompress.Archives.Rar -{ - internal static class RarArchiveVolumeFactory - { - internal static FileInfo? GetFilePart(int index, FileInfo part1) //base the name on the first part - { - FileInfo? item = null; +namespace SharpCompress.Archives.Rar; - //new style rar - ..part1 | /part01 | part001 .... - Match m = Regex.Match( - part1.Name, - @"^(.*\.part)([0-9]+)(\.rar)$", - RegexOptions.IgnoreCase +internal static class RarArchiveVolumeFactory +{ + internal static FileInfo? GetFilePart(int index, FileInfo part1) //base the name on the first part + { + FileInfo? item = null; + + //new style rar - ..part1 | /part01 | part001 .... + Match m = Regex.Match(part1.Name, @"^(.*\.part)([0-9]+)(\.rar)$", RegexOptions.IgnoreCase); + if (m.Success) + item = new FileInfo( + Path.Combine( + part1.DirectoryName!, + String.Concat( + m.Groups[1].Value, + (index + 1).ToString().PadLeft(m.Groups[2].Value.Length, '0'), + m.Groups[3].Value + ) + ) ); + else + { + //old style - ...rar, .r00, .r01 ... + m = Regex.Match(part1.Name, @"^(.*\.r)(ar|[0-9]+)$", RegexOptions.IgnoreCase); if (m.Success) item = new FileInfo( Path.Combine( part1.DirectoryName!, String.Concat( m.Groups[1].Value, - (index + 1).ToString().PadLeft(m.Groups[2].Value.Length, '0'), - m.Groups[3].Value + index == 0 + ? "ar" + : (index - 1).ToString().PadLeft(m.Groups[2].Value.Length, '0') ) ) ); - else - { - //old style - ...rar, .r00, .r01 ... - m = Regex.Match(part1.Name, @"^(.*\.r)(ar|[0-9]+)$", RegexOptions.IgnoreCase); - if (m.Success) - item = new FileInfo( - Path.Combine( - part1.DirectoryName!, - String.Concat( - m.Groups[1].Value, - index == 0 - ? "ar" - : (index - 1).ToString().PadLeft(m.Groups[2].Value.Length, '0') - ) - ) - ); - else //split .001, .002 .... - return ArchiveVolumeFactory.GetFilePart(index, part1); - } - - if (item != null && item.Exists) - return item; - - return null; //no more items + else //split .001, .002 .... + return ArchiveVolumeFactory.GetFilePart(index, part1); } + + if (item != null && item.Exists) + return item; + + return null; //no more items } } diff --git a/src/SharpCompress/Archives/Rar/StreamRarArchiveVolume.cs b/src/SharpCompress/Archives/Rar/StreamRarArchiveVolume.cs index 236c64e2..3eb5095c 100644 --- a/src/SharpCompress/Archives/Rar/StreamRarArchiveVolume.cs +++ b/src/SharpCompress/Archives/Rar/StreamRarArchiveVolume.cs @@ -12,13 +12,8 @@ internal class StreamRarArchiveVolume : RarVolume internal StreamRarArchiveVolume(Stream stream, ReaderOptions options, int index = 0) : base(StreamingMode.Seekable, stream, options, index) { } - internal override IEnumerable ReadFileParts() - { - return GetVolumeFileParts(); - } + internal override IEnumerable ReadFileParts() => GetVolumeFileParts(); - internal override RarFilePart CreateFilePart(MarkHeader markHeader, FileHeader fileHeader) - { - return new SeekableFilePart(markHeader, fileHeader, Index, Stream, ReaderOptions.Password); - } + internal override RarFilePart CreateFilePart(MarkHeader markHeader, FileHeader fileHeader) => + new SeekableFilePart(markHeader, fileHeader, Index, Stream, ReaderOptions.Password); } diff --git a/src/SharpCompress/Archives/SevenZip/SevenZipArchive.cs b/src/SharpCompress/Archives/SevenZip/SevenZipArchive.cs index c49bd550..8bb782f0 100644 --- a/src/SharpCompress/Archives/SevenZip/SevenZipArchive.cs +++ b/src/SharpCompress/Archives/SevenZip/SevenZipArchive.cs @@ -113,10 +113,7 @@ public class SevenZipArchive : AbstractArchive IsSevenZipFile(new FileInfo(filePath)); public static bool IsSevenZipFile(FileInfo fileInfo) { @@ -191,18 +188,11 @@ public class SevenZipArchive : AbstractArchive + new SevenZipReader(ReaderOptions, this); - public override bool IsSolid - { - get - { - return Entries.Where(x => !x.IsDirectory).GroupBy(x => x.FilePart.Folder).Count() > 1; - } - } + public override bool IsSolid => + Entries.Where(x => !x.IsDirectory).GroupBy(x => x.FilePart.Folder).Count() > 1; public override long TotalSize { @@ -221,10 +211,7 @@ public class SevenZipArchive : AbstractArchive this.archive = archive; public override SevenZipVolume Volume => archive.Volumes.Single(); @@ -261,24 +248,16 @@ public class SevenZipArchive : AbstractArchive + CreateEntryStream(new ReadOnlySubStream(currentStream, currentItem.Size)); } private class PasswordProvider : IPasswordProvider { private readonly string _password; - public PasswordProvider(string password) - { - _password = password; - } + public PasswordProvider(string password) => _password = password; - public string CryptoGetTextPassword() - { - return _password; - } + public string CryptoGetTextPassword() => _password; } } diff --git a/src/SharpCompress/Archives/SevenZip/SevenZipArchiveEntry.cs b/src/SharpCompress/Archives/SevenZip/SevenZipArchiveEntry.cs index 9f8c9654..4e30f18e 100644 --- a/src/SharpCompress/Archives/SevenZip/SevenZipArchiveEntry.cs +++ b/src/SharpCompress/Archives/SevenZip/SevenZipArchiveEntry.cs @@ -1,19 +1,14 @@ -using System.IO; +using System.IO; using SharpCompress.Common.SevenZip; namespace SharpCompress.Archives.SevenZip; public class SevenZipArchiveEntry : SevenZipEntry, IArchiveEntry { - internal SevenZipArchiveEntry(SevenZipArchive archive, SevenZipFilePart part) : base(part) - { + internal SevenZipArchiveEntry(SevenZipArchive archive, SevenZipFilePart part) : base(part) => Archive = archive; - } - public Stream OpenEntryStream() - { - return FilePart.GetCompressedStream(); - } + public Stream OpenEntryStream() => FilePart.GetCompressedStream(); public IArchive Archive { get; } diff --git a/src/SharpCompress/Archives/Tar/TarArchive.cs b/src/SharpCompress/Archives/Tar/TarArchive.cs index cb808761..218eda42 100644 --- a/src/SharpCompress/Archives/Tar/TarArchive.cs +++ b/src/SharpCompress/Archives/Tar/TarArchive.cs @@ -95,10 +95,7 @@ public class TarArchive : AbstractWritableArchive ); } - public static bool IsTarFile(string filePath) - { - return IsTarFile(new FileInfo(filePath)); - } + public static bool IsTarFile(string filePath) => IsTarFile(new FileInfo(filePath)); public static bool IsTarFile(FileInfo fileInfo) { @@ -196,10 +193,7 @@ public class TarArchive : AbstractWritableArchive } } - public static TarArchive Create() - { - return new TarArchive(); - } + public static TarArchive Create() => new TarArchive(); protected override TarArchiveEntry CreateEntryInternal( string filePath, @@ -207,9 +201,8 @@ public class TarArchive : AbstractWritableArchive long size, DateTime? modified, bool closeStream - ) - { - return new TarWritableArchiveEntry( + ) => + new TarWritableArchiveEntry( this, source, CompressionType.Unknown, @@ -218,7 +211,6 @@ public class TarArchive : AbstractWritableArchive modified, closeStream ); - } protected override void SaveTo( Stream stream, diff --git a/src/SharpCompress/Archives/Tar/TarArchiveEntry.cs b/src/SharpCompress/Archives/Tar/TarArchiveEntry.cs index eee8ed7a..2da84d71 100644 --- a/src/SharpCompress/Archives/Tar/TarArchiveEntry.cs +++ b/src/SharpCompress/Archives/Tar/TarArchiveEntry.cs @@ -1,4 +1,4 @@ -using System.IO; +using System.IO; using System.Linq; using SharpCompress.Common; using SharpCompress.Common.Tar; @@ -8,15 +8,9 @@ namespace SharpCompress.Archives.Tar; public class TarArchiveEntry : TarEntry, IArchiveEntry { internal TarArchiveEntry(TarArchive archive, TarFilePart part, CompressionType compressionType) - : base(part, compressionType) - { - Archive = archive; - } + : base(part, compressionType) => Archive = archive; - public virtual Stream OpenEntryStream() - { - return Parts.Single().GetCompressedStream(); - } + public virtual Stream OpenEntryStream() => Parts.Single().GetCompressedStream(); #region IArchiveEntry Members diff --git a/src/SharpCompress/Archives/Zip/ZipArchive.cs b/src/SharpCompress/Archives/Zip/ZipArchive.cs index ba3ccdb9..99a66161 100644 --- a/src/SharpCompress/Archives/Zip/ZipArchive.cs +++ b/src/SharpCompress/Archives/Zip/ZipArchive.cs @@ -32,13 +32,11 @@ public class ZipArchive : AbstractWritableArchive /// /// /// - internal ZipArchive(SourceStream srcStream) : base(ArchiveType.Zip, srcStream) - { + internal ZipArchive(SourceStream srcStream) : base(ArchiveType.Zip, srcStream) => headerFactory = new SeekableZipHeaderFactory( srcStream.ReaderOptions.Password, srcStream.ReaderOptions.ArchiveEncoding ); - } /// /// Constructor expects a filepath to an existing file. @@ -120,10 +118,8 @@ public class ZipArchive : AbstractWritableArchive ); } - public static bool IsZipFile(string filePath, string? password = null) - { - return IsZipFile(new FileInfo(filePath), password); - } + public static bool IsZipFile(string filePath, string? password = null) => + IsZipFile(new FileInfo(filePath), password); public static bool IsZipFile(FileInfo fileInfo, string? password = null) { @@ -271,10 +267,7 @@ public class ZipArchive : AbstractWritableArchive } } - public void SaveTo(Stream stream) - { - SaveTo(stream, new WriterOptions(CompressionType.Deflate)); - } + public void SaveTo(Stream stream) => SaveTo(stream, new WriterOptions(CompressionType.Deflate)); protected override void SaveTo( Stream stream, @@ -297,15 +290,9 @@ public class ZipArchive : AbstractWritableArchive long size, DateTime? modified, bool closeStream - ) - { - return new ZipWritableArchiveEntry(this, source, filePath, size, modified, closeStream); - } + ) => new ZipWritableArchiveEntry(this, source, filePath, size, modified, closeStream); - public static ZipArchive Create() - { - return new ZipArchive(); - } + public static ZipArchive Create() => new ZipArchive(); protected override IReader CreateReaderForSolidExtraction() { diff --git a/src/SharpCompress/Archives/Zip/ZipArchiveEntry.cs b/src/SharpCompress/Archives/Zip/ZipArchiveEntry.cs index 5059f61a..59e30fd8 100644 --- a/src/SharpCompress/Archives/Zip/ZipArchiveEntry.cs +++ b/src/SharpCompress/Archives/Zip/ZipArchiveEntry.cs @@ -1,4 +1,4 @@ -using System.IO; +using System.IO; using System.Linq; using SharpCompress.Common.Zip; @@ -6,15 +6,10 @@ namespace SharpCompress.Archives.Zip; public class ZipArchiveEntry : ZipEntry, IArchiveEntry { - internal ZipArchiveEntry(ZipArchive archive, SeekableZipFilePart? part) : base(part) - { + internal ZipArchiveEntry(ZipArchive archive, SeekableZipFilePart? part) : base(part) => Archive = archive; - } - public virtual Stream OpenEntryStream() - { - return Parts.Single().GetCompressedStream(); - } + public virtual Stream OpenEntryStream() => Parts.Single().GetCompressedStream(); #region IArchiveEntry Members diff --git a/src/SharpCompress/Archives/Zip/ZipArchiveVolumeFactory.cs b/src/SharpCompress/Archives/Zip/ZipArchiveVolumeFactory.cs index e38e4af1..fdaa85b9 100644 --- a/src/SharpCompress/Archives/Zip/ZipArchiveVolumeFactory.cs +++ b/src/SharpCompress/Archives/Zip/ZipArchiveVolumeFactory.cs @@ -1,46 +1,35 @@ using System; -using System.Collections.Generic; using System.IO; -using SharpCompress.Common.Rar; -using SharpCompress.Readers; -using System.Linq; -using System.Text; -using SharpCompress.Common.Rar.Headers; using System.Text.RegularExpressions; -namespace SharpCompress.Archives.Zip +namespace SharpCompress.Archives.Zip; + +internal static class ZipArchiveVolumeFactory { - internal static class ZipArchiveVolumeFactory + internal static FileInfo? GetFilePart(int index, FileInfo part1) //base the name on the first part { - internal static FileInfo? GetFilePart(int index, FileInfo part1) //base the name on the first part - { - FileInfo? item = null; + FileInfo? item = null; - //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 - ); - if (m.Success) - item = new FileInfo( - Path.Combine( - part1.DirectoryName!, - String.Concat( - m.Groups[1].Value, - Regex.Replace(m.Groups[2].Value, @"[^xz]", ""), - index.ToString().PadLeft(2, '0') - ) + //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); + if (m.Success) + item = new FileInfo( + Path.Combine( + part1.DirectoryName!, + String.Concat( + m.Groups[1].Value, + Regex.Replace(m.Groups[2].Value, @"[^xz]", ""), + index.ToString().PadLeft(2, '0') ) - ); - else //split - 001, 002 ... - return ArchiveVolumeFactory.GetFilePart(index, part1); + ) + ); + else //split - 001, 002 ... + return ArchiveVolumeFactory.GetFilePart(index, part1); - if (item != null && item.Exists) - return item; + if (item != null && item.Exists) + return item; - return null; //no more items - } + return null; //no more items } } diff --git a/src/SharpCompress/Common/ArchiveEncoding.cs b/src/SharpCompress/Common/ArchiveEncoding.cs index a5ee35b2..53848ef7 100644 --- a/src/SharpCompress/Common/ArchiveEncoding.cs +++ b/src/SharpCompress/Common/ArchiveEncoding.cs @@ -35,40 +35,20 @@ public class ArchiveEncoding } #if !NETFRAMEWORK - static ArchiveEncoding() - { - Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); - } + static ArchiveEncoding() => Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); #endif - public string Decode(byte[] bytes) - { - return Decode(bytes, 0, bytes.Length); - } + public string Decode(byte[] bytes) => Decode(bytes, 0, bytes.Length); - public string Decode(byte[] bytes, int start, int length) - { - return GetDecoder().Invoke(bytes, start, length); - } + public string Decode(byte[] bytes, int start, int length) => + GetDecoder().Invoke(bytes, start, length); - public string DecodeUTF8(byte[] bytes) - { - return Encoding.UTF8.GetString(bytes, 0, bytes.Length); - } + public string DecodeUTF8(byte[] bytes) => Encoding.UTF8.GetString(bytes, 0, bytes.Length); - public byte[] Encode(string str) - { - return GetEncoding().GetBytes(str); - } + public byte[] Encode(string str) => GetEncoding().GetBytes(str); - public Encoding GetEncoding() - { - return Forced ?? Default ?? Encoding.UTF8; - } + public Encoding GetEncoding() => Forced ?? Default ?? Encoding.UTF8; - public Func GetDecoder() - { - return CustomDecoder - ?? ((bytes, index, count) => GetEncoding().GetString(bytes, index, count)); - } + public Func GetDecoder() => + CustomDecoder ?? ((bytes, index, count) => GetEncoding().GetString(bytes, index, count)); } diff --git a/src/SharpCompress/Common/ArchiveExtractionEventArgs.cs b/src/SharpCompress/Common/ArchiveExtractionEventArgs.cs index 74d419a3..80817748 100644 --- a/src/SharpCompress/Common/ArchiveExtractionEventArgs.cs +++ b/src/SharpCompress/Common/ArchiveExtractionEventArgs.cs @@ -1,13 +1,10 @@ -using System; +using System; namespace SharpCompress.Common; public class ArchiveExtractionEventArgs : EventArgs { - internal ArchiveExtractionEventArgs(T entry) - { - Item = entry; - } + internal ArchiveExtractionEventArgs(T entry) => Item = entry; public T Item { get; } } diff --git a/src/SharpCompress/Common/EntryStream.cs b/src/SharpCompress/Common/EntryStream.cs index 6dcac04b..b3e7edea 100644 --- a/src/SharpCompress/Common/EntryStream.cs +++ b/src/SharpCompress/Common/EntryStream.cs @@ -77,18 +77,10 @@ public class EntryStream : Stream return value; } - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } + public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException(); - public override void SetLength(long value) - { - throw new NotSupportedException(); - } + public override void SetLength(long value) => throw new NotSupportedException(); - public override void Write(byte[] buffer, int offset, int count) - { + public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException(); - } } diff --git a/src/SharpCompress/Common/ExtractionMethods.cs b/src/SharpCompress/Common/ExtractionMethods.cs index 390a409b..c8e5896e 100644 --- a/src/SharpCompress/Common/ExtractionMethods.cs +++ b/src/SharpCompress/Common/ExtractionMethods.cs @@ -1,120 +1,117 @@ using System; using System.IO; -namespace SharpCompress.Common +namespace SharpCompress.Common; + +internal static class ExtractionMethods { - internal static class ExtractionMethods + /// + /// Extract to specific directory, retaining filename + /// + public static void WriteEntryToDirectory( + IEntry entry, + string destinationDirectory, + ExtractionOptions? options, + Action write + ) { - /// - /// Extract to specific directory, retaining filename - /// - public static void WriteEntryToDirectory( - IEntry entry, - string destinationDirectory, - ExtractionOptions? options, - Action write + string destinationFileName; + string fullDestinationDirectoryPath = Path.GetFullPath(destinationDirectory); + + //check for trailing slash. + if ( + fullDestinationDirectoryPath[fullDestinationDirectoryPath.Length - 1] + != Path.DirectorySeparatorChar ) { - string destinationFileName; - string fullDestinationDirectoryPath = Path.GetFullPath(destinationDirectory); - - //check for trailing slash. - if ( - fullDestinationDirectoryPath[fullDestinationDirectoryPath.Length - 1] - != Path.DirectorySeparatorChar - ) - { - fullDestinationDirectoryPath += Path.DirectorySeparatorChar; - } - - if (!Directory.Exists(fullDestinationDirectoryPath)) - { - throw new ExtractionException( - $"Directory does not exist to extract to: {fullDestinationDirectoryPath}" - ); - } - - options ??= new ExtractionOptions() { Overwrite = true }; - - string file = Path.GetFileName(entry.Key); - if (options.ExtractFullPath) - { - string folder = Path.GetDirectoryName(entry.Key)!; - string destdir = Path.GetFullPath( - Path.Combine(fullDestinationDirectoryPath, folder) - ); - - if (!Directory.Exists(destdir)) - { - if (!destdir.StartsWith(fullDestinationDirectoryPath, StringComparison.Ordinal)) - { - throw new ExtractionException( - "Entry is trying to create a directory outside of the destination directory." - ); - } - - Directory.CreateDirectory(destdir); - } - destinationFileName = Path.Combine(destdir, file); - } - else - { - destinationFileName = Path.Combine(fullDestinationDirectoryPath, file); - } - - if (!entry.IsDirectory) - { - destinationFileName = Path.GetFullPath(destinationFileName); - - if ( - !destinationFileName.StartsWith( - fullDestinationDirectoryPath, - StringComparison.Ordinal - ) - ) - { - throw new ExtractionException( - "Entry is trying to write a file outside of the destination directory." - ); - } - write(destinationFileName, options); - } - else if (options.ExtractFullPath && !Directory.Exists(destinationFileName)) - { - Directory.CreateDirectory(destinationFileName); - } + fullDestinationDirectoryPath += Path.DirectorySeparatorChar; } - public static void WriteEntryToFile( - IEntry entry, - string destinationFileName, - ExtractionOptions? options, - Action openAndWrite - ) + if (!Directory.Exists(fullDestinationDirectoryPath)) { - if (entry.LinkTarget != null) + throw new ExtractionException( + $"Directory does not exist to extract to: {fullDestinationDirectoryPath}" + ); + } + + options ??= new ExtractionOptions() { Overwrite = true }; + + string file = Path.GetFileName(entry.Key); + if (options.ExtractFullPath) + { + string folder = Path.GetDirectoryName(entry.Key)!; + string destdir = Path.GetFullPath(Path.Combine(fullDestinationDirectoryPath, folder)); + + if (!Directory.Exists(destdir)) { - if (options?.WriteSymbolicLink is null) + if (!destdir.StartsWith(fullDestinationDirectoryPath, StringComparison.Ordinal)) { throw new ExtractionException( - "Entry is a symbolic link but ExtractionOptions.WriteSymbolicLink delegate is null" + "Entry is trying to create a directory outside of the destination directory." ); } - options.WriteSymbolicLink(destinationFileName, entry.LinkTarget); + + Directory.CreateDirectory(destdir); } - else + destinationFileName = Path.Combine(destdir, file); + } + else + { + destinationFileName = Path.Combine(fullDestinationDirectoryPath, file); + } + + if (!entry.IsDirectory) + { + destinationFileName = Path.GetFullPath(destinationFileName); + + if ( + !destinationFileName.StartsWith( + fullDestinationDirectoryPath, + StringComparison.Ordinal + ) + ) { - FileMode fm = FileMode.Create; - options ??= new ExtractionOptions() { Overwrite = true }; - - if (!options.Overwrite) - { - fm = FileMode.CreateNew; - } - - openAndWrite(destinationFileName, fm); - entry.PreserveExtractionOptions(destinationFileName, options); + throw new ExtractionException( + "Entry is trying to write a file outside of the destination directory." + ); } + write(destinationFileName, options); + } + else if (options.ExtractFullPath && !Directory.Exists(destinationFileName)) + { + Directory.CreateDirectory(destinationFileName); + } + } + + public static void WriteEntryToFile( + IEntry entry, + string destinationFileName, + ExtractionOptions? options, + Action openAndWrite + ) + { + if (entry.LinkTarget != null) + { + if (options?.WriteSymbolicLink is null) + { + throw new ExtractionException( + "Entry is a symbolic link but ExtractionOptions.WriteSymbolicLink delegate is null" + ); + } + options.WriteSymbolicLink(destinationFileName, entry.LinkTarget); + } + else + { + FileMode fm = FileMode.Create; + options ??= new ExtractionOptions() { Overwrite = true }; + + if (!options.Overwrite) + { + fm = FileMode.CreateNew; + } + + openAndWrite(destinationFileName, fm); + entry.PreserveExtractionOptions(destinationFileName, options); } } } diff --git a/src/SharpCompress/Common/FilePart.cs b/src/SharpCompress/Common/FilePart.cs index e196618f..3c286d54 100644 --- a/src/SharpCompress/Common/FilePart.cs +++ b/src/SharpCompress/Common/FilePart.cs @@ -4,10 +4,7 @@ namespace SharpCompress.Common; public abstract class FilePart { - protected FilePart(ArchiveEncoding archiveEncoding) - { - ArchiveEncoding = archiveEncoding; - } + protected FilePart(ArchiveEncoding archiveEncoding) => ArchiveEncoding = archiveEncoding; internal ArchiveEncoding ArchiveEncoding { get; } diff --git a/src/SharpCompress/Common/FlagUtility.cs b/src/SharpCompress/Common/FlagUtility.cs index 63cad03b..73215817 100644 --- a/src/SharpCompress/Common/FlagUtility.cs +++ b/src/SharpCompress/Common/FlagUtility.cs @@ -1,4 +1,4 @@ -using System; +using System; namespace SharpCompress.Common; @@ -12,10 +12,8 @@ internal static class FlagUtility /// Flagged variable /// Flag to test /// - public static bool HasFlag(long bitField, T flag) where T : struct - { - return HasFlag(bitField, flag); - } + public static bool HasFlag(long bitField, T flag) where T : struct => + HasFlag(bitField, flag); /// /// Returns true if the flag is set on the specified bit field. @@ -25,10 +23,8 @@ internal static class FlagUtility /// Flagged variable /// Flag to test /// - public static bool HasFlag(ulong bitField, T flag) where T : struct - { - return HasFlag(bitField, flag); - } + public static bool HasFlag(ulong bitField, T flag) where T : struct => + HasFlag(bitField, flag); /// /// Returns true if the flag is set on the specified bit field. @@ -37,15 +33,9 @@ internal static class FlagUtility /// Flagged variable /// Flag to test /// - public static bool HasFlag(ulong bitField, ulong flag) - { - return ((bitField & flag) == flag); - } + public static bool HasFlag(ulong bitField, ulong flag) => ((bitField & flag) == flag); - public static bool HasFlag(short bitField, short flag) - { - return ((bitField & flag) == flag); - } + public static bool HasFlag(short bitField, short flag) => ((bitField & flag) == flag); /// /// Returns true if the flag is set on the specified bit field. @@ -55,10 +45,8 @@ internal static class FlagUtility /// Flagged variable /// Flag to test /// - public static bool HasFlag(T bitField, T flag) where T : struct - { - return HasFlag(Convert.ToInt64(bitField), Convert.ToInt64(flag)); - } + public static bool HasFlag(T bitField, T flag) where T : struct => + HasFlag(Convert.ToInt64(bitField), Convert.ToInt64(flag)); /// /// Returns true if the flag is set on the specified bit field. @@ -67,10 +55,7 @@ internal static class FlagUtility /// Flagged variable /// Flag to test /// - public static bool HasFlag(long bitField, long flag) - { - return ((bitField & flag) == flag); - } + public static bool HasFlag(long bitField, long flag) => ((bitField & flag) == flag); /// /// Sets a bit-field to either on or off for the specified flag. @@ -96,8 +81,6 @@ internal static class FlagUtility /// Flag to change /// bool /// The flagged variable with the flag changed - public static long SetFlag(T bitField, T flag, bool on) where T : struct - { - return SetFlag(Convert.ToInt64(bitField), Convert.ToInt64(flag), on); - } + public static long SetFlag(T bitField, T flag, bool on) where T : struct => + SetFlag(Convert.ToInt64(bitField), Convert.ToInt64(flag), on); } diff --git a/src/SharpCompress/Common/GZip/GZipEntry.cs b/src/SharpCompress/Common/GZip/GZipEntry.cs index ec16c979..bb9a22da 100644 --- a/src/SharpCompress/Common/GZip/GZipEntry.cs +++ b/src/SharpCompress/Common/GZip/GZipEntry.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.IO; @@ -8,10 +8,7 @@ public class GZipEntry : Entry { private readonly GZipFilePart _filePart; - internal GZipEntry(GZipFilePart filePart) - { - _filePart = filePart; - } + internal GZipEntry(GZipFilePart filePart) => _filePart = filePart; public override CompressionType CompressionType => CompressionType.GZip; diff --git a/src/SharpCompress/Common/GZip/GZipFilePart.cs b/src/SharpCompress/Common/GZip/GZipFilePart.cs index 04cfc355..0dd9a2d1 100644 --- a/src/SharpCompress/Common/GZip/GZipFilePart.cs +++ b/src/SharpCompress/Common/GZip/GZipFilePart.cs @@ -35,15 +35,10 @@ internal sealed class GZipFilePart : FilePart internal override string FilePartName => _name!; - internal override Stream GetCompressedStream() - { - return new DeflateStream(_stream, CompressionMode.Decompress, CompressionLevel.Default); - } + internal override Stream GetCompressedStream() => + new DeflateStream(_stream, CompressionMode.Decompress, CompressionLevel.Default); - internal override Stream GetRawStream() - { - return _stream; - } + internal override Stream GetRawStream() => _stream; private void ReadTrailer() { diff --git a/src/SharpCompress/Common/GZip/GZipVolume.cs b/src/SharpCompress/Common/GZip/GZipVolume.cs index e13abd8c..0dd9b8d9 100644 --- a/src/SharpCompress/Common/GZip/GZipVolume.cs +++ b/src/SharpCompress/Common/GZip/GZipVolume.cs @@ -8,10 +8,8 @@ public class GZipVolume : Volume public GZipVolume(Stream stream, ReaderOptions options, int index = 0) : base(stream, options, index) { } - public GZipVolume(FileInfo fileInfo, ReaderOptions options) : base(fileInfo.OpenRead(), options) - { - options.LeaveStreamOpen = false; - } + public GZipVolume(FileInfo fileInfo, ReaderOptions options) + : base(fileInfo.OpenRead(), options) => options.LeaveStreamOpen = false; public override bool IsFirstVolume => true; diff --git a/src/SharpCompress/Common/Rar/Headers/ArchiveHeader.cs b/src/SharpCompress/Common/Rar/Headers/ArchiveHeader.cs index c46ffa84..e8f344ad 100644 --- a/src/SharpCompress/Common/Rar/Headers/ArchiveHeader.cs +++ b/src/SharpCompress/Common/Rar/Headers/ArchiveHeader.cs @@ -35,10 +35,7 @@ internal sealed class ArchiveHeader : RarHeader private ushort Flags { get; set; } - private bool HasFlag(ushort flag) - { - return (Flags & flag) == flag; - } + private bool HasFlag(ushort flag) => (Flags & flag) == flag; internal int? VolumeNumber { get; private set; } diff --git a/src/SharpCompress/Common/Rar/Headers/EndArchiveHeader.cs b/src/SharpCompress/Common/Rar/Headers/EndArchiveHeader.cs index 10c79850..f5bc4523 100644 --- a/src/SharpCompress/Common/Rar/Headers/EndArchiveHeader.cs +++ b/src/SharpCompress/Common/Rar/Headers/EndArchiveHeader.cs @@ -1,4 +1,4 @@ -using SharpCompress.IO; +using SharpCompress.IO; namespace SharpCompress.Common.Rar.Headers; @@ -29,10 +29,7 @@ internal class EndArchiveHeader : RarHeader private ushort Flags { get; set; } - private bool HasFlag(ushort flag) - { - return (Flags & flag) == flag; - } + private bool HasFlag(ushort flag) => (Flags & flag) == flag; internal int? ArchiveCrc { get; private set; } diff --git a/src/SharpCompress/Common/Rar/Headers/FileHeader.cs b/src/SharpCompress/Common/Rar/Headers/FileHeader.cs index d0f7450b..e95052ef 100644 --- a/src/SharpCompress/Common/Rar/Headers/FileHeader.cs +++ b/src/SharpCompress/Common/Rar/Headers/FileHeader.cs @@ -389,17 +389,11 @@ internal class FileHeader : RarHeader return path; } - public override string ToString() - { - return FileName; - } + public override string ToString() => FileName; private ushort Flags { get; set; } - private bool HasFlag(ushort flag) - { - return (Flags & flag) == flag; - } + private bool HasFlag(ushort flag) => (Flags & flag) == flag; internal uint FileCrc { diff --git a/src/SharpCompress/Common/Rar/Headers/FileNameDecoder.cs b/src/SharpCompress/Common/Rar/Headers/FileNameDecoder.cs index d6447b49..38bdb3df 100644 --- a/src/SharpCompress/Common/Rar/Headers/FileNameDecoder.cs +++ b/src/SharpCompress/Common/Rar/Headers/FileNameDecoder.cs @@ -7,10 +7,7 @@ namespace SharpCompress.Common.Rar.Headers; /// internal static class FileNameDecoder { - internal static int GetChar(byte[] name, int pos) - { - return name[pos] & 0xff; - } + internal static int GetChar(byte[] name, int pos) => name[pos] & 0xff; internal static string Decode(byte[] name, int encPos) { diff --git a/src/SharpCompress/Common/Rar/Headers/MarkHeader.cs b/src/SharpCompress/Common/Rar/Headers/MarkHeader.cs index d359aef4..9ca0f9b2 100644 --- a/src/SharpCompress/Common/Rar/Headers/MarkHeader.cs +++ b/src/SharpCompress/Common/Rar/Headers/MarkHeader.cs @@ -11,10 +11,7 @@ internal class MarkHeader : IRarHeader public bool IsRar5 { get; } - private MarkHeader(bool isRar5) - { - IsRar5 = isRar5; - } + private MarkHeader(bool isRar5) => IsRar5 = isRar5; public HeaderType HeaderType => HeaderType.Mark; diff --git a/src/SharpCompress/Common/Rar/Headers/NewSubHeaderType.cs b/src/SharpCompress/Common/Rar/Headers/NewSubHeaderType.cs index 01b2ffc0..b45f98bb 100644 --- a/src/SharpCompress/Common/Rar/Headers/NewSubHeaderType.cs +++ b/src/SharpCompress/Common/Rar/Headers/NewSubHeaderType.cs @@ -1,4 +1,4 @@ -using System; +using System; namespace SharpCompress.Common.Rar.Headers; @@ -41,8 +41,5 @@ internal sealed class NewSubHeaderType : IEquatable return _bytes.AsSpan().SequenceEqual(bytes); } - public bool Equals(NewSubHeaderType? other) - { - return other is not null && Equals(other._bytes); - } + public bool Equals(NewSubHeaderType? other) => other is not null && Equals(other._bytes); } diff --git a/src/SharpCompress/Common/Rar/Headers/RarHeader.cs b/src/SharpCompress/Common/Rar/Headers/RarHeader.cs index 571da972..81002fc4 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; @@ -87,15 +87,11 @@ internal class RarHeader : IRarHeader VerifyHeaderCrc(reader.GetCrc32()); } - protected int RemainingHeaderBytes(MarkingBinaryReader reader) - { - return checked(HeaderSize - (int)reader.CurrentReadByteCount); - } + protected int RemainingHeaderBytes(MarkingBinaryReader reader) => + checked(HeaderSize - (int)reader.CurrentReadByteCount); - protected virtual void ReadFinish(MarkingBinaryReader reader) - { + protected virtual void ReadFinish(MarkingBinaryReader reader) => throw new NotImplementedException(); - } private void VerifyHeaderCrc(uint crc32) { @@ -116,10 +112,7 @@ internal class RarHeader : IRarHeader protected ushort HeaderFlags { get; } - protected bool HasHeaderFlag(ushort flag) - { - return (HeaderFlags & flag) == flag; - } + protected bool HasHeaderFlag(ushort flag) => (HeaderFlags & flag) == flag; protected int HeaderSize { get; } diff --git a/src/SharpCompress/Common/Rar/RarCrcBinaryReader.cs b/src/SharpCompress/Common/Rar/RarCrcBinaryReader.cs index 586b9a8f..97a8aaa9 100644 --- a/src/SharpCompress/Common/Rar/RarCrcBinaryReader.cs +++ b/src/SharpCompress/Common/Rar/RarCrcBinaryReader.cs @@ -10,25 +10,13 @@ internal class RarCrcBinaryReader : MarkingBinaryReader public RarCrcBinaryReader(Stream stream) : base(stream) { } - public uint GetCrc32() - { - return ~_currentCrc; - } + public uint GetCrc32() => ~_currentCrc; - public void ResetCrc() - { - _currentCrc = 0xffffffff; - } + public void ResetCrc() => _currentCrc = 0xffffffff; - protected void UpdateCrc(byte b) - { - _currentCrc = RarCRC.CheckCrc(_currentCrc, b); - } + protected void UpdateCrc(byte b) => _currentCrc = RarCRC.CheckCrc(_currentCrc, b); - protected byte[] ReadBytesNoCrc(int count) - { - return base.ReadBytes(count); - } + protected byte[] ReadBytesNoCrc(int count) => base.ReadBytes(count); public override byte ReadByte() { diff --git a/src/SharpCompress/Common/Rar/RarCryptoBinaryReader.cs b/src/SharpCompress/Common/Rar/RarCryptoBinaryReader.cs index d02750ed..71902fdf 100644 --- a/src/SharpCompress/Common/Rar/RarCryptoBinaryReader.cs +++ b/src/SharpCompress/Common/Rar/RarCryptoBinaryReader.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.IO; namespace SharpCompress.Common.Rar; @@ -33,10 +33,7 @@ internal sealed class RarCryptoBinaryReader : RarCrcBinaryReader } } - public override void Mark() - { - _readCount = 0; - } + public override void Mark() => _readCount = 0; private bool UseEncryption => _salt != null; @@ -95,10 +92,7 @@ internal sealed class RarCryptoBinaryReader : RarCrcBinaryReader return decryptedBytes; } - public void ClearQueue() - { - _data.Clear(); - } + public void ClearQueue() => _data.Clear(); public void SkipQueue() { diff --git a/src/SharpCompress/Common/Rar/RarCryptoWrapper.cs b/src/SharpCompress/Common/Rar/RarCryptoWrapper.cs index 385ed2a0..e92056b4 100644 --- a/src/SharpCompress/Common/Rar/RarCryptoWrapper.cs +++ b/src/SharpCompress/Common/Rar/RarCryptoWrapper.cs @@ -18,20 +18,11 @@ internal sealed class RarCryptoWrapper : Stream _rijndael = RarRijndael.InitializeFrom(password, salt); } - public override void Flush() - { - throw new NotSupportedException(); - } + public override void Flush() => throw new NotSupportedException(); - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } + public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException(); - public override void SetLength(long value) - { - throw new NotSupportedException(); - } + public override void SetLength(long value) => throw new NotSupportedException(); public override int Read(byte[] buffer, int offset, int count) { @@ -71,10 +62,8 @@ internal sealed class RarCryptoWrapper : Stream return count; } - public override void Write(byte[] buffer, int offset, int count) - { + public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException(); - } public override bool CanRead => true; diff --git a/src/SharpCompress/Common/Rar/RarEntry.cs b/src/SharpCompress/Common/Rar/RarEntry.cs index 54c12b8c..f3614a40 100644 --- a/src/SharpCompress/Common/Rar/RarEntry.cs +++ b/src/SharpCompress/Common/Rar/RarEntry.cs @@ -1,4 +1,4 @@ -using System; +using System; using SharpCompress.Common.Rar.Headers; namespace SharpCompress.Common.Rar; @@ -60,14 +60,12 @@ public abstract class RarEntry : Entry public override bool IsSplitAfter => FileHeader.IsSplitAfter; - public override string ToString() - { - return string.Format( + public override string ToString() => + string.Format( "Entry Path: {0} Compressed Size: {1} Uncompressed Size: {2} CRC: {3}", Key, CompressedSize, Size, Crc ); - } } diff --git a/src/SharpCompress/Common/Rar/RarFilePart.cs b/src/SharpCompress/Common/Rar/RarFilePart.cs index fa99614b..7608d0ac 100644 --- a/src/SharpCompress/Common/Rar/RarFilePart.cs +++ b/src/SharpCompress/Common/Rar/RarFilePart.cs @@ -19,8 +19,5 @@ internal abstract class RarFilePart : FilePart internal FileHeader FileHeader { get; } - internal override Stream? GetRawStream() - { - return null; - } + internal override Stream? GetRawStream() => null; } diff --git a/src/SharpCompress/Common/Rar/RarVolume.cs b/src/SharpCompress/Common/Rar/RarVolume.cs index 49c04698..7be719ec 100644 --- a/src/SharpCompress/Common/Rar/RarVolume.cs +++ b/src/SharpCompress/Common/Rar/RarVolume.cs @@ -17,10 +17,7 @@ public abstract class RarVolume : Volume internal int _maxCompressionAlgorithm; internal RarVolume(StreamingMode mode, Stream stream, ReaderOptions options, int index = 0) - : base(stream, options, index) - { - _headerFactory = new RarHeaderFactory(mode, options); - } + : base(stream, options, index) => _headerFactory = new RarHeaderFactory(mode, options); #nullable disable internal ArchiveHeader ArchiveHeader { get; private set; } diff --git a/src/SharpCompress/Common/SevenZip/ArchiveDatabase.cs b/src/SharpCompress/Common/SevenZip/ArchiveDatabase.cs index dbacf332..5e42494a 100644 --- a/src/SharpCompress/Common/SevenZip/ArchiveDatabase.cs +++ b/src/SharpCompress/Common/SevenZip/ArchiveDatabase.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable using System; using System.Collections.Generic; @@ -27,10 +27,8 @@ internal class ArchiveDatabase internal IPasswordProvider PasswordProvider { get; } - public ArchiveDatabase(IPasswordProvider passwordProvider) - { + public ArchiveDatabase(IPasswordProvider passwordProvider) => PasswordProvider = passwordProvider; - } internal void Clear() { @@ -45,14 +43,12 @@ internal class ArchiveDatabase _fileIndexToFolderIndexMap.Clear(); } - internal bool IsEmpty() - { - return _packSizes.Count == 0 - && _packCrCs.Count == 0 - && _folders.Count == 0 - && _numUnpackStreamsVector.Count == 0 - && _files.Count == 0; - } + internal bool IsEmpty() => + _packSizes.Count == 0 + && _packCrCs.Count == 0 + && _folders.Count == 0 + && _numUnpackStreamsVector.Count == 0 + && _files.Count == 0; private void FillStartPos() { diff --git a/src/SharpCompress/Common/SevenZip/ArchiveReader.cs b/src/SharpCompress/Common/SevenZip/ArchiveReader.cs index 543b5323..42b5b6b2 100644 --- a/src/SharpCompress/Common/SevenZip/ArchiveReader.cs +++ b/src/SharpCompress/Common/SevenZip/ArchiveReader.cs @@ -28,42 +28,22 @@ internal class ArchiveReader _currentReader = new DataReader(buffer, offset, length); } - internal void DeleteByteStream() - { - _currentReader = _readerStack.Pop(); - } + internal void DeleteByteStream() => _currentReader = _readerStack.Pop(); #region Private Methods - Data Reader - internal byte ReadByte() - { - return _currentReader.ReadByte(); - } + internal byte ReadByte() => _currentReader.ReadByte(); - private void ReadBytes(byte[] buffer, int offset, int length) - { + private void ReadBytes(byte[] buffer, int offset, int length) => _currentReader.ReadBytes(buffer, offset, length); - } - private ulong ReadNumber() - { - return _currentReader.ReadNumber(); - } + private ulong ReadNumber() => _currentReader.ReadNumber(); - internal int ReadNum() - { - return _currentReader.ReadNum(); - } + internal int ReadNum() => _currentReader.ReadNum(); - private uint ReadUInt32() - { - return _currentReader.ReadUInt32(); - } + private uint ReadUInt32() => _currentReader.ReadUInt32(); - private ulong ReadUInt64() - { - return _currentReader.ReadUInt64(); - } + private ulong ReadUInt64() => _currentReader.ReadUInt64(); private BlockType? ReadId() { @@ -78,15 +58,9 @@ internal class ArchiveReader return (BlockType)id; } - private void SkipData(long size) - { - _currentReader.SkipData(size); - } + private void SkipData(long size) => _currentReader.SkipData(size); - private void SkipData() - { - _currentReader.SkipData(); - } + private void SkipData() => _currentReader.SkipData(); private void WaitAttribute(BlockType attribute) { @@ -174,11 +148,9 @@ internal class ArchiveReader } } - private DateTime TranslateTime(long time) - { + private DateTime TranslateTime(long time) => // FILETIME = 100-nanosecond intervals since January 1, 1601 (UTC) - return DateTime.FromFileTimeUtc(time).ToLocalTime(); - } + DateTime.FromFileTimeUtc(time).ToLocalTime(); private DateTime? TranslateTime(long? time) { @@ -193,14 +165,12 @@ internal class ArchiveReader List dataVector, int numFiles, Action action - ) - { + ) => ReadNumberVector( dataVector, numFiles, (index, value) => action(index, TranslateTime(value)) ); - } private void ReadAttributeVector( List dataVector, @@ -1423,10 +1393,7 @@ internal class ArchiveReader public override bool CanWrite => false; - public override void Flush() - { - throw new NotSupportedException(); - } + public override void Flush() => throw new NotSupportedException(); public override long Length => throw new NotSupportedException(); @@ -1436,20 +1403,13 @@ internal class ArchiveReader set => throw new NotSupportedException(); } - public override int Read(byte[] buffer, int offset, int count) - { + public override int Read(byte[] buffer, int offset, int count) => throw new NotSupportedException(); - } - public override long Seek(long offset, SeekOrigin origin) - { + public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException(); - } - public override void SetLength(long value) - { - throw new NotSupportedException(); - } + public override void SetLength(long value) => throw new NotSupportedException(); private Stream _stream; private long _rem; @@ -1669,15 +1629,9 @@ internal class ArchiveReader } } - public IEnumerable GetFiles(ArchiveDatabase db) - { - return db._files; - } + public IEnumerable GetFiles(ArchiveDatabase db) => db._files; - public int GetFileIndex(ArchiveDatabase db, CFileItem item) - { - return db._files.IndexOf(item); - } + public int GetFileIndex(ArchiveDatabase db, CFileItem item) => db._files.IndexOf(item); #endregion } diff --git a/src/SharpCompress/Common/SevenZip/CFileItem.cs b/src/SharpCompress/Common/SevenZip/CFileItem.cs index f83019fe..c6509ee0 100644 --- a/src/SharpCompress/Common/SevenZip/CFileItem.cs +++ b/src/SharpCompress/Common/SevenZip/CFileItem.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable using System; @@ -18,10 +18,7 @@ internal class CFileItem public bool AttribDefined => Attrib != null; - public void SetAttrib(uint attrib) - { - Attrib = attrib; - } + public void SetAttrib(uint attrib) => Attrib = attrib; public DateTime? CTime { get; internal set; } public DateTime? ATime { get; internal set; } @@ -30,8 +27,5 @@ internal class CFileItem public long? StartPos { get; internal set; } public bool IsAnti { get; internal set; } - internal CFileItem() - { - HasStream = true; - } + internal CFileItem() => HasStream = true; } diff --git a/src/SharpCompress/Common/SevenZip/CMethodId.cs b/src/SharpCompress/Common/SevenZip/CMethodId.cs index 33a331c9..6dce5773 100644 --- a/src/SharpCompress/Common/SevenZip/CMethodId.cs +++ b/src/SharpCompress/Common/SevenZip/CMethodId.cs @@ -1,4 +1,4 @@ -namespace SharpCompress.Common.SevenZip; +namespace SharpCompress.Common.SevenZip; internal readonly struct CMethodId { @@ -14,35 +14,17 @@ internal readonly struct CMethodId public readonly ulong _id; - public CMethodId(ulong id) - { - _id = id; - } + public CMethodId(ulong id) => _id = id; - public override int GetHashCode() - { - return _id.GetHashCode(); - } + public override int GetHashCode() => _id.GetHashCode(); - public override bool Equals(object? obj) - { - return obj is CMethodId other && Equals(other); - } + public override bool Equals(object? obj) => obj is CMethodId other && Equals(other); - public bool Equals(CMethodId other) - { - return _id == other._id; - } + public bool Equals(CMethodId other) => _id == other._id; - public static bool operator ==(CMethodId left, CMethodId right) - { - return left._id == right._id; - } + public static bool operator ==(CMethodId left, CMethodId right) => left._id == right._id; - public static bool operator !=(CMethodId left, CMethodId right) - { - return left._id != right._id; - } + public static bool operator !=(CMethodId left, CMethodId right) => left._id != right._id; public int GetLength() { diff --git a/src/SharpCompress/Common/SevenZip/DataReader.cs b/src/SharpCompress/Common/SevenZip/DataReader.cs index 48e9dabc..f280a3c1 100644 --- a/src/SharpCompress/Common/SevenZip/DataReader.cs +++ b/src/SharpCompress/Common/SevenZip/DataReader.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; using System.Text; using SharpCompress.Compressors.LZMA; @@ -9,25 +9,21 @@ internal class DataReader { #region Static Methods - public static uint Get32(byte[] buffer, int offset) - { - return buffer[offset] - + ((uint)buffer[offset + 1] << 8) - + ((uint)buffer[offset + 2] << 16) - + ((uint)buffer[offset + 3] << 24); - } + public static uint Get32(byte[] buffer, int offset) => + buffer[offset] + + ((uint)buffer[offset + 1] << 8) + + ((uint)buffer[offset + 2] << 16) + + ((uint)buffer[offset + 3] << 24); - public static ulong Get64(byte[] buffer, int offset) - { - return buffer[offset] - + ((ulong)buffer[offset + 1] << 8) - + ((ulong)buffer[offset + 2] << 16) - + ((ulong)buffer[offset + 3] << 24) - + ((ulong)buffer[offset + 4] << 32) - + ((ulong)buffer[offset + 5] << 40) - + ((ulong)buffer[offset + 6] << 48) - + ((ulong)buffer[offset + 7] << 56); - } + public static ulong Get64(byte[] buffer, int offset) => + buffer[offset] + + ((ulong)buffer[offset + 1] << 8) + + ((ulong)buffer[offset + 2] << 16) + + ((ulong)buffer[offset + 3] << 24) + + ((ulong)buffer[offset + 4] << 32) + + ((ulong)buffer[offset + 5] << 40) + + ((ulong)buffer[offset + 6] << 48) + + ((ulong)buffer[offset + 7] << 56); #endregion @@ -85,10 +81,7 @@ internal class DataReader #endif } - public void SkipData() - { - SkipData(checked((long)ReadNumber())); - } + public void SkipData() => SkipData(checked((long)ReadNumber())); public ulong ReadNumber() { diff --git a/src/SharpCompress/Common/SevenZip/SevenZipEntry.cs b/src/SharpCompress/Common/SevenZip/SevenZipEntry.cs index 3e806681..66170ba8 100644 --- a/src/SharpCompress/Common/SevenZip/SevenZipEntry.cs +++ b/src/SharpCompress/Common/SevenZip/SevenZipEntry.cs @@ -1,14 +1,11 @@ -using System; +using System; using System.Collections.Generic; namespace SharpCompress.Common.SevenZip; public class SevenZipEntry : Entry { - internal SevenZipEntry(SevenZipFilePart filePart) - { - FilePart = filePart; - } + internal SevenZipEntry(SevenZipFilePart filePart) => FilePart = filePart; internal SevenZipFilePart FilePart { get; } diff --git a/src/SharpCompress/Common/SevenZip/SevenZipFilePart.cs b/src/SharpCompress/Common/SevenZip/SevenZipFilePart.cs index 92e375aa..7aac0ade 100644 --- a/src/SharpCompress/Common/SevenZip/SevenZipFilePart.cs +++ b/src/SharpCompress/Common/SevenZip/SevenZipFilePart.cs @@ -34,10 +34,7 @@ internal class SevenZipFilePart : FilePart internal override string FilePartName => Header.Name; - internal override Stream? GetRawStream() - { - return null; - } + internal override Stream? GetRawStream() => null; internal override Stream GetCompressedStream() { diff --git a/src/SharpCompress/Common/Tar/Headers/TarHeader.cs b/src/SharpCompress/Common/Tar/Headers/TarHeader.cs index 5ae1b806..ef86ab00 100644 --- a/src/SharpCompress/Common/Tar/Headers/TarHeader.cs +++ b/src/SharpCompress/Common/Tar/Headers/TarHeader.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable using System; using System.Buffers.Binary; @@ -11,10 +11,7 @@ internal sealed class TarHeader { internal static readonly DateTime EPOCH = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); - public TarHeader(ArchiveEncoding archiveEncoding) - { - ArchiveEncoding = archiveEncoding; - } + public TarHeader(ArchiveEncoding archiveEncoding) => ArchiveEncoding = archiveEncoding; internal string Name { get; set; } internal string LinkName { get; set; } @@ -173,10 +170,7 @@ internal sealed class TarHeader return ArchiveEncoding.Decode(nameBytes, 0, nameBytes.Length).TrimNulls(); } - private static EntryType ReadEntryType(byte[] buffer) - { - return (EntryType)buffer[156]; - } + private static EntryType ReadEntryType(byte[] buffer) => (EntryType)buffer[156]; private long ReadSize(byte[] buffer) { diff --git a/src/SharpCompress/Common/Tar/TarFilePart.cs b/src/SharpCompress/Common/Tar/TarFilePart.cs index 8fa6223f..c81f87e4 100644 --- a/src/SharpCompress/Common/Tar/TarFilePart.cs +++ b/src/SharpCompress/Common/Tar/TarFilePart.cs @@ -1,4 +1,4 @@ -using System.IO; +using System.IO; using SharpCompress.Common.Tar.Headers; namespace SharpCompress.Common.Tar; @@ -27,8 +27,5 @@ internal sealed class TarFilePart : FilePart return Header.PackedStream; } - internal override Stream? GetRawStream() - { - return null; - } + internal override Stream? GetRawStream() => null; } diff --git a/src/SharpCompress/Common/Tar/TarReadOnlySubStream.cs b/src/SharpCompress/Common/Tar/TarReadOnlySubStream.cs index 2678ebee..7ccfd238 100644 --- a/src/SharpCompress/Common/Tar/TarReadOnlySubStream.cs +++ b/src/SharpCompress/Common/Tar/TarReadOnlySubStream.cs @@ -1,111 +1,96 @@ -using SharpCompress.IO; +using SharpCompress.IO; using System; using System.IO; -namespace SharpCompress.Common.Tar +namespace SharpCompress.Common.Tar; + +internal class TarReadOnlySubStream : NonDisposingStream { - internal class TarReadOnlySubStream : NonDisposingStream + private bool _isDisposed; + private long _amountRead; + + public TarReadOnlySubStream(Stream stream, long bytesToRead) + : base(stream, throwOnDispose: false) => BytesLeftToRead = bytesToRead; + + protected override void Dispose(bool disposing) { - private bool _isDisposed; - private long _amountRead; - - public TarReadOnlySubStream(Stream stream, long bytesToRead) - : base(stream, throwOnDispose: false) + if (_isDisposed) { - BytesLeftToRead = bytesToRead; + return; } - protected override void Dispose(bool disposing) + _isDisposed = true; + + if (disposing) { - if (_isDisposed) + // Ensure we read all remaining blocks for this entry. + Stream.Skip(BytesLeftToRead); + _amountRead += BytesLeftToRead; + + // If the last block wasn't a full 512 bytes, skip the remaining padding bytes. + var bytesInLastBlock = _amountRead % 512; + + if (bytesInLastBlock != 0) { - return; + Stream.Skip(512 - bytesInLastBlock); } - - _isDisposed = true; - - if (disposing) - { - // Ensure we read all remaining blocks for this entry. - Stream.Skip(BytesLeftToRead); - _amountRead += BytesLeftToRead; - - // If the last block wasn't a full 512 bytes, skip the remaining padding bytes. - var bytesInLastBlock = _amountRead % 512; - - if (bytesInLastBlock != 0) - { - Stream.Skip(512 - bytesInLastBlock); - } - } - - base.Dispose(disposing); } - private long BytesLeftToRead { get; set; } - - public override bool CanRead => true; - - public override bool CanSeek => false; - - public override bool CanWrite => false; - - public override void Flush() - { - throw new NotSupportedException(); - } - - public override long Length => throw new NotSupportedException(); - - public override long Position - { - get => throw new NotSupportedException(); - set => throw new NotSupportedException(); - } - - public override int Read(byte[] buffer, int offset, int count) - { - if (BytesLeftToRead < count) - { - count = (int)BytesLeftToRead; - } - int read = Stream.Read(buffer, offset, count); - if (read > 0) - { - BytesLeftToRead -= read; - _amountRead += read; - } - return read; - } - - public override int ReadByte() - { - if (BytesLeftToRead <= 0) - { - return -1; - } - int value = Stream.ReadByte(); - if (value != -1) - { - --BytesLeftToRead; - ++_amountRead; - } - return value; - } - - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } - - public override void SetLength(long value) - { - throw new NotSupportedException(); - } - - public override void Write(byte[] buffer, int offset, int count) - { - throw new NotSupportedException(); - } + base.Dispose(disposing); } + + private long BytesLeftToRead { get; set; } + + public override bool CanRead => true; + + public override bool CanSeek => false; + + public override bool CanWrite => false; + + public override void Flush() => throw new NotSupportedException(); + + public override long Length => throw new NotSupportedException(); + + public override long Position + { + get => throw new NotSupportedException(); + set => throw new NotSupportedException(); + } + + public override int Read(byte[] buffer, int offset, int count) + { + if (BytesLeftToRead < count) + { + count = (int)BytesLeftToRead; + } + int read = Stream.Read(buffer, offset, count); + if (read > 0) + { + BytesLeftToRead -= read; + _amountRead += read; + } + return read; + } + + public override int ReadByte() + { + if (BytesLeftToRead <= 0) + { + return -1; + } + int value = Stream.ReadByte(); + if (value != -1) + { + --BytesLeftToRead; + ++_amountRead; + } + return value; + } + + public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException(); + + public override void SetLength(long value) => throw new NotSupportedException(); + + public override void Write(byte[] buffer, int offset, int count) => + throw new NotSupportedException(); } diff --git a/src/SharpCompress/Common/Volume.cs b/src/SharpCompress/Common/Volume.cs index 1872e65d..1f259257 100644 --- a/src/SharpCompress/Common/Volume.cs +++ b/src/SharpCompress/Common/Volume.cs @@ -32,10 +32,7 @@ public abstract class Volume : IVolume public virtual int Index { get; internal set; } - public string FileName - { - get { return (_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/LocalEntryHeaderExtraFactory.cs b/src/SharpCompress/Common/Zip/Headers/LocalEntryHeaderExtraFactory.cs index b230e9cc..80ec9b8f 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; @@ -147,9 +147,8 @@ internal sealed class Zip64ExtendedInformationExtraField : ExtraData internal static class LocalEntryHeaderExtraFactory { - internal static ExtraData Create(ExtraDataType type, ushort length, byte[] extraData) - { - return type switch + internal static ExtraData Create(ExtraDataType type, ushort length, byte[] extraData) => + type switch { ExtraDataType.UnicodePathExtraField => new ExtraUnicodePathExtraField(type, length, extraData), @@ -157,5 +156,4 @@ internal static class LocalEntryHeaderExtraFactory => new Zip64ExtendedInformationExtraField(type, length, extraData), _ => new ExtraData(type, length, extraData) }; - } } diff --git a/src/SharpCompress/Common/Zip/Headers/SplitHeader.cs b/src/SharpCompress/Common/Zip/Headers/SplitHeader.cs index 1e98517b..e151d4e5 100644 --- a/src/SharpCompress/Common/Zip/Headers/SplitHeader.cs +++ b/src/SharpCompress/Common/Zip/Headers/SplitHeader.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; namespace SharpCompress.Common.Zip.Headers; @@ -7,8 +7,5 @@ internal class SplitHeader : ZipHeader { public SplitHeader() : base(ZipHeaderType.Split) { } - internal override void Read(BinaryReader reader) - { - throw new NotImplementedException(); - } + internal override void Read(BinaryReader reader) => throw new NotImplementedException(); } diff --git a/src/SharpCompress/Common/Zip/PkwareTraditionalCryptoStream.cs b/src/SharpCompress/Common/Zip/PkwareTraditionalCryptoStream.cs index 6ca28fc6..273a7a3c 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; @@ -92,15 +92,9 @@ internal class PkwareTraditionalCryptoStream : Stream //throw new NotSupportedException(); } - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } + public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException(); - public override void SetLength(long value) - { - throw new NotSupportedException(); - } + public override void SetLength(long value) => throw new NotSupportedException(); protected override void Dispose(bool disposing) { diff --git a/src/SharpCompress/Common/Zip/StreamingZipFilePart.cs b/src/SharpCompress/Common/Zip/StreamingZipFilePart.cs index 1aaffe81..c5ed221a 100644 --- a/src/SharpCompress/Common/Zip/StreamingZipFilePart.cs +++ b/src/SharpCompress/Common/Zip/StreamingZipFilePart.cs @@ -11,10 +11,7 @@ internal sealed class StreamingZipFilePart : ZipFilePart internal StreamingZipFilePart(ZipFileEntry header, Stream stream) : base(header, stream) { } - protected override Stream CreateBaseStream() - { - return Header.PackedStream; - } + protected override Stream CreateBaseStream() => Header.PackedStream; internal override Stream GetCompressedStream() { diff --git a/src/SharpCompress/Common/Zip/WinzipAesCryptoStream.cs b/src/SharpCompress/Common/Zip/WinzipAesCryptoStream.cs index 4425af1d..093ac034 100644 --- a/src/SharpCompress/Common/Zip/WinzipAesCryptoStream.cs +++ b/src/SharpCompress/Common/Zip/WinzipAesCryptoStream.cs @@ -43,30 +43,18 @@ internal class WinzipAesCryptoStream : Stream return cipher; } - public override bool CanRead - { - get { return true; } - } + public override bool CanRead => true; - public override bool CanSeek - { - get { return false; } - } + public override bool CanSeek => false; - public override bool CanWrite - { - get { return false; } - } + public override bool CanWrite => false; - public override long Length - { - get { throw new NotSupportedException(); } - } + public override long Length => throw new NotSupportedException(); public override long Position { - get { throw new NotSupportedException(); } - set { throw new NotSupportedException(); } + get => throw new NotSupportedException(); + set => throw new NotSupportedException(); } protected override void Dispose(bool disposing) @@ -85,10 +73,7 @@ internal class WinzipAesCryptoStream : Stream } } - public override void Flush() - { - throw new NotSupportedException(); - } + public override void Flush() => throw new NotSupportedException(); public override int Read(byte[] buffer, int offset, int count) { @@ -164,18 +149,10 @@ internal class WinzipAesCryptoStream : Stream } } - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } + public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException(); - public override void SetLength(long value) - { - throw new NotSupportedException(); - } + public override void SetLength(long value) => throw new NotSupportedException(); - public override void Write(byte[] buffer, int offset, int count) - { + public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException(); - } } diff --git a/src/SharpCompress/Common/Zip/WinzipAesEncryptionData.cs b/src/SharpCompress/Common/Zip/WinzipAesEncryptionData.cs index ce31eed9..251b919e 100644 --- a/src/SharpCompress/Common/Zip/WinzipAesEncryptionData.cs +++ b/src/SharpCompress/Common/Zip/WinzipAesEncryptionData.cs @@ -35,21 +35,16 @@ internal class WinzipAesEncryptionData internal byte[] KeyBytes { get; set; } - private int KeySizeInBytes - { - get { return KeyLengthInBytes(_keySize); } - } + private int KeySizeInBytes => KeyLengthInBytes(_keySize); - internal static int KeyLengthInBytes(WinzipAesKeySize keySize) - { - return keySize switch + internal static int KeyLengthInBytes(WinzipAesKeySize keySize) => + keySize switch { WinzipAesKeySize.KeySize128 => 16, WinzipAesKeySize.KeySize192 => 24, WinzipAesKeySize.KeySize256 => 32, _ => throw new InvalidOperationException(), }; - } private void Initialize() { diff --git a/src/SharpCompress/Compressors/ADC/ADCBase.cs b/src/SharpCompress/Compressors/ADC/ADCBase.cs index 0ee2f1bb..6fc755a9 100644 --- a/src/SharpCompress/Compressors/ADC/ADCBase.cs +++ b/src/SharpCompress/Compressors/ADC/ADCBase.cs @@ -1,4 +1,4 @@ -// +// // ADC.cs // // Author: @@ -50,27 +50,23 @@ public static class ADCBase return TWO_BYTE; } - private static int GetChunkSize(byte byt) - { - return GetChunkType(byt) switch + private static int GetChunkSize(byte byt) => + GetChunkType(byt) switch { PLAIN => (byt & 0x7F) + 1, TWO_BYTE => ((byt & 0x3F) >> 2) + 3, THREE_BYTE => (byt & 0x3F) + 4, _ => -1, }; - } - private static int GetOffset(ReadOnlySpan chunk) - { - return GetChunkType(chunk[0]) switch + private static int GetOffset(ReadOnlySpan chunk) => + GetChunkType(chunk[0]) switch { PLAIN => 0, TWO_BYTE => ((chunk[0] & 0x03) << 8) + chunk[1], THREE_BYTE => (chunk[1] << 8) + chunk[2], _ => -1, }; - } /// /// Decompresses a byte buffer that's compressed with ADC @@ -79,10 +75,8 @@ public static class ADCBase /// Buffer to hold decompressed data /// Max size for decompressed data /// How many bytes are stored on - public static int Decompress(byte[] input, out byte[]? output, int bufferSize = 262144) - { - return Decompress(new MemoryStream(input), out output, bufferSize); - } + public static int Decompress(byte[] input, out byte[]? output, int bufferSize = 262144) => + Decompress(new MemoryStream(input), out output, bufferSize); /// /// Decompresses a stream that's compressed with ADC diff --git a/src/SharpCompress/Compressors/ADC/ADCStream.cs b/src/SharpCompress/Compressors/ADC/ADCStream.cs index 313583db..0660d11f 100644 --- a/src/SharpCompress/Compressors/ADC/ADCStream.cs +++ b/src/SharpCompress/Compressors/ADC/ADCStream.cs @@ -160,18 +160,10 @@ public sealed class ADCStream : Stream return copied; } - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } + public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException(); - public override void SetLength(long value) - { - throw new NotSupportedException(); - } + public override void SetLength(long value) => throw new NotSupportedException(); - public override void Write(byte[] buffer, int offset, int count) - { + public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException(); - } } diff --git a/src/SharpCompress/Compressors/BZip2/BZip2Stream.cs b/src/SharpCompress/Compressors/BZip2/BZip2Stream.cs index 852adc1e..feea12d1 100644 --- a/src/SharpCompress/Compressors/BZip2/BZip2Stream.cs +++ b/src/SharpCompress/Compressors/BZip2/BZip2Stream.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; namespace SharpCompress.Compressors.BZip2; @@ -27,10 +27,7 @@ public sealed class BZip2Stream : Stream } } - public void Finish() - { - (stream as CBZip2OutputStream)?.Finish(); - } + public void Finish() => (stream as CBZip2OutputStream)?.Finish(); protected override void Dispose(bool disposing) { @@ -53,10 +50,7 @@ public sealed class BZip2Stream : Stream public override bool CanWrite => stream.CanWrite; - public override void Flush() - { - stream.Flush(); - } + public override void Flush() => stream.Flush(); public override long Length => stream.Length; @@ -66,48 +60,26 @@ public sealed class BZip2Stream : Stream set => stream.Position = value; } - public override int Read(byte[] buffer, int offset, int count) - { - return stream.Read(buffer, offset, count); - } + public override int Read(byte[] buffer, int offset, int count) => + stream.Read(buffer, offset, count); - public override int ReadByte() - { - return stream.ReadByte(); - } + public override int ReadByte() => stream.ReadByte(); - public override long Seek(long offset, SeekOrigin origin) - { - return stream.Seek(offset, origin); - } + public override long Seek(long offset, SeekOrigin origin) => stream.Seek(offset, origin); - public override void SetLength(long value) - { - stream.SetLength(value); - } + public override void SetLength(long value) => stream.SetLength(value); #if !NETFRAMEWORK && !NETSTANDARD2_0 - public override int Read(Span buffer) - { - return stream.Read(buffer); - } + public override int Read(Span buffer) => stream.Read(buffer); - public override void Write(ReadOnlySpan buffer) - { - stream.Write(buffer); - } + public override void Write(ReadOnlySpan buffer) => stream.Write(buffer); #endif - public override void Write(byte[] buffer, int offset, int count) - { + public override void Write(byte[] buffer, int offset, int count) => stream.Write(buffer, offset, count); - } - public override void WriteByte(byte value) - { - stream.WriteByte(value); - } + public override void WriteByte(byte value) => stream.WriteByte(value); /// /// Consumes two bytes to test if there is a BZip2 header diff --git a/src/SharpCompress/Compressors/BZip2/CBZip2InputStream.cs b/src/SharpCompress/Compressors/BZip2/CBZip2InputStream.cs index f53f48dc..e03a5096 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; @@ -45,20 +45,11 @@ internal class CBZip2InputStream : Stream //throw new CCoruptionError(); } - private static void BadBGLengths() - { - Cadvise(); - } + private static void BadBGLengths() => Cadvise(); - private static void BitStreamEOF() - { - Cadvise(); - } + private static void BitStreamEOF() => Cadvise(); - private static void CompressedStreamEOF() - { - Cadvise(); - } + private static void CompressedStreamEOF() => Cadvise(); private void MakeMaps() { @@ -366,20 +357,11 @@ internal class CBZip2InputStream : Stream return complete; } - private static void BlockOverrun() - { - Cadvise(); - } + private static void BlockOverrun() => Cadvise(); - private static void BadBlockHeader() - { - Cadvise(); - } + private static void BadBlockHeader() => Cadvise(); - private static void CrcError() - { - Cadvise(); - } + private static void CrcError() => Cadvise(); private void BsFinishedWithStream() { @@ -423,10 +405,7 @@ internal class CBZip2InputStream : Stream return v; } - private char BsGetUChar() - { - return (char)BsR(8); - } + private char BsGetUChar() => (char)BsR(8); private int BsGetint() { @@ -438,15 +417,9 @@ internal class CBZip2InputStream : Stream return u; } - private int BsGetIntVS(int numBits) - { - return BsR(numBits); - } + private int BsGetIntVS(int numBits) => BsR(numBits); - private int BsGetInt32() - { - return BsGetint(); - } + private int BsGetInt32() => BsGetint(); private void HbCreateDecodeTables( int[] limit, @@ -1118,10 +1091,7 @@ internal class CBZip2InputStream : Stream return k; } - public override long Seek(long offset, SeekOrigin origin) - { - return 0; - } + public override long Seek(long offset, SeekOrigin origin) => 0; public override void SetLength(long value) { } @@ -1139,7 +1109,7 @@ internal class CBZip2InputStream : Stream public override long Position { - get { return 0; } + get => 0; set { } } } diff --git a/src/SharpCompress/Compressors/BZip2/CBZip2OutputStream.cs b/src/SharpCompress/Compressors/BZip2/CBZip2OutputStream.cs index 2e79312e..4f8a240b 100644 --- a/src/SharpCompress/Compressors/BZip2/CBZip2OutputStream.cs +++ b/src/SharpCompress/Compressors/BZip2/CBZip2OutputStream.cs @@ -473,10 +473,7 @@ internal sealed class CBZip2OutputStream : Stream Flush(); } - public override void Flush() - { - bsStream.Flush(); - } + public override void Flush() => bsStream.Flush(); private int blockCRC, combinedCRC; @@ -638,10 +635,7 @@ internal sealed class CBZip2OutputStream : Stream bsLive += n; } - private void BsPutUChar(int c) - { - BsW(8, c); - } + private void BsPutUChar(int c) => BsW(8, c); private void BsPutint(int u) { @@ -651,10 +645,7 @@ internal sealed class CBZip2OutputStream : Stream BsW(8, u & 0xff); } - private void BsPutIntVS(int numBits, int c) - { - BsW(numBits, c); - } + private void BsPutIntVS(int numBits, int c) => BsW(numBits, c); private void SendMTFValues() { @@ -1986,20 +1977,11 @@ internal sealed class CBZip2OutputStream : Stream nMTF = wr; } - public override int Read(byte[] buffer, int offset, int count) - { - return 0; - } + public override int Read(byte[] buffer, int offset, int count) => 0; - public override int ReadByte() - { - return -1; - } + public override int ReadByte() => -1; - public override long Seek(long offset, SeekOrigin origin) - { - return 0; - } + public override long Seek(long offset, SeekOrigin origin) => 0; public override void SetLength(long value) { } @@ -2021,7 +2003,7 @@ internal sealed class CBZip2OutputStream : Stream public override long Position { - get { return 0; } + get => 0; set { } } } diff --git a/src/SharpCompress/Compressors/BZip2/CRC.cs b/src/SharpCompress/Compressors/BZip2/CRC.cs index 7c208aff..9f593c40 100644 --- a/src/SharpCompress/Compressors/BZip2/CRC.cs +++ b/src/SharpCompress/Compressors/BZip2/CRC.cs @@ -1,4 +1,4 @@ -/* +/* * Copyright 2001,2004-2005 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -291,30 +291,15 @@ internal class CRC unchecked((int)0xb1f740b4) }; - public CRC() - { - InitialiseCRC(); - } + public CRC() => InitialiseCRC(); - internal void InitialiseCRC() - { - globalCrc = unchecked((int)0xffffffff); - } + internal void InitialiseCRC() => globalCrc = unchecked((int)0xffffffff); - internal int GetFinalCRC() - { - return ~globalCrc; - } + internal int GetFinalCRC() => ~globalCrc; - internal int GetGlobalCRC() - { - return globalCrc; - } + internal int GetGlobalCRC() => globalCrc; - internal void SetGlobalCRC(int newCrc) - { - globalCrc = newCrc; - } + internal void SetGlobalCRC(int newCrc) => globalCrc = newCrc; internal void UpdateCRC(int inCh) { diff --git a/src/SharpCompress/Compressors/Deflate/CRC32.cs b/src/SharpCompress/Compressors/Deflate/CRC32.cs index 01e5ba2a..892459fb 100644 --- a/src/SharpCompress/Compressors/Deflate/CRC32.cs +++ b/src/SharpCompress/Compressors/Deflate/CRC32.cs @@ -101,10 +101,7 @@ public class CRC32 /// /// The stream over which to calculate the CRC32 /// the CRC32 calculation - public uint GetCrc32(Stream input) - { - return GetCrc32AndCopy(input, null); - } + public uint GetCrc32(Stream input) => GetCrc32AndCopy(input, null); /// /// Returns the CRC32 for the specified stream, and writes the input into the @@ -149,15 +146,10 @@ public class CRC32 /// The word to start with. /// The byte to combine it with. /// The CRC-ized result. - public int ComputeCrc32(int W, byte B) - { - return _InternalComputeCrc32((uint)W, B); - } + public int ComputeCrc32(int W, byte B) => _InternalComputeCrc32((uint)W, B); - internal int _InternalComputeCrc32(uint W, byte B) - { - return (int)(crc32Table[(W ^ B) & 0xFF] ^ (W >> 8)); - } + internal int _InternalComputeCrc32(uint W, byte B) => + (int)(crc32Table[(W ^ B) & 0xFF] ^ (W >> 8)); /// /// Update the value for the running CRC32 using the given block of bytes. diff --git a/src/SharpCompress/Compressors/Deflate/DeflateManager.cs b/src/SharpCompress/Compressors/Deflate/DeflateManager.cs index a7dff8b5..27ad4018 100644 --- a/src/SharpCompress/Compressors/Deflate/DeflateManager.cs +++ b/src/SharpCompress/Compressors/Deflate/DeflateManager.cs @@ -201,13 +201,9 @@ internal sealed partial class DeflateManager Flavor = flavor; } - public static Config Lookup(CompressionLevel level) - { - return Table[(int)level]; - } + public static Config Lookup(CompressionLevel level) => Table[(int)level]; - static Config() - { + static Config() => Table = new[] { new Config(0, 0, 0, 0, DeflateFlavor.Store), @@ -221,7 +217,6 @@ internal sealed partial class DeflateManager new Config(32, 128, 258, 1024, DeflateFlavor.Slow), new Config(32, 258, 258, 4096, DeflateFlavor.Slow) }; - } private static readonly Config[] Table; } @@ -1679,25 +1674,18 @@ internal sealed partial class DeflateManager internal bool WantRfc1950HeaderBytes { get; set; } = true; - internal int Initialize(ZlibCodec codec, CompressionLevel level) - { - return Initialize(codec, level, ZlibConstants.WindowBitsMax); - } + internal int Initialize(ZlibCodec codec, CompressionLevel level) => + Initialize(codec, level, ZlibConstants.WindowBitsMax); - internal int Initialize(ZlibCodec codec, CompressionLevel level, int bits) - { - return Initialize(codec, level, bits, MEM_LEVEL_DEFAULT, CompressionStrategy.Default); - } + internal int Initialize(ZlibCodec codec, CompressionLevel level, int bits) => + Initialize(codec, level, bits, MEM_LEVEL_DEFAULT, CompressionStrategy.Default); internal int Initialize( ZlibCodec codec, CompressionLevel level, int bits, CompressionStrategy compressionStrategy - ) - { - return Initialize(codec, level, bits, MEM_LEVEL_DEFAULT, compressionStrategy); - } + ) => Initialize(codec, level, bits, MEM_LEVEL_DEFAULT, compressionStrategy); internal int Initialize( ZlibCodec codec, diff --git a/src/SharpCompress/Compressors/Deflate/DeflateStream.cs b/src/SharpCompress/Compressors/Deflate/DeflateStream.cs index cb7512a6..05003d7f 100644 --- a/src/SharpCompress/Compressors/Deflate/DeflateStream.cs +++ b/src/SharpCompress/Compressors/Deflate/DeflateStream.cs @@ -40,8 +40,7 @@ public class DeflateStream : Stream CompressionMode mode, CompressionLevel level = CompressionLevel.Default, Encoding? forceEncoding = null - ) - { + ) => _baseStream = new ZlibBaseStream( stream, mode, @@ -49,7 +48,6 @@ public class DeflateStream : Stream ZlibStreamFlavor.DEFLATE, forceEncoding ); - } #region Zlib properties @@ -310,19 +308,13 @@ public class DeflateStream : Stream /// this is irrelevant, since it will always throw! /// this is irrelevant, since it will always throw! /// irrelevant! - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } + public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException(); /// /// Calling this method always throws a . /// /// this is irrelevant, since it will always throw! - public override void SetLength(long value) - { - throw new NotSupportedException(); - } + public override void SetLength(long value) => throw new NotSupportedException(); /// /// Write data to the stream. diff --git a/src/SharpCompress/Compressors/Deflate/GZipStream.cs b/src/SharpCompress/Compressors/Deflate/GZipStream.cs index 9c99cd26..c547df14 100644 --- a/src/SharpCompress/Compressors/Deflate/GZipStream.cs +++ b/src/SharpCompress/Compressors/Deflate/GZipStream.cs @@ -296,19 +296,13 @@ public class GZipStream : Stream /// irrelevant; it will always throw! /// irrelevant; it will always throw! /// irrelevant! - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } + public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException(); /// /// Calling this method always throws a . /// /// irrelevant; this method will always throw! - public override void SetLength(long value) - { - throw new NotSupportedException(); - } + public override void SetLength(long value) => throw new NotSupportedException(); /// /// Write data to the stream. diff --git a/src/SharpCompress/Compressors/Deflate/Inflate.cs b/src/SharpCompress/Compressors/Deflate/Inflate.cs index abeebb32..ebea2805 100644 --- a/src/SharpCompress/Compressors/Deflate/Inflate.cs +++ b/src/SharpCompress/Compressors/Deflate/Inflate.cs @@ -728,10 +728,7 @@ internal sealed class InflateBlocks // Returns true if inflate is currently at the end of a block generated // by Z_SYNC_FLUSH or Z_FULL_FLUSH. - internal int SyncPoint() - { - return mode == InflateBlockMode.LENS ? 1 : 0; - } + internal int SyncPoint() => mode == InflateBlockMode.LENS ? 1 : 0; // copy as much as possible from the sliding window to the output area internal int Flush(int r) @@ -1655,10 +1652,8 @@ internal sealed class InflateManager public InflateManager() { } - public InflateManager(bool expectRfc1950HeaderBytes) - { + public InflateManager(bool expectRfc1950HeaderBytes) => HandleRfc1950HeaderBytes = expectRfc1950HeaderBytes; - } internal bool HandleRfc1950HeaderBytes { get; set; } = true; @@ -2041,10 +2036,7 @@ internal sealed class InflateManager // but removes the length bytes of the resulting empty stored block. When // decompressing, PPP checks that at the end of input packet, inflate is // waiting for these length bytes. - internal int SyncPoint(ZlibCodec z) - { - return blocks.SyncPoint(); - } + internal int SyncPoint(ZlibCodec z) => blocks.SyncPoint(); #region Nested type: InflateManagerMode diff --git a/src/SharpCompress/Compressors/Deflate/Tree.cs b/src/SharpCompress/Compressors/Deflate/Tree.cs index 25f8ada3..ec1eb51f 100644 --- a/src/SharpCompress/Compressors/Deflate/Tree.cs +++ b/src/SharpCompress/Compressors/Deflate/Tree.cs @@ -958,10 +958,8 @@ internal sealed partial class DeflateManager /// /// No side effects. _dist_code[256] and _dist_code[257] are never used. /// - internal static int DistanceCode(int dist) - { - return (dist < 256) ? _dist_code[dist] : _dist_code[256 + SharedUtils.URShift(dist, 7)]; - } + internal static int DistanceCode(int dist) => + (dist < 256) ? _dist_code[dist] : _dist_code[256 + SharedUtils.URShift(dist, 7)]; // Compute the optimal bit lengths for a tree and update the total bit length // for the current block. diff --git a/src/SharpCompress/Compressors/Deflate/Zlib.cs b/src/SharpCompress/Compressors/Deflate/Zlib.cs index 00336548..1377b116 100644 --- a/src/SharpCompress/Compressors/Deflate/Zlib.cs +++ b/src/SharpCompress/Compressors/Deflate/Zlib.cs @@ -200,10 +200,7 @@ internal class SharedUtils /// Number to operate on /// Ammount of bits to shift /// The resulting number from the shift operation - public static int URShift(int number, int bits) - { - return (int)((uint)number >> bits); - } + public static int URShift(int number, int bits) => (int)((uint)number >> bits); #if NOT diff --git a/src/SharpCompress/Compressors/Deflate/ZlibBaseStream.cs b/src/SharpCompress/Compressors/Deflate/ZlibBaseStream.cs index a3a5eae5..19a3c60a 100644 --- a/src/SharpCompress/Compressors/Deflate/ZlibBaseStream.cs +++ b/src/SharpCompress/Compressors/Deflate/ZlibBaseStream.cs @@ -33,139 +33,177 @@ using System.IO; using SharpCompress.Common.Tar.Headers; using System.Text; -namespace SharpCompress.Compressors.Deflate +namespace SharpCompress.Compressors.Deflate; + +internal enum ZlibStreamFlavor { - internal enum ZlibStreamFlavor + ZLIB = 1950, + DEFLATE = 1951, + GZIP = 1952 +} + +internal class ZlibBaseStream : Stream +{ + protected internal ZlibCodec _z; // deferred init... new ZlibCodec(); + + protected internal StreamMode _streamMode = StreamMode.Undefined; + protected internal FlushType _flushMode; + protected internal ZlibStreamFlavor _flavor; + protected internal CompressionMode _compressionMode; + protected internal CompressionLevel _level; + protected internal byte[] _workingBuffer; + protected internal int _bufferSize = ZlibConstants.WorkingBufferSizeDefault; + protected internal byte[] _buf1 = new byte[1]; + + protected internal Stream _stream; + protected internal CompressionStrategy Strategy = CompressionStrategy.Default; + + // workitem 7159 + private readonly CRC32 crc; + protected internal string _GzipFileName; + protected internal string _GzipComment; + protected internal DateTime _GzipMtime; + protected internal int _gzipHeaderByteCount; + + private readonly Encoding _encoding; + + internal int Crc32 => crc?.Crc32Result ?? 0; + + public ZlibBaseStream( + Stream stream, + CompressionMode compressionMode, + CompressionLevel level, + ZlibStreamFlavor flavor, + Encoding encoding + ) { - ZLIB = 1950, - DEFLATE = 1951, - GZIP = 1952 - } + _flushMode = FlushType.None; - internal class ZlibBaseStream : Stream - { - protected internal ZlibCodec _z; // deferred init... new ZlibCodec(); + //this._workingBuffer = new byte[WORKING_BUFFER_SIZE_DEFAULT]; + _stream = stream; + _compressionMode = compressionMode; + _flavor = flavor; + _level = level; - protected internal StreamMode _streamMode = StreamMode.Undefined; - protected internal FlushType _flushMode; - protected internal ZlibStreamFlavor _flavor; - protected internal CompressionMode _compressionMode; - protected internal CompressionLevel _level; - protected internal byte[] _workingBuffer; - protected internal int _bufferSize = ZlibConstants.WorkingBufferSizeDefault; - protected internal byte[] _buf1 = new byte[1]; - - protected internal Stream _stream; - protected internal CompressionStrategy Strategy = CompressionStrategy.Default; + _encoding = encoding; // workitem 7159 - private readonly CRC32 crc; - protected internal string _GzipFileName; - protected internal string _GzipComment; - protected internal DateTime _GzipMtime; - protected internal int _gzipHeaderByteCount; - - private readonly Encoding _encoding; - - internal int Crc32 => crc?.Crc32Result ?? 0; - - public ZlibBaseStream( - Stream stream, - CompressionMode compressionMode, - CompressionLevel level, - ZlibStreamFlavor flavor, - Encoding encoding - ) + if (flavor == ZlibStreamFlavor.GZIP) { - _flushMode = FlushType.None; - - //this._workingBuffer = new byte[WORKING_BUFFER_SIZE_DEFAULT]; - _stream = stream; - _compressionMode = compressionMode; - _flavor = flavor; - _level = level; - - _encoding = encoding; - - // workitem 7159 - if (flavor == ZlibStreamFlavor.GZIP) - { - crc = new CRC32(); - } + crc = new CRC32(); } + } - protected internal bool _wantCompress => (_compressionMode == CompressionMode.Compress); + protected internal bool _wantCompress => (_compressionMode == CompressionMode.Compress); - private ZlibCodec z + private ZlibCodec z + { + get { - get + if (_z is null) { - if (_z is null) + bool wantRfc1950Header = (_flavor == ZlibStreamFlavor.ZLIB); + _z = new ZlibCodec(); + if (_compressionMode == CompressionMode.Decompress) { - bool wantRfc1950Header = (_flavor == ZlibStreamFlavor.ZLIB); - _z = new ZlibCodec(); - if (_compressionMode == CompressionMode.Decompress) - { - _z.InitializeInflate(wantRfc1950Header); - } - else - { - _z.Strategy = Strategy; - _z.InitializeDeflate(_level, wantRfc1950Header); - } + _z.InitializeInflate(wantRfc1950Header); + } + else + { + _z.Strategy = Strategy; + _z.InitializeDeflate(_level, wantRfc1950Header); } - return _z; } + return _z; + } + } + + private byte[] workingBuffer => _workingBuffer ??= new byte[_bufferSize]; + + public override void Write(byte[] buffer, int offset, int count) + { + // workitem 7159 + // calculate the CRC on the unccompressed data (before writing) + if (crc != null) + { + crc.SlurpBlock(buffer, offset, count); } - private byte[] workingBuffer + if (_streamMode == StreamMode.Undefined) { - get => _workingBuffer ??= new byte[_bufferSize]; + _streamMode = StreamMode.Writer; + } + else if (_streamMode != StreamMode.Writer) + { + throw new ZlibException("Cannot Write after Reading."); } - public override void Write(byte[] buffer, int offset, int count) + if (count == 0) { - // workitem 7159 - // calculate the CRC on the unccompressed data (before writing) - if (crc != null) + return; + } + + // first reference of z property will initialize the private var _z + z.InputBuffer = buffer; + _z.NextIn = offset; + _z.AvailableBytesIn = count; + bool done = false; + do + { + _z.OutputBuffer = workingBuffer; + _z.NextOut = 0; + _z.AvailableBytesOut = _workingBuffer.Length; + int rc = (_wantCompress) ? _z.Deflate(_flushMode) : _z.Inflate(_flushMode); + if (rc != ZlibConstants.Z_OK && rc != ZlibConstants.Z_STREAM_END) { - crc.SlurpBlock(buffer, offset, count); + throw new ZlibException((_wantCompress ? "de" : "in") + "flating: " + _z.Message); } - if (_streamMode == StreamMode.Undefined) - { - _streamMode = StreamMode.Writer; - } - else if (_streamMode != StreamMode.Writer) - { - throw new ZlibException("Cannot Write after Reading."); - } + //if (_workingBuffer.Length - _z.AvailableBytesOut > 0) + _stream.Write(_workingBuffer, 0, _workingBuffer.Length - _z.AvailableBytesOut); - if (count == 0) - { - return; - } + done = _z.AvailableBytesIn == 0 && _z.AvailableBytesOut != 0; - // first reference of z property will initialize the private var _z - z.InputBuffer = buffer; - _z.NextIn = offset; - _z.AvailableBytesIn = count; + // If GZIP and de-compress, we're done when 8 bytes remain. + if (_flavor == ZlibStreamFlavor.GZIP && !_wantCompress) + { + done = (_z.AvailableBytesIn == 8 && _z.AvailableBytesOut != 0); + } + } while (!done); + } + + private void finish() + { + if (_z is null) + { + return; + } + + if (_streamMode == StreamMode.Writer) + { bool done = false; do { _z.OutputBuffer = workingBuffer; _z.NextOut = 0; _z.AvailableBytesOut = _workingBuffer.Length; - int rc = (_wantCompress) ? _z.Deflate(_flushMode) : _z.Inflate(_flushMode); - if (rc != ZlibConstants.Z_OK && rc != ZlibConstants.Z_STREAM_END) + int rc = + (_wantCompress) ? _z.Deflate(FlushType.Finish) : _z.Inflate(FlushType.Finish); + + if (rc != ZlibConstants.Z_STREAM_END && rc != ZlibConstants.Z_OK) { - throw new ZlibException( - (_wantCompress ? "de" : "in") + "flating: " + _z.Message - ); + string verb = (_wantCompress ? "de" : "in") + "flating"; + if (_z.Message is null) + { + throw new ZlibException(String.Format("{0}: (rc = {1})", verb, rc)); + } + throw new ZlibException(verb + ": " + _z.Message); } - //if (_workingBuffer.Length - _z.AvailableBytesOut > 0) - _stream.Write(_workingBuffer, 0, _workingBuffer.Length - _z.AvailableBytesOut); + if (_workingBuffer.Length - _z.AvailableBytesOut > 0) + { + _stream.Write(_workingBuffer, 0, _workingBuffer.Length - _z.AvailableBytesOut); + } done = _z.AvailableBytesIn == 0 && _z.AvailableBytesOut != 0; @@ -175,478 +213,313 @@ namespace SharpCompress.Compressors.Deflate done = (_z.AvailableBytesIn == 8 && _z.AvailableBytesOut != 0); } } while (!done); - } - private void finish() - { - if (_z is null) - { - return; - } + Flush(); - if (_streamMode == StreamMode.Writer) - { - bool done = false; - do - { - _z.OutputBuffer = workingBuffer; - _z.NextOut = 0; - _z.AvailableBytesOut = _workingBuffer.Length; - int 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"; - if (_z.Message is null) - { - throw new ZlibException(String.Format("{0}: (rc = {1})", verb, rc)); - } - throw new ZlibException(verb + ": " + _z.Message); - } - - if (_workingBuffer.Length - _z.AvailableBytesOut > 0) - { - _stream.Write( - _workingBuffer, - 0, - _workingBuffer.Length - _z.AvailableBytesOut - ); - } - - done = _z.AvailableBytesIn == 0 && _z.AvailableBytesOut != 0; - - // If GZIP and de-compress, we're done when 8 bytes remain. - if (_flavor == ZlibStreamFlavor.GZIP && !_wantCompress) - { - done = (_z.AvailableBytesIn == 8 && _z.AvailableBytesOut != 0); - } - } while (!done); - - Flush(); - - // workitem 7159 - if (_flavor == ZlibStreamFlavor.GZIP) - { - if (_wantCompress) - { - // Emit the GZIP trailer: CRC32 and size mod 2^32 - Span intBuf = stackalloc byte[4]; - BinaryPrimitives.WriteInt32LittleEndian(intBuf, crc.Crc32Result); - _stream.Write(intBuf); - int c2 = (int)(crc.TotalBytesRead & 0x00000000FFFFFFFF); - BinaryPrimitives.WriteInt32LittleEndian(intBuf, c2); - _stream.Write(intBuf); - } - else - { - throw new ZlibException("Writing with decompression is not supported."); - } - } - } // workitem 7159 - else if (_streamMode == StreamMode.Reader) + if (_flavor == ZlibStreamFlavor.GZIP) { - if (_flavor == ZlibStreamFlavor.GZIP) + if (_wantCompress) { - if (!_wantCompress) - { - // workitem 8501: handle edge case (decompress empty stream) - if (_z.TotalBytesOut == 0L) - { - return; - } - - // Read and potentially verify the GZIP trailer: CRC32 and size mod 2^32 - Span trailer = stackalloc byte[8]; - - // workitem 8679 - if (_z.AvailableBytesIn != 8) - { - // 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( - trailer.Slice(_z.AvailableBytesIn, bytesNeeded) - ); - if (bytesNeeded != bytesRead) - { - throw new ZlibException( - String.Format( - "Protocol error. AvailableBytesIn={0}, expected 8", - _z.AvailableBytesIn + bytesRead - ) - ); - } - } - else - { - _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); - - if (crc32_actual != crc32_expected) - { - throw new ZlibException( - String.Format( - "Bad CRC32 in GZIP stream. (actual({0:X8})!=expected({1:X8}))", - crc32_actual, - crc32_expected - ) - ); - } - - if (isize_actual != isize_expected) - { - throw new ZlibException( - String.Format( - "Bad size in GZIP stream. (actual({0})!=expected({1}))", - isize_actual, - isize_expected - ) - ); - } - } - else - { - throw new ZlibException("Reading with compression is not supported."); - } - } - } - } - - private void end() - { - if (z is null) - { - return; - } - if (_wantCompress) - { - _z.EndDeflate(); - } - else - { - _z.EndInflate(); - } - _z = null; - } - - protected override void Dispose(bool disposing) - { - if (isDisposed) - { - return; - } - isDisposed = true; - base.Dispose(disposing); - if (disposing) - { - if (_stream is null) - { - return; - } - try - { - finish(); - } - finally - { - end(); - _stream?.Dispose(); - _stream = null; - } - } - } - - public override void Flush() - { - _stream.Flush(); - } - - public override Int64 Seek(Int64 offset, SeekOrigin origin) - { - throw new NotSupportedException(); - - //_outStream.Seek(offset, origin); - } - - public override void SetLength(Int64 value) - { - _stream.SetLength(value); - } - -#if NOT - public int Read() - { - if (Read(_buf1, 0, 1) == 0) - return 0; - // calculate CRC after reading - if (crc != null) - crc.SlurpBlock(_buf1, 0, 1); - return (_buf1[0] & 0xFF); - } -#endif - - private bool nomoreinput; - private bool isDisposed; - - private string ReadZeroTerminatedString() - { - var list = new List(); - bool done = false; - do - { - // workitem 7740 - int n = _stream.Read(_buf1, 0, 1); - if (n != 1) - { - throw new ZlibException("Unexpected EOF reading GZIP header."); - } - if (_buf1[0] == 0) - { - done = true; + // Emit the GZIP trailer: CRC32 and size mod 2^32 + Span intBuf = stackalloc byte[4]; + BinaryPrimitives.WriteInt32LittleEndian(intBuf, crc.Crc32Result); + _stream.Write(intBuf); + int c2 = (int)(crc.TotalBytesRead & 0x00000000FFFFFFFF); + BinaryPrimitives.WriteInt32LittleEndian(intBuf, c2); + _stream.Write(intBuf); } else { - list.Add(_buf1[0]); + throw new ZlibException("Writing with decompression is not supported."); } - } while (!done); - byte[] buffer = list.ToArray(); - return _encoding.GetString(buffer, 0, buffer.Length); + } } - - private int _ReadAndValidateGzipHeader() + // workitem 7159 + else if (_streamMode == StreamMode.Reader) { - int totalBytesRead = 0; - - // read the header on the first read - Span header = stackalloc byte[10]; - int n = _stream.Read(header); - - // workitem 8501: handle edge case (decompress empty stream) - if (n == 0) + if (_flavor == ZlibStreamFlavor.GZIP) { - return 0; - } - - if (n != 10) - { - throw new ZlibException("Not a valid GZIP stream."); - } - - if (header[0] != 0x1F || header[1] != 0x8B || header[2] != 8) - { - throw new ZlibException("Bad GZIP header."); - } - - int timet = BinaryPrimitives.ReadInt32LittleEndian(header.Slice(4)); - _GzipMtime = TarHeader.EPOCH.AddSeconds(timet); - totalBytesRead += n; - if ((header[3] & 0x04) == 0x04) - { - // read and discard extra field - 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]; - n = _stream.Read(extra, 0, extra.Length); - if (n != extraLength) + if (!_wantCompress) { - throw new ZlibException("Unexpected end-of-file reading GZIP header."); - } - totalBytesRead += n; - } - if ((header[3] & 0x08) == 0x08) - { - _GzipFileName = ReadZeroTerminatedString(); - } - if ((header[3] & 0x10) == 0x010) - { - _GzipComment = ReadZeroTerminatedString(); - } - if ((header[3] & 0x02) == 0x02) - { - Read(_buf1, 0, 1); // CRC16, ignore - } - - return totalBytesRead; - } - - public override Int32 Read(Byte[] buffer, Int32 offset, Int32 count) - { - // According to MS documentation, any implementation of the IO.Stream.Read function must: - // (a) throw an exception if offset & count reference an invalid part of the buffer, - // or if count < 0, or if buffer is null - // (b) return 0 only upon EOF, or if count = 0 - // (c) if not EOF, then return at least 1 byte, up to bytes - - if (_streamMode == StreamMode.Undefined) - { - if (!_stream.CanRead) - { - throw new ZlibException("The stream is not readable."); - } - - // for the first read, set up some controls. - _streamMode = StreamMode.Reader; - - // (The first reference to _z goes through the private accessor which - // may initialize it.) - z.AvailableBytesIn = 0; - if (_flavor == ZlibStreamFlavor.GZIP) - { - _gzipHeaderByteCount = _ReadAndValidateGzipHeader(); - // workitem 8501: handle edge case (decompress empty stream) - if (_gzipHeaderByteCount == 0) + if (_z.TotalBytesOut == 0L) { - return 0; + return; } - } - } - if (_streamMode != StreamMode.Reader) - { - throw new ZlibException("Cannot Read after Writing."); - } + // Read and potentially verify the GZIP trailer: CRC32 and size mod 2^32 + Span trailer = stackalloc byte[8]; - int rc = 0; - - // set up the output of the deflate/inflate codec: - _z.OutputBuffer = buffer; - _z.NextOut = offset; - _z.AvailableBytesOut = count; - - if (count == 0) - { - return 0; - } - if (nomoreinput && _wantCompress) - { - // no more input data available; therefore we flush to - // try to complete the read - rc = _z.Deflate(FlushType.Finish); - - if (rc != ZlibConstants.Z_OK && rc != ZlibConstants.Z_STREAM_END) - { - throw new ZlibException( - String.Format("Deflating: rc={0} msg={1}", rc, _z.Message) - ); - } - - rc = (count - _z.AvailableBytesOut); - - // calculate CRC after reading - if (crc != null) - { - crc.SlurpBlock(buffer, offset, rc); - } - - return rc; - } - if (buffer is null) - { - throw new ArgumentNullException(nameof(buffer)); - } - if (count < 0) - { - throw new ArgumentOutOfRangeException(nameof(count)); - } - if (offset < buffer.GetLowerBound(0)) - { - throw new ArgumentOutOfRangeException(nameof(offset)); - } - if ((offset + count) > buffer.GetLength(0)) - { - throw new ArgumentOutOfRangeException(nameof(count)); - } - - // This is necessary in case _workingBuffer has been resized. (new byte[]) - // (The first reference to _workingBuffer goes through the private accessor which - // may initialize it.) - _z.InputBuffer = workingBuffer; - - do - { - // need data in _workingBuffer in order to deflate/inflate. Here, we check if we have any. - if ((_z.AvailableBytesIn == 0) && (!nomoreinput)) - { - // No data available, so try to Read data from the captive stream. - _z.NextIn = 0; - _z.AvailableBytesIn = _stream.Read(_workingBuffer, 0, _workingBuffer.Length); - if (_z.AvailableBytesIn == 0) + // workitem 8679 + if (_z.AvailableBytesIn != 8) { - nomoreinput = true; - } - } - - // we have data in InputBuffer; now compress or decompress as appropriate - rc = (_wantCompress) ? _z.Deflate(_flushMode) : _z.Inflate(_flushMode); - - if (nomoreinput && (rc == ZlibConstants.Z_BUF_ERROR)) - { - return 0; - } - - if (rc != ZlibConstants.Z_OK && rc != ZlibConstants.Z_STREAM_END) - { - throw new ZlibException( - String.Format( - "{0}flating: rc={1} msg={2}", - (_wantCompress ? "de" : "in"), - rc, - _z.Message - ) - ); - } - - if ( - (nomoreinput || rc == ZlibConstants.Z_STREAM_END) - && (_z.AvailableBytesOut == count) - ) - { - break; // nothing more to read - } - } //while (_z.AvailableBytesOut == count && rc == ZlibConstants.Z_OK); - while (_z.AvailableBytesOut > 0 && !nomoreinput && rc == ZlibConstants.Z_OK); - - // workitem 8557 - // is there more room in output? - if (_z.AvailableBytesOut > 0) - { - if (rc == ZlibConstants.Z_OK && _z.AvailableBytesIn == 0) - { - // deferred - } - - // are we completely done reading? - if (nomoreinput) - { - // and in compression? - if (_wantCompress) - { - // no more input data available; therefore we flush to - // try to complete the read - rc = _z.Deflate(FlushType.Finish); - - if (rc != ZlibConstants.Z_OK && rc != ZlibConstants.Z_STREAM_END) + // 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( + trailer.Slice(_z.AvailableBytesIn, bytesNeeded) + ); + if (bytesNeeded != bytesRead) { throw new ZlibException( - String.Format("Deflating: rc={0} msg={1}", rc, _z.Message) + String.Format( + "Protocol error. AvailableBytesIn={0}, expected 8", + _z.AvailableBytesIn + bytesRead + ) ); } } + else + { + _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); + + if (crc32_actual != crc32_expected) + { + throw new ZlibException( + String.Format( + "Bad CRC32 in GZIP stream. (actual({0:X8})!=expected({1:X8}))", + crc32_actual, + crc32_expected + ) + ); + } + + if (isize_actual != isize_expected) + { + throw new ZlibException( + String.Format( + "Bad size in GZIP stream. (actual({0})!=expected({1}))", + isize_actual, + isize_expected + ) + ); + } } + else + { + throw new ZlibException("Reading with compression is not supported."); + } + } + } + } + + private void end() + { + if (z is null) + { + return; + } + if (_wantCompress) + { + _z.EndDeflate(); + } + else + { + _z.EndInflate(); + } + _z = null; + } + + protected override void Dispose(bool disposing) + { + if (isDisposed) + { + return; + } + isDisposed = true; + base.Dispose(disposing); + if (disposing) + { + if (_stream is null) + { + return; + } + try + { + finish(); + } + finally + { + end(); + _stream?.Dispose(); + _stream = null; + } + } + } + + public override void Flush() => _stream.Flush(); + + public override Int64 Seek(Int64 offset, SeekOrigin origin) => + throw new NotSupportedException(); + + //_outStream.Seek(offset, origin); + public override void SetLength(Int64 value) => _stream.SetLength(value); + +#if NOT + public int Read() + { + if (Read(_buf1, 0, 1) == 0) + return 0; + // calculate CRC after reading + if (crc != null) + crc.SlurpBlock(_buf1, 0, 1); + return (_buf1[0] & 0xFF); + } +#endif + + private bool nomoreinput; + private bool isDisposed; + + private string ReadZeroTerminatedString() + { + var list = new List(); + bool done = false; + do + { + // workitem 7740 + int n = _stream.Read(_buf1, 0, 1); + if (n != 1) + { + throw new ZlibException("Unexpected EOF reading GZIP header."); + } + if (_buf1[0] == 0) + { + done = true; + } + else + { + list.Add(_buf1[0]); + } + } while (!done); + byte[] buffer = list.ToArray(); + return _encoding.GetString(buffer, 0, buffer.Length); + } + + private int _ReadAndValidateGzipHeader() + { + int totalBytesRead = 0; + + // read the header on the first read + Span header = stackalloc byte[10]; + int n = _stream.Read(header); + + // workitem 8501: handle edge case (decompress empty stream) + if (n == 0) + { + return 0; + } + + if (n != 10) + { + throw new ZlibException("Not a valid GZIP stream."); + } + + if (header[0] != 0x1F || header[1] != 0x8B || header[2] != 8) + { + throw new ZlibException("Bad GZIP header."); + } + + int timet = BinaryPrimitives.ReadInt32LittleEndian(header.Slice(4)); + _GzipMtime = TarHeader.EPOCH.AddSeconds(timet); + totalBytesRead += n; + if ((header[3] & 0x04) == 0x04) + { + // read and discard extra field + 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]; + n = _stream.Read(extra, 0, extra.Length); + if (n != extraLength) + { + throw new ZlibException("Unexpected end-of-file reading GZIP header."); + } + totalBytesRead += n; + } + if ((header[3] & 0x08) == 0x08) + { + _GzipFileName = ReadZeroTerminatedString(); + } + if ((header[3] & 0x10) == 0x010) + { + _GzipComment = ReadZeroTerminatedString(); + } + if ((header[3] & 0x02) == 0x02) + { + Read(_buf1, 0, 1); // CRC16, ignore + } + + return totalBytesRead; + } + + public override Int32 Read(Byte[] buffer, Int32 offset, Int32 count) + { + // According to MS documentation, any implementation of the IO.Stream.Read function must: + // (a) throw an exception if offset & count reference an invalid part of the buffer, + // or if count < 0, or if buffer is null + // (b) return 0 only upon EOF, or if count = 0 + // (c) if not EOF, then return at least 1 byte, up to bytes + + if (_streamMode == StreamMode.Undefined) + { + if (!_stream.CanRead) + { + throw new ZlibException("The stream is not readable."); + } + + // for the first read, set up some controls. + _streamMode = StreamMode.Reader; + + // (The first reference to _z goes through the private accessor which + // may initialize it.) + z.AvailableBytesIn = 0; + if (_flavor == ZlibStreamFlavor.GZIP) + { + _gzipHeaderByteCount = _ReadAndValidateGzipHeader(); + + // workitem 8501: handle edge case (decompress empty stream) + if (_gzipHeaderByteCount == 0) + { + return 0; + } + } + } + + if (_streamMode != StreamMode.Reader) + { + throw new ZlibException("Cannot Read after Writing."); + } + + int rc = 0; + + // set up the output of the deflate/inflate codec: + _z.OutputBuffer = buffer; + _z.NextOut = offset; + _z.AvailableBytesOut = count; + + if (count == 0) + { + return 0; + } + if (nomoreinput && _wantCompress) + { + // no more input data available; therefore we flush to + // try to complete the read + rc = _z.Deflate(FlushType.Finish); + + if (rc != ZlibConstants.Z_OK && rc != ZlibConstants.Z_STREAM_END) + { + throw new ZlibException( + String.Format("Deflating: rc={0} msg={1}", rc, _z.Message) + ); } rc = (count - _z.AvailableBytesOut); @@ -659,26 +532,129 @@ namespace SharpCompress.Compressors.Deflate return rc; } - - public override Boolean CanRead => _stream.CanRead; - - public override Boolean CanSeek => _stream.CanSeek; - - public override Boolean CanWrite => _stream.CanWrite; - - public override Int64 Length => _stream.Length; - - public override long Position + if (buffer is null) { - get => throw new NotSupportedException(); - set => throw new NotSupportedException(); + throw new ArgumentNullException(nameof(buffer)); + } + if (count < 0) + { + throw new ArgumentOutOfRangeException(nameof(count)); + } + if (offset < buffer.GetLowerBound(0)) + { + throw new ArgumentOutOfRangeException(nameof(offset)); + } + if ((offset + count) > buffer.GetLength(0)) + { + throw new ArgumentOutOfRangeException(nameof(count)); } - internal enum StreamMode + // This is necessary in case _workingBuffer has been resized. (new byte[]) + // (The first reference to _workingBuffer goes through the private accessor which + // may initialize it.) + _z.InputBuffer = workingBuffer; + + do { - Writer, - Reader, - Undefined + // need data in _workingBuffer in order to deflate/inflate. Here, we check if we have any. + if ((_z.AvailableBytesIn == 0) && (!nomoreinput)) + { + // No data available, so try to Read data from the captive stream. + _z.NextIn = 0; + _z.AvailableBytesIn = _stream.Read(_workingBuffer, 0, _workingBuffer.Length); + if (_z.AvailableBytesIn == 0) + { + nomoreinput = true; + } + } + + // we have data in InputBuffer; now compress or decompress as appropriate + rc = (_wantCompress) ? _z.Deflate(_flushMode) : _z.Inflate(_flushMode); + + if (nomoreinput && (rc == ZlibConstants.Z_BUF_ERROR)) + { + return 0; + } + + if (rc != ZlibConstants.Z_OK && rc != ZlibConstants.Z_STREAM_END) + { + throw new ZlibException( + String.Format( + "{0}flating: rc={1} msg={2}", + (_wantCompress ? "de" : "in"), + rc, + _z.Message + ) + ); + } + + if ( + (nomoreinput || rc == ZlibConstants.Z_STREAM_END) && (_z.AvailableBytesOut == count) + ) + { + break; // nothing more to read + } + } //while (_z.AvailableBytesOut == count && rc == ZlibConstants.Z_OK); + while (_z.AvailableBytesOut > 0 && !nomoreinput && rc == ZlibConstants.Z_OK); + + // workitem 8557 + // is there more room in output? + if (_z.AvailableBytesOut > 0) + { + if (rc == ZlibConstants.Z_OK && _z.AvailableBytesIn == 0) + { + // deferred + } + + // are we completely done reading? + if (nomoreinput) + { + // and in compression? + if (_wantCompress) + { + // no more input data available; therefore we flush to + // try to complete the read + rc = _z.Deflate(FlushType.Finish); + + if (rc != ZlibConstants.Z_OK && rc != ZlibConstants.Z_STREAM_END) + { + throw new ZlibException( + String.Format("Deflating: rc={0} msg={1}", rc, _z.Message) + ); + } + } + } } + + rc = (count - _z.AvailableBytesOut); + + // calculate CRC after reading + if (crc != null) + { + crc.SlurpBlock(buffer, offset, rc); + } + + return rc; + } + + public override Boolean CanRead => _stream.CanRead; + + public override Boolean CanSeek => _stream.CanSeek; + + public override Boolean CanWrite => _stream.CanWrite; + + public override Int64 Length => _stream.Length; + + public override long Position + { + get => throw new NotSupportedException(); + set => throw new NotSupportedException(); + } + + internal enum StreamMode + { + Writer, + Reader, + Undefined } } diff --git a/src/SharpCompress/Compressors/Deflate/ZlibCodec.cs b/src/SharpCompress/Compressors/Deflate/ZlibCodec.cs index c6b68dad..7c49c780 100644 --- a/src/SharpCompress/Compressors/Deflate/ZlibCodec.cs +++ b/src/SharpCompress/Compressors/Deflate/ZlibCodec.cs @@ -223,10 +223,7 @@ internal sealed class ZlibCodec /// It is implicitly called when you call the constructor. /// /// Z_OK if everything goes well. - public int InitializeInflate() - { - return InitializeInflate(WindowBits); - } + public int InitializeInflate() => InitializeInflate(WindowBits); /// /// Initialize the inflation state with an explicit flag to @@ -246,10 +243,8 @@ internal sealed class ZlibCodec /// pair when reading the stream of data to be inflated. /// /// Z_OK if everything goes well. - public int InitializeInflate(bool expectRfc1950Header) - { - return InitializeInflate(WindowBits, expectRfc1950Header); - } + public int InitializeInflate(bool expectRfc1950Header) => + InitializeInflate(WindowBits, expectRfc1950Header); /// /// Initialize the ZlibCodec for inflation, with the specified number of window bits. @@ -440,10 +435,7 @@ internal sealed class ZlibCodec /// /// /// Z_OK if all goes well. You generally don't need to check the return code. - public int InitializeDeflate() - { - return _InternalInitializeDeflate(true); - } + public int InitializeDeflate() => _InternalInitializeDeflate(true); /// /// Initialize the ZlibCodec for deflation operation, using the specified CompressionLevel. diff --git a/src/SharpCompress/Compressors/Deflate/ZlibStream.cs b/src/SharpCompress/Compressors/Deflate/ZlibStream.cs index 22ccfdd8..e2c69b53 100644 --- a/src/SharpCompress/Compressors/Deflate/ZlibStream.cs +++ b/src/SharpCompress/Compressors/Deflate/ZlibStream.cs @@ -47,10 +47,7 @@ public class ZlibStream : Stream CompressionMode mode, CompressionLevel level, Encoding encoding - ) - { - _baseStream = new ZlibBaseStream(stream, mode, level, ZlibStreamFlavor.ZLIB, encoding); - } + ) => _baseStream = new ZlibBaseStream(stream, mode, level, ZlibStreamFlavor.ZLIB, encoding); #region Zlib properties @@ -286,18 +283,12 @@ public class ZlibStream : Stream /// /// Calling this method always throws a . /// - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } + public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException(); /// /// Calling this method always throws a . /// - public override void SetLength(long value) - { - throw new NotSupportedException(); - } + public override void SetLength(long value) => throw new NotSupportedException(); /// /// Write data to the stream. diff --git a/src/SharpCompress/Compressors/Deflate64/Deflate64Stream.cs b/src/SharpCompress/Compressors/Deflate64/Deflate64Stream.cs index d182db74..149f7c92 100644 --- a/src/SharpCompress/Compressors/Deflate64/Deflate64Stream.cs +++ b/src/SharpCompress/Compressors/Deflate64/Deflate64Stream.cs @@ -10,289 +10,264 @@ using System.Diagnostics; using System.IO; using System.Runtime.CompilerServices; -namespace SharpCompress.Compressors.Deflate64 +namespace SharpCompress.Compressors.Deflate64; + +public sealed class Deflate64Stream : Stream { - public sealed class Deflate64Stream : Stream + private const int DEFAULT_BUFFER_SIZE = 8192; + + private Stream _stream; + private CompressionMode _mode; + private InflaterManaged _inflater; + private byte[] _buffer; + + public Deflate64Stream(Stream stream, CompressionMode mode) { - private const int DEFAULT_BUFFER_SIZE = 8192; - - private Stream _stream; - private CompressionMode _mode; - private InflaterManaged _inflater; - private byte[] _buffer; - - public Deflate64Stream(Stream stream, CompressionMode mode) + if (stream is null) { - if (stream is null) - { - throw new ArgumentNullException(nameof(stream)); - } - - if (mode != CompressionMode.Decompress) - { - throw new NotImplementedException( - "Deflate64: this implementation only supports decompression" - ); - } - - if (!stream.CanRead) - { - throw new ArgumentException( - "Deflate64: input stream is not readable", - nameof(stream) - ); - } - - InitializeInflater(stream, ZipCompressionMethod.Deflate64); + throw new ArgumentNullException(nameof(stream)); } - /// - /// Sets up this DeflateManagedStream to be used for Inflation/Decompression - /// - private void InitializeInflater( - Stream stream, - ZipCompressionMethod method = ZipCompressionMethod.Deflate - ) + if (mode != CompressionMode.Decompress) { - Debug.Assert(stream != null); - Debug.Assert( - method == ZipCompressionMethod.Deflate || method == ZipCompressionMethod.Deflate64 + throw new NotImplementedException( + "Deflate64: this implementation only supports decompression" ); - if (!stream.CanRead) - { - throw new ArgumentException( - "Deflate64: input stream is not readable", - nameof(stream) - ); - } - - _inflater = new InflaterManaged(method == ZipCompressionMethod.Deflate64); - - _stream = stream; - _mode = CompressionMode.Decompress; - _buffer = new byte[DEFAULT_BUFFER_SIZE]; } - public override bool CanRead + if (!stream.CanRead) { - get - { - if (_stream is null) - { - return false; - } - - return (_mode == CompressionMode.Decompress && _stream.CanRead); - } + throw new ArgumentException("Deflate64: input stream is not readable", nameof(stream)); } - public override bool CanWrite + InitializeInflater(stream, ZipCompressionMethod.Deflate64); + } + + /// + /// Sets up this DeflateManagedStream to be used for Inflation/Decompression + /// + private void InitializeInflater( + Stream stream, + ZipCompressionMethod method = ZipCompressionMethod.Deflate + ) + { + Debug.Assert(stream != null); + Debug.Assert( + method == ZipCompressionMethod.Deflate || method == ZipCompressionMethod.Deflate64 + ); + if (!stream.CanRead) { - get - { - if (_stream is null) - { - return false; - } - - return (_mode == CompressionMode.Compress && _stream.CanWrite); - } + throw new ArgumentException("Deflate64: input stream is not readable", nameof(stream)); } - public override bool CanSeek => false; + _inflater = new InflaterManaged(method == ZipCompressionMethod.Deflate64); - public override long Length - { - get { throw new NotSupportedException("Deflate64: not supported"); } - } + _stream = stream; + _mode = CompressionMode.Decompress; + _buffer = new byte[DEFAULT_BUFFER_SIZE]; + } - public override long Position - { - get { throw new NotSupportedException("Deflate64: not supported"); } - set { throw new NotSupportedException("Deflate64: not supported"); } - } - - public override void Flush() - { - EnsureNotDisposed(); - } - - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException("Deflate64: not supported"); - } - - public override void SetLength(long value) - { - throw new NotSupportedException("Deflate64: not supported"); - } - - public override int Read(byte[] array, int offset, int count) - { - EnsureDecompressionMode(); - ValidateParameters(array, offset, count); - EnsureNotDisposed(); - - int bytesRead; - int currentOffset = offset; - int remainingCount = count; - - while (true) - { - bytesRead = _inflater.Inflate(array, currentOffset, remainingCount); - currentOffset += bytesRead; - remainingCount -= bytesRead; - - if (remainingCount == 0) - { - break; - } - - if (_inflater.Finished()) - { - // if we finished decompressing, we can't have anything left in the outputwindow. - Debug.Assert( - _inflater.AvailableOutput == 0, - "We should have copied all stuff out!" - ); - break; - } - - int bytes = _stream.Read(_buffer, 0, _buffer.Length); - if (bytes <= 0) - { - break; - } - else if (bytes > _buffer.Length) - { - // The stream is either malicious or poorly implemented and returned a number of - // bytes larger than the buffer supplied to it. - throw new InvalidDataException("Deflate64: invalid data"); - } - - _inflater.SetInput(_buffer, 0, bytes); - } - - return count - remainingCount; - } - - private void ValidateParameters(byte[] array, int offset, int count) - { - if (array is null) - { - throw new ArgumentNullException(nameof(array)); - } - - if (offset < 0) - { - throw new ArgumentOutOfRangeException(nameof(offset)); - } - - if (count < 0) - { - throw new ArgumentOutOfRangeException(nameof(count)); - } - - if (array.Length - offset < count) - { - throw new ArgumentException("Deflate64: invalid offset/count combination"); - } - } - - private void EnsureNotDisposed() + public override bool CanRead + { + get { if (_stream is null) { - ThrowStreamClosedException(); + return false; } - } - [MethodImpl(MethodImplOptions.NoInlining)] - private static void ThrowStreamClosedException() - { - throw new ObjectDisposedException(null, "Deflate64: stream has been disposed"); + return (_mode == CompressionMode.Decompress && _stream.CanRead); } + } - private void EnsureDecompressionMode() + public override bool CanWrite + { + get { - if (_mode != CompressionMode.Decompress) + if (_stream is null) { - ThrowCannotReadFromDeflateManagedStreamException(); + return false; } - } - [MethodImpl(MethodImplOptions.NoInlining)] - private static void ThrowCannotReadFromDeflateManagedStreamException() - { - throw new InvalidOperationException("Deflate64: cannot read from this stream"); + return (_mode == CompressionMode.Compress && _stream.CanWrite); } + } - private void EnsureCompressionMode() + public override bool CanSeek => false; + + public override long Length => throw new NotSupportedException("Deflate64: not supported"); + + public override long Position + { + get => throw new NotSupportedException("Deflate64: not supported"); + set => throw new NotSupportedException("Deflate64: not supported"); + } + + public override void Flush() => EnsureNotDisposed(); + + public override long Seek(long offset, SeekOrigin origin) => + throw new NotSupportedException("Deflate64: not supported"); + + public override void SetLength(long value) => + throw new NotSupportedException("Deflate64: not supported"); + + public override int Read(byte[] array, int offset, int count) + { + EnsureDecompressionMode(); + ValidateParameters(array, offset, count); + EnsureNotDisposed(); + + int bytesRead; + int currentOffset = offset; + int remainingCount = count; + + while (true) { - if (_mode != CompressionMode.Compress) + bytesRead = _inflater.Inflate(array, currentOffset, remainingCount); + currentOffset += bytesRead; + remainingCount -= bytesRead; + + if (remainingCount == 0) { - ThrowCannotWriteToDeflateManagedStreamException(); + break; } + + if (_inflater.Finished()) + { + // if we finished decompressing, we can't have anything left in the outputwindow. + Debug.Assert( + _inflater.AvailableOutput == 0, + "We should have copied all stuff out!" + ); + break; + } + + int bytes = _stream.Read(_buffer, 0, _buffer.Length); + if (bytes <= 0) + { + break; + } + else if (bytes > _buffer.Length) + { + // The stream is either malicious or poorly implemented and returned a number of + // bytes larger than the buffer supplied to it. + throw new InvalidDataException("Deflate64: invalid data"); + } + + _inflater.SetInput(_buffer, 0, bytes); } - [MethodImpl(MethodImplOptions.NoInlining)] - private static void ThrowCannotWriteToDeflateManagedStreamException() + return count - remainingCount; + } + + private void ValidateParameters(byte[] array, int offset, int count) + { + if (array is null) { - throw new InvalidOperationException("Deflate64: cannot write to this stream"); + throw new ArgumentNullException(nameof(array)); } - public override void Write(byte[] array, int offset, int count) + if (offset < 0) + { + throw new ArgumentOutOfRangeException(nameof(offset)); + } + + if (count < 0) + { + throw new ArgumentOutOfRangeException(nameof(count)); + } + + if (array.Length - offset < count) + { + throw new ArgumentException("Deflate64: invalid offset/count combination"); + } + } + + private void EnsureNotDisposed() + { + if (_stream is null) + { + ThrowStreamClosedException(); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void ThrowStreamClosedException() => + throw new ObjectDisposedException(null, "Deflate64: stream has been disposed"); + + private void EnsureDecompressionMode() + { + if (_mode != CompressionMode.Decompress) + { + ThrowCannotReadFromDeflateManagedStreamException(); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void ThrowCannotReadFromDeflateManagedStreamException() => + throw new InvalidOperationException("Deflate64: cannot read from this stream"); + + private void EnsureCompressionMode() + { + if (_mode != CompressionMode.Compress) { ThrowCannotWriteToDeflateManagedStreamException(); } + } - // This is called by Dispose: - private void PurgeBuffers(bool disposing) + [MethodImpl(MethodImplOptions.NoInlining)] + private static void ThrowCannotWriteToDeflateManagedStreamException() => + throw new InvalidOperationException("Deflate64: cannot write to this stream"); + + public override void Write(byte[] array, int offset, int count) => + ThrowCannotWriteToDeflateManagedStreamException(); + + // This is called by Dispose: + private void PurgeBuffers(bool disposing) + { + if (!disposing) { - if (!disposing) - { - return; - } - - if (_stream is null) - { - return; - } - - Flush(); + return; } - protected override void Dispose(bool disposing) + if (_stream is null) { + return; + } + + Flush(); + } + + protected override void Dispose(bool disposing) + { + try + { + PurgeBuffers(disposing); + } + finally + { + // Close the underlying stream even if PurgeBuffers threw. + // Stream.Close() may throw here (may or may not be due to the same error). + // In this case, we still need to clean up internal resources, hence the inner finally blocks. try { - PurgeBuffers(disposing); + if (disposing) + { + _stream?.Dispose(); + } } finally { - // Close the underlying stream even if PurgeBuffers threw. - // Stream.Close() may throw here (may or may not be due to the same error). - // In this case, we still need to clean up internal resources, hence the inner finally blocks. + _stream = null; + try { - if (disposing) - { - _stream?.Dispose(); - } + _inflater?.Dispose(); } finally { - _stream = null; - - try - { - _inflater?.Dispose(); - } - finally - { - _inflater = null; - base.Dispose(disposing); - } + _inflater = null; + base.Dispose(disposing); } } } diff --git a/src/SharpCompress/Compressors/Deflate64/DeflateInput.cs b/src/SharpCompress/Compressors/Deflate64/DeflateInput.cs index b4e8fc82..6a12df3b 100644 --- a/src/SharpCompress/Compressors/Deflate64/DeflateInput.cs +++ b/src/SharpCompress/Compressors/Deflate64/DeflateInput.cs @@ -8,10 +8,7 @@ namespace SharpCompress.Compressors.Deflate64; internal sealed class DeflateInput { - public DeflateInput(byte[] buffer) - { - Buffer = buffer; - } + public DeflateInput(byte[] buffer) => Buffer = buffer; public byte[] Buffer { get; } public int Count { get; set; } diff --git a/src/SharpCompress/Compressors/Deflate64/InflaterManaged.cs b/src/SharpCompress/Compressors/Deflate64/InflaterManaged.cs index 7b11812e..6a3c226b 100644 --- a/src/SharpCompress/Compressors/Deflate64/InflaterManaged.cs +++ b/src/SharpCompress/Compressors/Deflate64/InflaterManaged.cs @@ -241,12 +241,10 @@ internal sealed class InflaterManaged Reset(); } - private void Reset() - { + private void Reset() => _state = //_hasFormatReader ? //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 c3212118..f658b385 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; @@ -37,15 +37,9 @@ internal class BCJ2Filter : Stream private const int K_BIT_MODEL_TOTAL = 1 << K_NUM_BIT_MODEL_TOTAL_BITS; private const int K_NUM_MOVE_BITS = 5; - private static bool IsJ(byte b0, byte b1) - { - return (b1 & 0xFE) == 0xE8 || IsJcc(b0, b1); - } + private static bool IsJ(byte b0, byte b1) => (b1 & 0xFE) == 0xE8 || IsJcc(b0, b1); - private static bool IsJcc(byte b0, byte b1) - { - return b0 == 0x0F && (b1 & 0xF0) == 0x80; - } + private static bool IsJcc(byte b0, byte b1) => b0 == 0x0F && (b1 & 0xF0) == 0x80; public BCJ2Filter(byte[] control, byte[] data1, byte[] data2, Stream baseStream) { @@ -85,10 +79,7 @@ internal class BCJ2Filter : Stream public override bool CanWrite => false; - public override void Flush() - { - throw new NotSupportedException(); - } + public override void Flush() => throw new NotSupportedException(); public override long Length => _baseStream.Length + _data1.Length + _data2.Length; @@ -212,18 +203,10 @@ internal class BCJ2Filter : Stream return size; } - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } + public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException(); - public override void SetLength(long value) - { - throw new NotSupportedException(); - } + public override void SetLength(long value) => throw new NotSupportedException(); - public override void Write(byte[] buffer, int offset, int count) - { + public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException(); - } } diff --git a/src/SharpCompress/Compressors/Filters/BCJFilter.cs b/src/SharpCompress/Compressors/Filters/BCJFilter.cs index 416725db..ca8e8c7e 100644 --- a/src/SharpCompress/Compressors/Filters/BCJFilter.cs +++ b/src/SharpCompress/Compressors/Filters/BCJFilter.cs @@ -1,4 +1,4 @@ -using System.IO; +using System.IO; namespace SharpCompress.Compressors.Filters; @@ -21,15 +21,10 @@ internal class BCJFilter : Filter private int _pos; private int _prevMask; - public BCJFilter(bool isEncoder, Stream baseStream) : base(isEncoder, baseStream, 5) - { + public BCJFilter(bool isEncoder, Stream baseStream) : base(isEncoder, baseStream, 5) => _pos = 5; - } - private static bool Test86MsByte(byte b) - { - return b == 0x00 || b == 0xFF; - } + private static bool Test86MsByte(byte b) => b == 0x00 || b == 0xFF; protected override int Transform(byte[] buffer, int offset, int count) { diff --git a/src/SharpCompress/Compressors/Filters/Filter.cs b/src/SharpCompress/Compressors/Filters/Filter.cs index d7f183f9..93d95195 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,10 +40,7 @@ internal abstract class Filter : Stream public override bool CanWrite => _isEncoder; - public override void Flush() - { - throw new NotSupportedException(); - } + public override void Flush() => throw new NotSupportedException(); public override long Length => _baseStream.Length; @@ -137,15 +134,9 @@ internal abstract class Filter : Stream return size; } - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } + public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException(); - public override void SetLength(long value) - { - throw new NotSupportedException(); - } + public override void SetLength(long value) => throw new NotSupportedException(); public override void Write(byte[] buffer, int offset, int count) { diff --git a/src/SharpCompress/Compressors/LZMA/AesDecoderStream.cs b/src/SharpCompress/Compressors/LZMA/AesDecoderStream.cs index a3c47462..24823c73 100644 --- a/src/SharpCompress/Compressors/LZMA/AesDecoderStream.cs +++ b/src/SharpCompress/Compressors/LZMA/AesDecoderStream.cs @@ -4,279 +4,278 @@ using System.Security.Cryptography; using System.Text; using SharpCompress.Compressors.LZMA.Utilites; -namespace SharpCompress.Compressors.LZMA +namespace SharpCompress.Compressors.LZMA; + +internal sealed class AesDecoderStream : DecoderStream2 { - internal sealed class AesDecoderStream : DecoderStream2 + private readonly Stream mStream; + private readonly ICryptoTransform mDecoder; + private readonly byte[] mBuffer; + private long mWritten; + private readonly long mLimit; + private int mOffset; + private int mEnding; + private int mUnderflow; + private bool isDisposed; + + public AesDecoderStream(Stream input, byte[] info, IPasswordProvider pass, long limit) { - private readonly Stream mStream; - private readonly ICryptoTransform mDecoder; - private readonly byte[] mBuffer; - private long mWritten; - private readonly long mLimit; - private int mOffset; - private int mEnding; - private int mUnderflow; - private bool isDisposed; - - public AesDecoderStream(Stream input, byte[] info, IPasswordProvider pass, long limit) + if (pass.CryptoGetTextPassword() == null) { - if (pass.CryptoGetTextPassword() == null) - { - throw new SharpCompress.Common.CryptographicException( - "Encrypted 7Zip archive has no password specified." - ); - } - - mStream = input; - mLimit = limit; - - if (((uint)input.Length & 15) != 0) - { - throw new NotSupportedException("AES decoder does not support padding."); - } - - Init(info, out int numCyclesPower, out byte[] salt, out byte[] seed); - - byte[] password = Encoding.Unicode.GetBytes(pass.CryptoGetTextPassword()); - byte[]? key = InitKey(numCyclesPower, salt, password); - if (key == null) - { - throw new InvalidOperationException("Initialized with null key"); - } - - using (var aes = Aes.Create()) - { - aes.Mode = CipherMode.CBC; - aes.Padding = PaddingMode.None; - mDecoder = aes.CreateDecryptor(key, seed); - } - - mBuffer = new byte[4 << 10]; + throw new SharpCompress.Common.CryptographicException( + "Encrypted 7Zip archive has no password specified." + ); } - protected override void Dispose(bool disposing) + mStream = input; + mLimit = limit; + + if (((uint)input.Length & 15) != 0) { - try - { - if (isDisposed) - { - return; - } - isDisposed = true; - if (disposing) - { - mStream.Dispose(); - mDecoder.Dispose(); - } - } - finally - { - base.Dispose(disposing); - } + throw new NotSupportedException("AES decoder does not support padding."); } - public override long Position => mWritten; + Init(info, out int numCyclesPower, out byte[] salt, out byte[] seed); - public override long Length => mLimit; - - public override int Read(byte[] buffer, int offset, int count) + byte[] password = Encoding.Unicode.GetBytes(pass.CryptoGetTextPassword()); + byte[]? key = InitKey(numCyclesPower, salt, password); + if (key == null) { - if (count == 0 || mWritten == mLimit) - { - return 0; - } - - if (mUnderflow > 0) - { - return HandleUnderflow(buffer, offset, count); - } - - // Need at least 16 bytes to proceed. - if (mEnding - mOffset < 16) - { - Buffer.BlockCopy(mBuffer, mOffset, mBuffer, 0, mEnding - mOffset); - mEnding -= mOffset; - mOffset = 0; - - do - { - int read = mStream.Read(mBuffer, mEnding, mBuffer.Length - mEnding); - if (read == 0) - { - // We are not done decoding and have less than 16 bytes. - throw new EndOfStreamException(); - } - - mEnding += read; - } while (mEnding - mOffset < 16); - } - - // We shouldn't return more data than we are limited to. - // Currently this is handled by forcing an underflow if - // the stream length is not a multiple of the block size. - if (count > mLimit - mWritten) - { - count = (int)(mLimit - mWritten); - } - - // We cannot transform less than 16 bytes into the target buffer, - // but we also cannot return zero, so we need to handle this. - // We transform the data locally and use our own buffer as cache. - if (count < 16) - { - return HandleUnderflow(buffer, offset, count); - } - - if (count > mEnding - mOffset) - { - count = mEnding - mOffset; - } - - // Otherwise we transform directly into the target buffer. - int processed = mDecoder.TransformBlock(mBuffer, mOffset, count & ~15, buffer, offset); - mOffset += processed; - mWritten += processed; - return processed; + throw new InvalidOperationException("Initialized with null key"); } - #region Private Methods - - private void Init(byte[] info, out int numCyclesPower, out byte[] salt, out byte[] iv) + using (var aes = Aes.Create()) { - byte bt = info[0]; - numCyclesPower = bt & 0x3F; + aes.Mode = CipherMode.CBC; + aes.Padding = PaddingMode.None; + mDecoder = aes.CreateDecryptor(key, seed); + } - if ((bt & 0xC0) == 0) + mBuffer = new byte[4 << 10]; + } + + protected override void Dispose(bool disposing) + { + try + { + if (isDisposed) { - salt = Array.Empty(); - iv = Array.Empty(); return; } - - int saltSize = (bt >> 7) & 1; - int ivSize = (bt >> 6) & 1; - if (info.Length == 1) + isDisposed = true; + if (disposing) { - throw new InvalidOperationException(); - } - - byte bt2 = info[1]; - saltSize += (bt2 >> 4); - ivSize += (bt2 & 15); - if (info.Length < 2 + saltSize + ivSize) - { - throw new InvalidOperationException(); - } - - salt = new byte[saltSize]; - for (int i = 0; i < saltSize; i++) - { - salt[i] = info[i + 2]; - } - - iv = new byte[16]; - for (int i = 0; i < ivSize; i++) - { - iv[i] = info[i + saltSize + 2]; - } - - if (numCyclesPower > 24) - { - throw new NotSupportedException(); + mStream.Dispose(); + mDecoder.Dispose(); } } - - private byte[]? InitKey(int mNumCyclesPower, byte[] salt, byte[] pass) + finally { - if (mNumCyclesPower == 0x3F) - { - var key = new byte[32]; - - int pos; - for (pos = 0; pos < salt.Length; pos++) - { - key[pos] = salt[pos]; - } - - for (int i = 0; i < pass.Length && pos < 32; i++) - { - key[pos++] = pass[i]; - } - - return key; - } - 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; - for (long round = 0; round < numRounds; round++) - { - sha.TransformBlock(salt, 0, salt.Length, null, 0); - sha.TransformBlock(pass, 0, pass.Length, null, 0); - sha.TransformBlock(counter, 0, 8, null, 0); - - // 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; - } - } - } - - sha.TransformFinalBlock(counter, 0, 0); - return sha.Hash; -#endif - } + base.Dispose(disposing); } - - private int HandleUnderflow(byte[] buffer, int offset, int count) - { - // If this is zero we were called to create a new underflow buffer. - // Just transform as much as possible so we can feed from it as long as possible. - if (mUnderflow == 0) - { - int blockSize = (mEnding - mOffset) & ~15; - mUnderflow = mDecoder.TransformBlock(mBuffer, mOffset, blockSize, mBuffer, mOffset); - } - - if (count > mUnderflow) - { - count = mUnderflow; - } - - Buffer.BlockCopy(mBuffer, mOffset, buffer, offset, count); - mWritten += count; - mOffset += count; - mUnderflow -= count; - return count; - } - - #endregion } + + public override long Position => mWritten; + + public override long Length => mLimit; + + public override int Read(byte[] buffer, int offset, int count) + { + if (count == 0 || mWritten == mLimit) + { + return 0; + } + + if (mUnderflow > 0) + { + return HandleUnderflow(buffer, offset, count); + } + + // Need at least 16 bytes to proceed. + if (mEnding - mOffset < 16) + { + Buffer.BlockCopy(mBuffer, mOffset, mBuffer, 0, mEnding - mOffset); + mEnding -= mOffset; + mOffset = 0; + + do + { + int read = mStream.Read(mBuffer, mEnding, mBuffer.Length - mEnding); + if (read == 0) + { + // We are not done decoding and have less than 16 bytes. + throw new EndOfStreamException(); + } + + mEnding += read; + } while (mEnding - mOffset < 16); + } + + // We shouldn't return more data than we are limited to. + // Currently this is handled by forcing an underflow if + // the stream length is not a multiple of the block size. + if (count > mLimit - mWritten) + { + count = (int)(mLimit - mWritten); + } + + // We cannot transform less than 16 bytes into the target buffer, + // but we also cannot return zero, so we need to handle this. + // We transform the data locally and use our own buffer as cache. + if (count < 16) + { + return HandleUnderflow(buffer, offset, count); + } + + if (count > mEnding - mOffset) + { + count = mEnding - mOffset; + } + + // Otherwise we transform directly into the target buffer. + int processed = mDecoder.TransformBlock(mBuffer, mOffset, count & ~15, buffer, offset); + mOffset += processed; + mWritten += processed; + return processed; + } + + #region Private Methods + + private void Init(byte[] info, out int numCyclesPower, out byte[] salt, out byte[] iv) + { + byte bt = info[0]; + numCyclesPower = bt & 0x3F; + + if ((bt & 0xC0) == 0) + { + salt = Array.Empty(); + iv = Array.Empty(); + return; + } + + int saltSize = (bt >> 7) & 1; + int ivSize = (bt >> 6) & 1; + if (info.Length == 1) + { + throw new InvalidOperationException(); + } + + byte bt2 = info[1]; + saltSize += (bt2 >> 4); + ivSize += (bt2 & 15); + if (info.Length < 2 + saltSize + ivSize) + { + throw new InvalidOperationException(); + } + + salt = new byte[saltSize]; + for (int i = 0; i < saltSize; i++) + { + salt[i] = info[i + 2]; + } + + iv = new byte[16]; + for (int i = 0; i < ivSize; i++) + { + iv[i] = info[i + saltSize + 2]; + } + + if (numCyclesPower > 24) + { + throw new NotSupportedException(); + } + } + + private byte[]? InitKey(int mNumCyclesPower, byte[] salt, byte[] pass) + { + if (mNumCyclesPower == 0x3F) + { + var key = new byte[32]; + + int pos; + for (pos = 0; pos < salt.Length; pos++) + { + key[pos] = salt[pos]; + } + + for (int i = 0; i < pass.Length && pos < 32; i++) + { + key[pos++] = pass[i]; + } + + return key; + } + 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; + for (long round = 0; round < numRounds; round++) + { + sha.TransformBlock(salt, 0, salt.Length, null, 0); + sha.TransformBlock(pass, 0, pass.Length, null, 0); + sha.TransformBlock(counter, 0, 8, null, 0); + + // 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; + } + } + } + + sha.TransformFinalBlock(counter, 0, 0); + return sha.Hash; +#endif + } + } + + private int HandleUnderflow(byte[] buffer, int offset, int count) + { + // If this is zero we were called to create a new underflow buffer. + // Just transform as much as possible so we can feed from it as long as possible. + if (mUnderflow == 0) + { + int blockSize = (mEnding - mOffset) & ~15; + mUnderflow = mDecoder.TransformBlock(mBuffer, mOffset, blockSize, mBuffer, mOffset); + } + + if (count > mUnderflow) + { + count = mUnderflow; + } + + Buffer.BlockCopy(mBuffer, mOffset, buffer, offset, count); + mWritten += count; + mOffset += count; + mUnderflow -= count; + return count; + } + + #endregion } diff --git a/src/SharpCompress/Compressors/LZMA/Bcj2DecoderStream.cs b/src/SharpCompress/Compressors/LZMA/Bcj2DecoderStream.cs index fe66d4cd..fd18b16c 100644 --- a/src/SharpCompress/Compressors/LZMA/Bcj2DecoderStream.cs +++ b/src/SharpCompress/Compressors/LZMA/Bcj2DecoderStream.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.IO; @@ -36,10 +36,7 @@ internal class Bcj2DecoderStream : DecoderStream2 return (byte)bt; } - public void Dispose() - { - _mStream.Dispose(); - } + public void Dispose() => _mStream.Dispose(); } private class StatusDecoder @@ -51,10 +48,7 @@ internal class Bcj2DecoderStream : DecoderStream2 private uint _prob; - public StatusDecoder() - { - _prob = K_BIT_MODEL_TOTAL / 2; - } + public StatusDecoder() => _prob = K_BIT_MODEL_TOTAL / 2; public uint Decode(RangeDecoder decoder) { @@ -131,15 +125,9 @@ internal class Bcj2DecoderStream : DecoderStream2 _mJumpStream.Dispose(); } - private static bool IsJcc(byte b0, byte b1) - { - return b0 == 0x0F && (b1 & 0xF0) == 0x80; - } + private static bool IsJcc(byte b0, byte b1) => b0 == 0x0F && (b1 & 0xF0) == 0x80; - private static bool IsJ(byte b0, byte b1) - { - return (b1 & 0xFE) == 0xE8 || IsJcc(b0, b1); - } + private static bool IsJ(byte b0, byte b1) => (b1 & 0xFE) == 0xE8 || IsJcc(b0, b1); private static int GetIndex(byte b0, byte b1) { diff --git a/src/SharpCompress/Compressors/LZMA/CRC.cs b/src/SharpCompress/Compressors/LZMA/CRC.cs index cccce883..ea2969bd 100644 --- a/src/SharpCompress/Compressors/LZMA/CRC.cs +++ b/src/SharpCompress/Compressors/LZMA/CRC.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; namespace SharpCompress.Compressors.LZMA; @@ -47,15 +47,9 @@ internal static class Crc return Finish(crc); } - public static uint Finish(uint crc) - { - return ~crc; - } + public static uint Finish(uint crc) => ~crc; - public static uint Update(uint crc, byte bt) - { - return TABLE[(crc & 0xFF) ^ bt] ^ (crc >> 8); - } + public static uint Update(uint crc, byte bt) => TABLE[(crc & 0xFF) ^ bt] ^ (crc >> 8); public static uint Update(uint crc, uint value) { @@ -66,15 +60,10 @@ internal static class Crc ^ TABLE[0x000 + (crc >> 24)]; } - public static uint Update(uint crc, ulong value) - { - return Update(Update(crc, (uint)value), (uint)(value >> 32)); - } + public static uint Update(uint crc, ulong value) => + Update(Update(crc, (uint)value), (uint)(value >> 32)); - public static uint Update(uint crc, long value) - { - return Update(crc, (ulong)value); - } + public static uint Update(uint crc, long value) => Update(crc, (ulong)value); public static uint Update(uint crc, byte[] buffer, int offset, int length) { diff --git a/src/SharpCompress/Compressors/LZMA/DecoderStream.cs b/src/SharpCompress/Compressors/LZMA/DecoderStream.cs index 2b2e20b4..16865351 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,10 +14,7 @@ internal abstract class DecoderStream2 : Stream public override bool CanWrite => false; - public override void Flush() - { - throw new NotSupportedException(); - } + public override void Flush() => throw new NotSupportedException(); public override long Length => throw new NotSupportedException(); @@ -27,20 +24,12 @@ internal abstract class DecoderStream2 : Stream set => throw new NotSupportedException(); } - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } + public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException(); - public override void SetLength(long value) - { - throw new NotSupportedException(); - } + public override void SetLength(long value) => throw new NotSupportedException(); - public override void Write(byte[] buffer, int offset, int count) - { + public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException(); - } } internal static class DecoderStreamHelper diff --git a/src/SharpCompress/Compressors/LZMA/LZ/LzBinTree.cs b/src/SharpCompress/Compressors/LZMA/LZ/LzBinTree.cs index 958294a1..b123e5d5 100644 --- a/src/SharpCompress/Compressors/LZMA/LZ/LzBinTree.cs +++ b/src/SharpCompress/Compressors/LZMA/LZ/LzBinTree.cs @@ -49,15 +49,9 @@ internal sealed class BinTree : InWindow } } - public new void SetStream(Stream stream) - { - base.SetStream(stream); - } + public new void SetStream(Stream stream) => base.SetStream(stream); - public new void ReleaseStream() - { - base.ReleaseStream(); - } + public new void ReleaseStream() => base.ReleaseStream(); public new void Init() { @@ -83,20 +77,12 @@ internal sealed class BinTree : InWindow } } - public new byte GetIndexByte(int index) - { - return base.GetIndexByte(index); - } + public new byte GetIndexByte(int index) => base.GetIndexByte(index); - public new uint GetMatchLen(int index, uint distance, uint limit) - { - return base.GetMatchLen(index, distance, limit); - } + public new uint GetMatchLen(int index, uint distance, uint limit) => + base.GetMatchLen(index, distance, limit); - public new uint GetNumAvailableBytes() - { - return base.GetNumAvailableBytes(); - } + public new uint GetNumAvailableBytes() => base.GetNumAvailableBytes(); public void Create( uint historySize, @@ -437,8 +423,5 @@ internal sealed class BinTree : InWindow ReduceOffsets((int)subValue); } - public void SetCutValue(uint cutValue) - { - _cutValue = cutValue; - } + public void SetCutValue(uint cutValue) => _cutValue = cutValue; } diff --git a/src/SharpCompress/Compressors/LZMA/LZ/LzInWindow.cs b/src/SharpCompress/Compressors/LZMA/LZ/LzInWindow.cs index 26353624..9df3c27d 100644 --- a/src/SharpCompress/Compressors/LZMA/LZ/LzInWindow.cs +++ b/src/SharpCompress/Compressors/LZMA/LZ/LzInWindow.cs @@ -78,10 +78,7 @@ internal class InWindow } } - private void Free() - { - _bufferBase = null; - } + private void Free() => _bufferBase = null; public void Create(uint keepSizeBefore, uint keepSizeAfter, uint keepSizeReserv) { @@ -111,10 +108,7 @@ internal class InWindow } } - public void ReleaseStream() - { - _stream = null; - } + public void ReleaseStream() => _stream = null; public void Init() { @@ -139,10 +133,7 @@ internal class InWindow } } - public byte GetIndexByte(int index) - { - return _bufferBase[_bufferOffset + _pos + index]; - } + public byte GetIndexByte(int index) => _bufferBase[_bufferOffset + _pos + index]; // index + limit have not to exceed _keepSizeAfter; public uint GetMatchLen(int index, uint distance, uint limit) @@ -167,10 +158,7 @@ internal class InWindow return i; } - public uint GetNumAvailableBytes() - { - return _streamPos - _pos; - } + public uint GetNumAvailableBytes() => _streamPos - _pos; public void ReduceOffsets(int subValue) { diff --git a/src/SharpCompress/Compressors/LZMA/LZ/LzOutWindow.cs b/src/SharpCompress/Compressors/LZMA/LZ/LzOutWindow.cs index 42eb38b3..6efabba1 100644 --- a/src/SharpCompress/Compressors/LZMA/LZ/LzOutWindow.cs +++ b/src/SharpCompress/Compressors/LZMA/LZ/LzOutWindow.cs @@ -36,10 +36,7 @@ internal class OutWindow _limit = 0; } - public void Reset() - { - Create(_windowSize); - } + public void Reset() => Create(_windowSize); public void Init(Stream stream) { @@ -163,10 +160,7 @@ internal class OutWindow return len - size; } - public void SetLimit(long size) - { - _limit = _total + size; - } + public void SetLimit(long size) => _limit = _total + size; public bool HasSpace => _pos < _windowSize && _total < _limit; diff --git a/src/SharpCompress/Compressors/LZMA/LZipStream.cs b/src/SharpCompress/Compressors/LZMA/LZipStream.cs index d55f8d7e..4b63a621 100644 --- a/src/SharpCompress/Compressors/LZMA/LZipStream.cs +++ b/src/SharpCompress/Compressors/LZMA/LZipStream.cs @@ -104,10 +104,7 @@ public sealed class LZipStream : Stream public override bool CanWrite => Mode == CompressionMode.Compress; - public override void Flush() - { - _stream.Flush(); - } + public override void Flush() => _stream.Flush(); // TODO: Both Length and Position are sometimes feasible, but would require // reading the output length when we initialize. @@ -130,10 +127,7 @@ public sealed class LZipStream : Stream #if !NETFRAMEWORK && !NETSTANDARD2_0 - public override int Read(Span buffer) - { - return _stream.Read(buffer); - } + public override int Read(Span buffer) => _stream.Read(buffer); public override void Write(ReadOnlySpan buffer) { diff --git a/src/SharpCompress/Compressors/LZMA/Log.cs b/src/SharpCompress/Compressors/LZMA/Log.cs index d19a46d2..e954e259 100644 --- a/src/SharpCompress/Compressors/LZMA/Log.cs +++ b/src/SharpCompress/Compressors/LZMA/Log.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; @@ -9,15 +9,9 @@ internal static class Log private static readonly Stack INDENT = new Stack(); private static bool NEEDS_INDENT = true; - static Log() - { - INDENT.Push(""); - } + static Log() => INDENT.Push(""); - public static void PushIndent(string indent = " ") - { - INDENT.Push(INDENT.Peek() + indent); - } + public static void PushIndent(string indent = " ") => INDENT.Push(INDENT.Peek() + indent); public static void PopIndent() { diff --git a/src/SharpCompress/Compressors/LZMA/LzmaBase.cs b/src/SharpCompress/Compressors/LZMA/LzmaBase.cs index e1d98639..d8bfa062 100644 --- a/src/SharpCompress/Compressors/LZMA/LzmaBase.cs +++ b/src/SharpCompress/Compressors/LZMA/LzmaBase.cs @@ -14,10 +14,7 @@ internal abstract class Base { public uint _index; - public void Init() - { - _index = 0; - } + public void Init() => _index = 0; public void UpdateChar() { @@ -35,25 +32,13 @@ internal abstract class Base } } - public void UpdateMatch() - { - _index = (uint)(_index < 7 ? 7 : 10); - } + public void UpdateMatch() => _index = (uint)(_index < 7 ? 7 : 10); - public void UpdateRep() - { - _index = (uint)(_index < 7 ? 8 : 11); - } + public void UpdateRep() => _index = (uint)(_index < 7 ? 8 : 11); - public void UpdateShortRep() - { - _index = (uint)(_index < 7 ? 9 : 11); - } + public void UpdateShortRep() => _index = (uint)(_index < 7 ? 9 : 11); - public bool IsCharState() - { - return _index < 7; - } + public bool IsCharState() => _index < 7; } public const int K_NUM_POS_SLOT_BITS = 6; diff --git a/src/SharpCompress/Compressors/LZMA/LzmaDecoder.cs b/src/SharpCompress/Compressors/LZMA/LzmaDecoder.cs index e22fbaf3..31039761 100644 --- a/src/SharpCompress/Compressors/LZMA/LzmaDecoder.cs +++ b/src/SharpCompress/Compressors/LZMA/LzmaDecoder.cs @@ -66,10 +66,7 @@ public class Decoder : ICoder, ISetDecoderProperties // ,System.IO.Stream { private BitDecoder[] _decoders; - public void Create() - { - _decoders = new BitDecoder[0x300]; - } + public void Create() => _decoders = new BitDecoder[0x300]; public void Init() { @@ -142,25 +139,18 @@ public class Decoder : ICoder, ISetDecoderProperties // ,System.IO.Stream } } - private uint GetState(uint pos, byte prevByte) - { - return ((pos & _posMask) << _numPrevBits) + (uint)(prevByte >> (8 - _numPrevBits)); - } + private uint GetState(uint pos, byte prevByte) => + ((pos & _posMask) << _numPrevBits) + (uint)(prevByte >> (8 - _numPrevBits)); - public byte DecodeNormal(RangeCoder.Decoder rangeDecoder, uint pos, byte prevByte) - { - return _coders[GetState(pos, prevByte)].DecodeNormal(rangeDecoder); - } + public byte DecodeNormal(RangeCoder.Decoder rangeDecoder, uint pos, byte prevByte) => + _coders[GetState(pos, prevByte)].DecodeNormal(rangeDecoder); public byte DecodeWithMatchByte( RangeCoder.Decoder rangeDecoder, uint pos, byte prevByte, byte matchByte - ) - { - return _coders[GetState(pos, prevByte)].DecodeWithMatchByte(rangeDecoder, matchByte); - } + ) => _coders[GetState(pos, prevByte)].DecodeWithMatchByte(rangeDecoder, matchByte); } private OutWindow _outWindow; diff --git a/src/SharpCompress/Compressors/LZMA/LzmaEncoder.cs b/src/SharpCompress/Compressors/LZMA/LzmaEncoder.cs index 1495ec2c..a802bc86 100644 --- a/src/SharpCompress/Compressors/LZMA/LzmaEncoder.cs +++ b/src/SharpCompress/Compressors/LZMA/LzmaEncoder.cs @@ -84,10 +84,7 @@ internal class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties { private BitEncoder[] _encoders; - public void Create() - { - _encoders = new BitEncoder[0x300]; - } + public void Create() => _encoders = new BitEncoder[0x300]; public void Init() { @@ -188,12 +185,8 @@ internal class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties } } - public Encoder2 GetSubCoder(uint pos, byte prevByte) - { - return _coders[ - ((pos & _posMask) << _numPrevBits) + (uint)(prevByte >> (8 - _numPrevBits)) - ]; - } + public Encoder2 GetSubCoder(uint pos, byte prevByte) => + _coders[((pos & _posMask) << _numPrevBits) + (uint)(prevByte >> (8 - _numPrevBits))]; } private class LenEncoder @@ -298,15 +291,10 @@ internal class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties private uint _tableSize; private readonly uint[] _counters = new uint[Base.K_NUM_POS_STATES_ENCODING_MAX]; - public void SetTableSize(uint tableSize) - { - _tableSize = tableSize; - } + public void SetTableSize(uint tableSize) => _tableSize = tableSize; - public uint GetPrice(uint symbol, uint posState) - { - return _prices[(posState * Base.K_NUM_LEN_SYMBOLS) + symbol]; - } + public uint GetPrice(uint symbol, uint posState) => + _prices[(posState * Base.K_NUM_LEN_SYMBOLS) + symbol]; private void UpdateTable(uint posState) { @@ -366,10 +354,7 @@ internal class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties _prev1IsChar = false; } - public bool IsShortRep() - { - return (_backPrev == 0); - } + public bool IsShortRep() => (_backPrev == 0); } private readonly Optimal[] _optimum = new Optimal[K_NUM_OPTS]; @@ -488,10 +473,7 @@ internal class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties } } - private void SetWriteEndMarkerMode(bool writeEndMarker) - { - _writeEndMark = writeEndMarker; - } + private void SetWriteEndMarkerMode(bool writeEndMarker) => _writeEndMark = writeEndMarker; private void Init() { @@ -561,11 +543,9 @@ internal class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties } } - private uint GetRepLen1Price(Base.State state, uint posState) - { - return _isRepG0[state._index].GetPrice0() - + _isRep0Long[(state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState].GetPrice0(); - } + private uint GetRepLen1Price(Base.State state, uint posState) => + _isRepG0[state._index].GetPrice0() + + _isRep0Long[(state._index << Base.K_NUM_POS_STATES_BITS_MAX) + posState].GetPrice0(); private uint GetPureRepPrice(uint repIndex, Base.State state, uint posState) { @@ -1543,15 +1523,9 @@ internal class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties } } - private void SetOutStream(Stream outStream) - { - _rangeEncoder.SetStream(outStream); - } + private void SetOutStream(Stream outStream) => _rangeEncoder.SetStream(outStream); - private void ReleaseOutStream() - { - _rangeEncoder.ReleaseStream(); - } + private void ReleaseOutStream() => _rangeEncoder.ReleaseStream(); private void ReleaseStreams() { @@ -1892,8 +1866,5 @@ internal class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties private uint _trainSize; - public void SetTrainSize(uint trainSize) - { - _trainSize = trainSize; - } + public void SetTrainSize(uint trainSize) => _trainSize = trainSize; } diff --git a/src/SharpCompress/Compressors/LZMA/LzmaStream.cs b/src/SharpCompress/Compressors/LZMA/LzmaStream.cs index aa7a42c9..01fddf17 100644 --- a/src/SharpCompress/Compressors/LZMA/LzmaStream.cs +++ b/src/SharpCompress/Compressors/LZMA/LzmaStream.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable using System; using System.Buffers.Binary; @@ -304,15 +304,9 @@ public class LzmaStream : Stream } } - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } + public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException(); - public override void SetLength(long value) - { - throw new NotSupportedException(); - } + public override void SetLength(long value) => throw new NotSupportedException(); public override void Write(byte[] buffer, int offset, int count) { diff --git a/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoder.cs b/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoder.cs index 3694286c..87906809 100644 --- a/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoder.cs +++ b/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoder.cs @@ -17,15 +17,9 @@ internal class Encoder //long StartPosition; - public void SetStream(Stream stream) - { - _stream = stream; - } + public void SetStream(Stream stream) => _stream = stream; - public void ReleaseStream() - { - _stream = null; - } + public void ReleaseStream() => _stream = null; public void Init() { @@ -45,15 +39,9 @@ internal class Encoder } } - public void FlushStream() - { - _stream.Flush(); - } + public void FlushStream() => _stream.Flush(); - public void CloseStream() - { - _stream.Dispose(); - } + public void CloseStream() => _stream.Dispose(); public void Encode(uint start, uint size, uint total) { @@ -118,13 +106,10 @@ internal class Encoder } } - public long GetProcessedSizeAdd() - { - return -1; + public long GetProcessedSizeAdd() => -1; - //return _cacheSize + Stream.Position - StartPosition + 4; - // (long)Stream.GetProcessedSize(); - } + //return _cacheSize + Stream.Position - StartPosition + 4; + // (long)Stream.GetProcessedSize(); } internal class Decoder @@ -151,16 +136,11 @@ internal class Decoder _total = 5; } - public void ReleaseStream() - { + public void ReleaseStream() => // Stream.ReleaseStream(); _stream = null; - } - public void CloseStream() - { - _stream.Dispose(); - } + public void CloseStream() => _stream.Dispose(); public void Normalize() { @@ -182,10 +162,7 @@ internal class Decoder } } - public uint GetThreshold(uint total) - { - return _code / (_range /= total); - } + public uint GetThreshold(uint total) => _code / (_range /= total); public void Decode(uint start, uint size) { diff --git a/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoderBit.cs b/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoderBit.cs index 2123f204..dd93b526 100644 --- a/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoderBit.cs +++ b/src/SharpCompress/Compressors/LZMA/RangeCoder/RangeCoderBit.cs @@ -10,10 +10,7 @@ internal struct BitEncoder private uint _prob; - public void Init() - { - _prob = K_BIT_MODEL_TOTAL >> 1; - } + public void Init() => _prob = K_BIT_MODEL_TOTAL >> 1; public void UpdateModel(uint symbol) { @@ -70,23 +67,15 @@ internal struct BitEncoder } } - public uint GetPrice(uint symbol) - { - return PROB_PRICES[ + public uint GetPrice(uint symbol) => + PROB_PRICES[ (((_prob - symbol) ^ ((-(int)symbol))) & (K_BIT_MODEL_TOTAL - 1)) >> K_NUM_MOVE_REDUCING_BITS ]; - } - public uint GetPrice0() - { - return PROB_PRICES[_prob >> K_NUM_MOVE_REDUCING_BITS]; - } + public uint GetPrice0() => PROB_PRICES[_prob >> K_NUM_MOVE_REDUCING_BITS]; - public uint GetPrice1() - { - return PROB_PRICES[(K_BIT_MODEL_TOTAL - _prob) >> K_NUM_MOVE_REDUCING_BITS]; - } + public uint GetPrice1() => PROB_PRICES[(K_BIT_MODEL_TOTAL - _prob) >> K_NUM_MOVE_REDUCING_BITS]; } internal struct BitDecoder @@ -109,10 +98,7 @@ internal struct BitDecoder } } - public void Init() - { - _prob = K_BIT_MODEL_TOTAL >> 1; - } + public void Init() => _prob = K_BIT_MODEL_TOTAL >> 1; public uint Decode(Decoder rangeDecoder) { diff --git a/src/SharpCompress/Compressors/LZMA/Utilites/CrcBuilderStream.cs b/src/SharpCompress/Compressors/LZMA/Utilites/CrcBuilderStream.cs index 6e8c608f..344924be 100644 --- a/src/SharpCompress/Compressors/LZMA/Utilites/CrcBuilderStream.cs +++ b/src/SharpCompress/Compressors/LZMA/Utilites/CrcBuilderStream.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; namespace SharpCompress.Compressors.LZMA.Utilites; @@ -56,20 +56,12 @@ internal class CrcBuilderStream : Stream set => throw new NotSupportedException(); } - public override int Read(byte[] buffer, int offset, int count) - { + public override int Read(byte[] buffer, int offset, int count) => throw new InvalidOperationException(); - } - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } + public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException(); - public override void SetLength(long value) - { - throw new NotSupportedException(); - } + public override void SetLength(long value) => throw new NotSupportedException(); public override void Write(byte[] buffer, int offset, int count) { diff --git a/src/SharpCompress/Compressors/LZMA/Utilites/CrcCheckStream.cs b/src/SharpCompress/Compressors/LZMA/Utilites/CrcCheckStream.cs index c81dbb1d..c10efda1 100644 --- a/src/SharpCompress/Compressors/LZMA/Utilites/CrcCheckStream.cs +++ b/src/SharpCompress/Compressors/LZMA/Utilites/CrcCheckStream.cs @@ -84,20 +84,12 @@ public class CrcCheckStream : Stream set => throw new NotSupportedException(); } - public override int Read(byte[] buffer, int offset, int count) - { + public override int Read(byte[] buffer, int offset, int count) => throw new InvalidOperationException(); - } - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } + public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException(); - public override void SetLength(long value) - { - throw new NotSupportedException(); - } + public override void SetLength(long value) => throw new NotSupportedException(); public override void Write(byte[] buffer, int offset, int count) { diff --git a/src/SharpCompress/Compressors/PPMd/H/FreqData.cs b/src/SharpCompress/Compressors/PPMd/H/FreqData.cs index bb7a630d..5811b59b 100644 --- a/src/SharpCompress/Compressors/PPMd/H/FreqData.cs +++ b/src/SharpCompress/Compressors/PPMd/H/FreqData.cs @@ -22,30 +22,16 @@ internal class FreqData : Pointer set => BinaryPrimitives.WriteInt16LittleEndian(Memory.AsSpan(Address), (short)value); } - internal FreqData Initialize(byte[] mem) - { - return Initialize(mem); - } + internal FreqData Initialize(byte[] mem) => Initialize(mem); - internal void IncrementSummFreq(int dSummFreq) - { - SummFreq += (short)dSummFreq; - } + internal void IncrementSummFreq(int dSummFreq) => SummFreq += (short)dSummFreq; - internal int GetStats() - { - return BinaryPrimitives.ReadInt32LittleEndian(Memory.AsSpan(Address + 2)); - } + internal int GetStats() => BinaryPrimitives.ReadInt32LittleEndian(Memory.AsSpan(Address + 2)); - internal virtual void SetStats(State state) - { - SetStats(state.Address); - } + internal virtual void SetStats(State state) => SetStats(state.Address); - internal void SetStats(int state) - { + internal void SetStats(int state) => BinaryPrimitives.WriteInt32LittleEndian(Memory.AsSpan(Address + 2), state); - } public override string ToString() { diff --git a/src/SharpCompress/Compressors/PPMd/H/ModelPPM.cs b/src/SharpCompress/Compressors/PPMd/H/ModelPPM.cs index 1675acf7..3b2d22ba 100644 --- a/src/SharpCompress/Compressors/PPMd/H/ModelPPM.cs +++ b/src/SharpCompress/Compressors/PPMd/H/ModelPPM.cs @@ -400,35 +400,17 @@ internal class ModelPpm return (symbol); } - public virtual See2Context[][] GetSee2Cont() - { - return _see2Cont; - } + public virtual See2Context[][] GetSee2Cont() => _see2Cont; - public virtual void IncEscCount(int dEscCount) - { - EscCount += dEscCount; - } + public virtual void IncEscCount(int dEscCount) => EscCount += dEscCount; - public virtual void IncRunLength(int dRunLength) - { - RunLength += dRunLength; - } + public virtual void IncRunLength(int dRunLength) => RunLength += dRunLength; - public virtual int[] GetHb2Flag() - { - return _hb2Flag; - } + public virtual int[] GetHb2Flag() => _hb2Flag; - public virtual int[] GetNs2BsIndx() - { - return _ns2BsIndx; - } + public virtual int[] GetNs2BsIndx() => _ns2BsIndx; - public virtual int[] GetNs2Indx() - { - return _ns2Indx; - } + public virtual int[] GetNs2Indx() => _ns2Indx; private int CreateSuccessors(bool skip, State p1) { diff --git a/src/SharpCompress/Compressors/PPMd/H/PPMContext.cs b/src/SharpCompress/Compressors/PPMd/H/PPMContext.cs index b27da093..a573aa8d 100644 --- a/src/SharpCompress/Compressors/PPMd/H/PPMContext.cs +++ b/src/SharpCompress/Compressors/PPMd/H/PPMContext.cs @@ -95,15 +95,9 @@ internal class PpmContext : Pointer return Initialize(mem); } - internal State GetOneState() - { - return _oneState; - } + internal State GetOneState() => _oneState; - internal void SetOneState(StateRef oneState) - { - _oneState.SetValues(oneState); - } + internal void SetOneState(StateRef oneState) => _oneState.SetValues(oneState); internal int GetSuffix() { @@ -114,10 +108,7 @@ internal class PpmContext : Pointer return _suffix; } - internal void SetSuffix(PpmContext suffix) - { - SetSuffix(suffix.Address); - } + internal void SetSuffix(PpmContext suffix) => SetSuffix(suffix.Address); internal void SetSuffix(int suffix) { @@ -263,10 +254,8 @@ internal class PpmContext : Pointer return ret; } - internal int GetMean(int summ, int shift, int round) - { - return (Utility.URShift((summ + (1 << (shift - round))), (shift))); - } + internal int GetMean(int summ, int shift, int round) => + (Utility.URShift((summ + (1 << (shift - round))), (shift))); internal void DecodeBinSymbol(ModelPpm model) { @@ -558,8 +547,5 @@ internal class PpmContext : Pointer return buffer.ToString(); } - static PpmContext() - { - UNION_SIZE = Math.Max(FreqData.SIZE, State.SIZE); - } + static PpmContext() => UNION_SIZE = Math.Max(FreqData.SIZE, State.SIZE); } diff --git a/src/SharpCompress/Compressors/PPMd/H/Pointer.cs b/src/SharpCompress/Compressors/PPMd/H/Pointer.cs index b7f04d48..b304b359 100644 --- a/src/SharpCompress/Compressors/PPMd/H/Pointer.cs +++ b/src/SharpCompress/Compressors/PPMd/H/Pointer.cs @@ -7,10 +7,7 @@ internal abstract class Pointer /// Initialize the object with the array (may be null) /// the byte array /// - internal Pointer(byte[] mem) - { - Memory = mem; - } + internal Pointer(byte[] mem) => Memory = mem; internal byte[] Memory { get; private set; } diff --git a/src/SharpCompress/Compressors/PPMd/H/RangeCoder.cs b/src/SharpCompress/Compressors/PPMd/H/RangeCoder.cs index 67f437ad..6659cb83 100644 --- a/src/SharpCompress/Compressors/PPMd/H/RangeCoder.cs +++ b/src/SharpCompress/Compressors/PPMd/H/RangeCoder.cs @@ -131,10 +131,7 @@ internal class SubRange _highCount, _scale; - internal void IncScale(int dScale) - { - Scale += dScale; - } + internal void IncScale(int dScale) => Scale += dScale; internal long HighCount { diff --git a/src/SharpCompress/Compressors/PPMd/H/RarMemBlock.cs b/src/SharpCompress/Compressors/PPMd/H/RarMemBlock.cs index cdf8cef8..9fe3958a 100644 --- a/src/SharpCompress/Compressors/PPMd/H/RarMemBlock.cs +++ b/src/SharpCompress/Compressors/PPMd/H/RarMemBlock.cs @@ -67,10 +67,7 @@ internal class RarMemBlock : Pointer return _next; } - internal void SetNext(RarMemBlock next) - { - SetNext(next.Address); - } + internal void SetNext(RarMemBlock next) => SetNext(next.Address); internal void SetNext(int next) { @@ -108,10 +105,7 @@ internal class RarMemBlock : Pointer return _prev; } - internal void SetPrev(RarMemBlock prev) - { - SetPrev(prev.Address); - } + internal void SetPrev(RarMemBlock prev) => SetPrev(prev.Address); internal void SetPrev(int prev) { diff --git a/src/SharpCompress/Compressors/PPMd/H/RarNode.cs b/src/SharpCompress/Compressors/PPMd/H/RarNode.cs index 5a9e5a29..614e62cb 100644 --- a/src/SharpCompress/Compressors/PPMd/H/RarNode.cs +++ b/src/SharpCompress/Compressors/PPMd/H/RarNode.cs @@ -21,10 +21,7 @@ internal class RarNode : Pointer return _next; } - internal void SetNext(RarNode next) - { - SetNext(next.Address); - } + internal void SetNext(RarNode next) => SetNext(next.Address); internal void SetNext(int next) { diff --git a/src/SharpCompress/Compressors/PPMd/H/SEE2Context.cs b/src/SharpCompress/Compressors/PPMd/H/SEE2Context.cs index 742bd279..0278294a 100644 --- a/src/SharpCompress/Compressors/PPMd/H/SEE2Context.cs +++ b/src/SharpCompress/Compressors/PPMd/H/SEE2Context.cs @@ -62,10 +62,7 @@ internal class See2Context _shift &= 0xff; } - public virtual void IncSumm(int dSumm) - { - Summ += dSumm; - } + public virtual void IncSumm(int dSumm) => Summ += dSumm; public override string ToString() { diff --git a/src/SharpCompress/Compressors/PPMd/H/State.cs b/src/SharpCompress/Compressors/PPMd/H/State.cs index 186476c3..dc901c2e 100644 --- a/src/SharpCompress/Compressors/PPMd/H/State.cs +++ b/src/SharpCompress/Compressors/PPMd/H/State.cs @@ -22,30 +22,18 @@ internal sealed class State : Pointer set => Memory[Address + 1] = (byte)value; } - internal State Initialize(byte[] mem) - { - return Initialize(mem); - } + internal State Initialize(byte[] mem) => Initialize(mem); - internal void IncrementFreq(int dFreq) - { + internal void IncrementFreq(int dFreq) => Memory[Address + 1] = (byte)(Memory[Address + 1] + dFreq); - } - internal int GetSuccessor() - { - return BinaryPrimitives.ReadInt32LittleEndian(Memory.AsSpan(Address + 2)); - } + internal int GetSuccessor() => + BinaryPrimitives.ReadInt32LittleEndian(Memory.AsSpan(Address + 2)); - internal void SetSuccessor(PpmContext successor) - { - SetSuccessor(successor.Address); - } + internal void SetSuccessor(PpmContext successor) => SetSuccessor(successor.Address); - internal void SetSuccessor(int successor) - { + internal void SetSuccessor(int successor) => BinaryPrimitives.WriteInt32LittleEndian(Memory.AsSpan(Address + 2), successor); - } internal void SetValues(StateRef state) { @@ -54,10 +42,8 @@ internal sealed class State : Pointer SetSuccessor(state.GetSuccessor()); } - internal void SetValues(State ptr) - { + internal void SetValues(State ptr) => Array.Copy(ptr.Memory, ptr.Address, Memory, Address, SIZE); - } internal State DecrementAddress() { diff --git a/src/SharpCompress/Compressors/PPMd/H/StateRef.cs b/src/SharpCompress/Compressors/PPMd/H/StateRef.cs index 9df43814..8ef56a09 100644 --- a/src/SharpCompress/Compressors/PPMd/H/StateRef.cs +++ b/src/SharpCompress/Compressors/PPMd/H/StateRef.cs @@ -32,30 +32,15 @@ internal class StateRef } } - public virtual void IncrementFreq(int dFreq) - { - _freq = (_freq + dFreq) & 0xff; - } + public virtual void IncrementFreq(int dFreq) => _freq = (_freq + dFreq) & 0xff; - public virtual void DecrementFreq(int dFreq) - { - _freq = (_freq - dFreq) & 0xff; - } + public virtual void DecrementFreq(int dFreq) => _freq = (_freq - dFreq) & 0xff; - public virtual int GetSuccessor() - { - return _successor; - } + public virtual int GetSuccessor() => _successor; - public virtual void SetSuccessor(PpmContext successor) - { - SetSuccessor(successor.Address); - } + public virtual void SetSuccessor(PpmContext successor) => SetSuccessor(successor.Address); - public virtual void SetSuccessor(int successor) - { - _successor = successor; - } + public virtual void SetSuccessor(int successor) => _successor = successor; public override string ToString() { diff --git a/src/SharpCompress/Compressors/PPMd/H/SubAllocator.cs b/src/SharpCompress/Compressors/PPMd/H/SubAllocator.cs index 43aaeca2..e507f3c3 100644 --- a/src/SharpCompress/Compressors/PPMd/H/SubAllocator.cs +++ b/src/SharpCompress/Compressors/PPMd/H/SubAllocator.cs @@ -77,15 +77,9 @@ internal class SubAllocator private RarMemBlock _tempRarMemBlock2; private RarMemBlock _tempRarMemBlock3; - public SubAllocator() - { - Clean(); - } + public SubAllocator() => Clean(); - public virtual void Clean() - { - _subAllocatorSize = 0; - } + public virtual void Clean() => _subAllocatorSize = 0; private void InsertNode(int p, int indx) { @@ -95,10 +89,7 @@ internal class SubAllocator _freeList[indx].SetNext(temp); } - public virtual void IncPText() - { - _pText++; - } + public virtual void IncPText() => _pText++; private int RemoveNode(int indx) { @@ -109,17 +100,11 @@ internal class SubAllocator return retVal; } - private int U2B(int nu) - { - return UNIT_SIZE * nu; - } + private int U2B(int nu) => UNIT_SIZE * nu; /* memblockptr */ - private int MbPtr(int basePtr, int items) - { - return (basePtr + U2B(items)); - } + private int MbPtr(int basePtr, int items) => (basePtr + U2B(items)); private void SplitBlock(int pv, int oldIndx, int newIndx) { @@ -154,10 +139,7 @@ internal class SubAllocator } } - public virtual int GetAllocatedMemory() - { - return _subAllocatorSize; - } + public virtual int GetAllocatedMemory() => _subAllocatorSize; public virtual bool StartSubAllocator(int saSize) { @@ -368,15 +350,9 @@ internal class SubAllocator return oldPtr; } - public virtual void FreeUnits(int ptr, int oldNu) - { - InsertNode(ptr, _units2Indx[oldNu - 1]); - } + public virtual void FreeUnits(int ptr, int oldNu) => InsertNode(ptr, _units2Indx[oldNu - 1]); - public virtual void DecPText(int dPText) - { - PText -= dPText; - } + public virtual void DecPText(int dPText) => PText -= dPText; public virtual void InitSubAllocator() { @@ -419,10 +395,7 @@ internal class SubAllocator } } - private int SizeOfFreeList() - { - return _freeList.Length * RarNode.SIZE; - } + private int SizeOfFreeList() => _freeList.Length * RarNode.SIZE; // Debug // public void dumpHeap() { @@ -465,8 +438,5 @@ internal class SubAllocator return buffer.ToString(); } - static SubAllocator() - { - UNIT_SIZE = Math.Max(PpmContext.SIZE, RarMemBlock.SIZE); - } + static SubAllocator() => UNIT_SIZE = Math.Max(PpmContext.SIZE, RarMemBlock.SIZE); } diff --git a/src/SharpCompress/Compressors/PPMd/I1/Allocator.cs b/src/SharpCompress/Compressors/PPMd/I1/Allocator.cs index ac270a3d..7b677a93 100644 --- a/src/SharpCompress/Compressors/PPMd/I1/Allocator.cs +++ b/src/SharpCompress/Compressors/PPMd/I1/Allocator.cs @@ -89,10 +89,7 @@ internal class Allocator #region Public Methods - public Allocator() - { - _memoryNodes = new MemoryNode[INDEX_COUNT]; - } + public Allocator() => _memoryNodes = new MemoryNode[INDEX_COUNT]; /// /// Initialize or reset the memory allocator (so that the single, large array can be re-used without destroying diff --git a/src/SharpCompress/Compressors/PPMd/I1/Coder.cs b/src/SharpCompress/Compressors/PPMd/I1/Coder.cs index 75a4e65b..b033a6f8 100644 --- a/src/SharpCompress/Compressors/PPMd/I1/Coder.cs +++ b/src/SharpCompress/Compressors/PPMd/I1/Coder.cs @@ -89,15 +89,10 @@ internal class Coder } } - public uint RangeGetCurrentCount() - { - return (_code - _low) / (_range /= _scale); - } + public uint RangeGetCurrentCount() => (_code - _low) / (_range /= _scale); - public uint RangeGetCurrentShiftCount(int rangeShift) - { - return (_code - _low) / (_range >>= rangeShift); - } + public uint RangeGetCurrentShiftCount(int rangeShift) => + (_code - _low) / (_range >>= rangeShift); public void RangeRemoveSubrange() { diff --git a/src/SharpCompress/Compressors/PPMd/I1/MemoryNode.cs b/src/SharpCompress/Compressors/PPMd/I1/MemoryNode.cs index e9c64e53..5e978c5c 100644 --- a/src/SharpCompress/Compressors/PPMd/I1/MemoryNode.cs +++ b/src/SharpCompress/Compressors/PPMd/I1/MemoryNode.cs @@ -117,10 +117,7 @@ internal struct MemoryNode /// /// Unlink this memory node. /// - public void Unlink() - { - Next = Next.Next; - } + public void Unlink() => Next = Next.Next; /// /// Insert the memory node into the linked list. @@ -152,10 +149,8 @@ internal struct MemoryNode /// /// /// - public static implicit operator MemoryNode(Pointer pointer) - { - return new MemoryNode(pointer._address, pointer._memory); - } + public static implicit operator MemoryNode(Pointer pointer) => + new MemoryNode(pointer._address, pointer._memory); /// /// Allow pointer-like addition on a memory node. @@ -211,10 +206,8 @@ internal struct MemoryNode /// /// /// - public static bool operator ==(MemoryNode memoryNode1, MemoryNode memoryNode2) - { - return memoryNode1._address == memoryNode2._address; - } + public static bool operator ==(MemoryNode memoryNode1, MemoryNode memoryNode2) => + memoryNode1._address == memoryNode2._address; /// /// Compare two memory nodes. @@ -222,10 +215,8 @@ internal struct MemoryNode /// /// /// - public static bool operator !=(MemoryNode memoryNode1, MemoryNode memoryNode2) - { - return memoryNode1._address != memoryNode2._address; - } + public static bool operator !=(MemoryNode memoryNode1, MemoryNode memoryNode2) => + memoryNode1._address != memoryNode2._address; /// /// Indicates whether this instance and a specified object are equal. @@ -245,8 +236,5 @@ internal struct MemoryNode /// Returns the hash code for this instance. /// /// A 32-bit signed integer that is the hash code for this instance. - public override int GetHashCode() - { - return _address.GetHashCode(); - } + public override int GetHashCode() => _address.GetHashCode(); } diff --git a/src/SharpCompress/Compressors/PPMd/I1/Model.cs b/src/SharpCompress/Compressors/PPMd/I1/Model.cs index f630aced..786cb0e7 100644 --- a/src/SharpCompress/Compressors/PPMd/I1/Model.cs +++ b/src/SharpCompress/Compressors/PPMd/I1/Model.cs @@ -938,10 +938,8 @@ internal partial class Model state1.Successor = state2.Successor; } - private static int Mean(int sum, int shift, int round) - { - return (sum + (1 << (shift - round))) >> shift; - } + private static int Mean(int sum, int shift, int round) => + (sum + (1 << (shift - round))) >> shift; private void ClearMask() { diff --git a/src/SharpCompress/Compressors/PPMd/I1/Pointer.cs b/src/SharpCompress/Compressors/PPMd/I1/Pointer.cs index 48fa7fff..72c557ba 100644 --- a/src/SharpCompress/Compressors/PPMd/I1/Pointer.cs +++ b/src/SharpCompress/Compressors/PPMd/I1/Pointer.cs @@ -68,30 +68,24 @@ internal struct Pointer /// /// /// - public static implicit operator Pointer(MemoryNode memoryNode) - { - return new Pointer(memoryNode._address, memoryNode._memory); - } + public static implicit operator Pointer(MemoryNode memoryNode) => + new Pointer(memoryNode._address, memoryNode._memory); /// /// Allow a to be implicitly converted to a . /// /// /// - public static implicit operator Pointer(Model.PpmContext context) - { - return new Pointer(context._address, context._memory); - } + public static implicit operator Pointer(Model.PpmContext context) => + new Pointer(context._address, context._memory); /// /// Allow a to be implicitly converted to a . /// /// /// - public static implicit operator Pointer(PpmState state) - { - return new Pointer(state._address, state._memory); - } + public static implicit operator Pointer(PpmState state) => + new Pointer(state._address, state._memory); /// /// Increase the address of a pointer by the given number of bytes. @@ -330,10 +324,8 @@ internal struct Pointer /// /// /// - public static bool operator ==(Pointer pointer1, Pointer pointer2) - { - return pointer1._address == pointer2._address; - } + public static bool operator ==(Pointer pointer1, Pointer pointer2) => + pointer1._address == pointer2._address; /// /// Compare two pointers. @@ -341,10 +333,8 @@ internal struct Pointer /// /// /// - public static bool operator !=(Pointer pointer1, Pointer pointer2) - { - return pointer1._address != pointer2._address; - } + public static bool operator !=(Pointer pointer1, Pointer pointer2) => + pointer1._address != pointer2._address; /// /// Indicates whether this instance and a specified object are equal. @@ -364,8 +354,5 @@ internal struct Pointer /// Returns the hash code for this instance. /// /// A 32-bit signed integer that is the hash code for this instance. - public override int GetHashCode() - { - return _address.GetHashCode(); - } + public override int GetHashCode() => _address.GetHashCode(); } diff --git a/src/SharpCompress/Compressors/PPMd/I1/PpmContext.cs b/src/SharpCompress/Compressors/PPMd/I1/PpmContext.cs index 9df07688..a37d278d 100644 --- a/src/SharpCompress/Compressors/PPMd/I1/PpmContext.cs +++ b/src/SharpCompress/Compressors/PPMd/I1/PpmContext.cs @@ -185,10 +185,8 @@ internal partial class Model /// /// /// - public static implicit operator PpmContext(Pointer pointer) - { - return new PpmContext(pointer._address, pointer._memory); - } + public static implicit operator PpmContext(Pointer pointer) => + new PpmContext(pointer._address, pointer._memory); /// /// Allow pointer-like addition on a PPM context. @@ -220,10 +218,8 @@ internal partial class Model /// /// /// - public static bool operator <=(PpmContext context1, PpmContext context2) - { - return context1._address <= context2._address; - } + public static bool operator <=(PpmContext context1, PpmContext context2) => + context1._address <= context2._address; /// /// Compare two PPM contexts. @@ -231,10 +227,8 @@ internal partial class Model /// /// /// - public static bool operator >=(PpmContext context1, PpmContext context2) - { - return context1._address >= context2._address; - } + public static bool operator >=(PpmContext context1, PpmContext context2) => + context1._address >= context2._address; /// /// Compare two PPM contexts. @@ -242,10 +236,8 @@ internal partial class Model /// /// /// - public static bool operator ==(PpmContext context1, PpmContext context2) - { - return context1._address == context2._address; - } + public static bool operator ==(PpmContext context1, PpmContext context2) => + context1._address == context2._address; /// /// Compare two PPM contexts. @@ -253,10 +245,8 @@ internal partial class Model /// /// /// - public static bool operator !=(PpmContext context1, PpmContext context2) - { - return context1._address != context2._address; - } + public static bool operator !=(PpmContext context1, PpmContext context2) => + context1._address != context2._address; /// /// Indicates whether this instance and a specified object are equal. @@ -276,10 +266,7 @@ internal partial class Model /// Returns the hash code for this instance. /// /// A 32-bit signed integer that is the hash code for this instance. - public override int GetHashCode() - { - return _address.GetHashCode(); - } + public override int GetHashCode() => _address.GetHashCode(); } private void EncodeBinarySymbol(int symbol, PpmContext context) diff --git a/src/SharpCompress/Compressors/PPMd/I1/PpmState.cs b/src/SharpCompress/Compressors/PPMd/I1/PpmState.cs index 6ed4f9a5..757afd00 100644 --- a/src/SharpCompress/Compressors/PPMd/I1/PpmState.cs +++ b/src/SharpCompress/Compressors/PPMd/I1/PpmState.cs @@ -84,10 +84,8 @@ internal struct PpmState /// /// /// - public static implicit operator PpmState(Pointer pointer) - { - return new PpmState(pointer._address, pointer._memory); - } + public static implicit operator PpmState(Pointer pointer) => + new PpmState(pointer._address, pointer._memory); /// /// Allow pointer-like addition on a PPM state. @@ -141,10 +139,8 @@ internal struct PpmState /// /// /// - public static bool operator <=(PpmState state1, PpmState state2) - { - return state1._address <= state2._address; - } + public static bool operator <=(PpmState state1, PpmState state2) => + state1._address <= state2._address; /// /// Compare two PPM states. @@ -152,10 +148,8 @@ internal struct PpmState /// /// /// - public static bool operator >=(PpmState state1, PpmState state2) - { - return state1._address >= state2._address; - } + public static bool operator >=(PpmState state1, PpmState state2) => + state1._address >= state2._address; /// /// Compare two PPM states. @@ -163,10 +157,8 @@ internal struct PpmState /// /// /// - public static bool operator ==(PpmState state1, PpmState state2) - { - return state1._address == state2._address; - } + public static bool operator ==(PpmState state1, PpmState state2) => + state1._address == state2._address; /// /// Compare two PPM states. @@ -174,10 +166,8 @@ internal struct PpmState /// /// /// - public static bool operator !=(PpmState state1, PpmState state2) - { - return state1._address != state2._address; - } + public static bool operator !=(PpmState state1, PpmState state2) => + state1._address != state2._address; /// /// Indicates whether this instance and a specified object are equal. @@ -197,8 +187,5 @@ internal struct PpmState /// Returns the hash code for this instance. /// /// A 32-bit signed integer that is the hash code for this instance. - public override int GetHashCode() - { - return _address.GetHashCode(); - } + public override int GetHashCode() => _address.GetHashCode(); } diff --git a/src/SharpCompress/Compressors/PPMd/PpmdStream.cs b/src/SharpCompress/Compressors/PPMd/PpmdStream.cs index 43c9757f..bdc4d65a 100644 --- a/src/SharpCompress/Compressors/PPMd/PpmdStream.cs +++ b/src/SharpCompress/Compressors/PPMd/PpmdStream.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable using System; using System.IO; @@ -125,15 +125,9 @@ public class PpmdStream : Stream return size; } - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } + public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException(); - public override void SetLength(long value) - { - throw new NotSupportedException(); - } + public override void SetLength(long value) => throw new NotSupportedException(); public override void Write(byte[] buffer, int offset, int count) { diff --git a/src/SharpCompress/Compressors/Rar/MultiVolumeReadOnlyStream.cs b/src/SharpCompress/Compressors/Rar/MultiVolumeReadOnlyStream.cs index 11a3f515..1e4adfde 100644 --- a/src/SharpCompress/Compressors/Rar/MultiVolumeReadOnlyStream.cs +++ b/src/SharpCompress/Compressors/Rar/MultiVolumeReadOnlyStream.cs @@ -130,10 +130,7 @@ internal sealed class MultiVolumeReadOnlyStream : Stream public uint CurrentCrc { get; private set; } - public override void Flush() - { - throw new NotSupportedException(); - } + public override void Flush() => throw new NotSupportedException(); public override long Length => throw new NotSupportedException(); @@ -143,18 +140,10 @@ internal sealed class MultiVolumeReadOnlyStream : Stream set => throw new NotSupportedException(); } - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } + public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException(); - public override void SetLength(long value) - { - throw new NotSupportedException(); - } + public override void SetLength(long value) => throw new NotSupportedException(); - public override void Write(byte[] buffer, int offset, int count) - { + public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException(); - } } diff --git a/src/SharpCompress/Compressors/Rar/RarCRC.cs b/src/SharpCompress/Compressors/Rar/RarCRC.cs index 75fd8187..8f4fb47e 100644 --- a/src/SharpCompress/Compressors/Rar/RarCRC.cs +++ b/src/SharpCompress/Compressors/Rar/RarCRC.cs @@ -6,10 +6,8 @@ internal static class RarCRC { private static readonly uint[] crcTab; - public static uint CheckCrc(uint startCrc, byte b) - { - return (crcTab[((int)startCrc ^ b) & 0xff] ^ (startCrc >> 8)); - } + public static uint CheckCrc(uint startCrc, byte b) => + (crcTab[((int)startCrc ^ b) & 0xff] ^ (startCrc >> 8)); public static uint CheckCrc(uint startCrc, byte[] data, int offset, int count) { diff --git a/src/SharpCompress/Compressors/Rar/RarCrcStream.cs b/src/SharpCompress/Compressors/Rar/RarCrcStream.cs index 569799b8..e4450c92 100644 --- a/src/SharpCompress/Compressors/Rar/RarCrcStream.cs +++ b/src/SharpCompress/Compressors/Rar/RarCrcStream.cs @@ -18,15 +18,9 @@ internal class RarCrcStream : RarStream ResetCrc(); } - public uint GetCrc() - { - return ~currentCrc; - } + public uint GetCrc() => ~currentCrc; - public void ResetCrc() - { - currentCrc = 0xffffffff; - } + public void ResetCrc() => currentCrc = 0xffffffff; public override int Read(byte[] buffer, int offset, int count) { diff --git a/src/SharpCompress/Compressors/Rar/RarStream.cs b/src/SharpCompress/Compressors/Rar/RarStream.cs index 7bbc1700..0bc2e054 100644 --- a/src/SharpCompress/Compressors/Rar/RarStream.cs +++ b/src/SharpCompress/Compressors/Rar/RarStream.cs @@ -89,15 +89,9 @@ internal class RarStream : Stream return outTotal; } - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } + public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException(); - public override void SetLength(long value) - { - throw new NotSupportedException(); - } + public override void SetLength(long value) => throw new NotSupportedException(); public override void Write(byte[] buffer, int offset, int count) { diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/AudioVariables.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/AudioVariables.cs index d53d777f..ade62f55 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/AudioVariables.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/Decode/AudioVariables.cs @@ -2,10 +2,7 @@ namespace SharpCompress.Compressors.Rar.UnpackV1.Decode; internal class AudioVariables { - internal AudioVariables() - { - Dif = new int[11]; - } + internal AudioVariables() => Dif = new int[11]; internal int[] Dif { get; } internal int ByteCount { get; set; } diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack.cs index 08f0ddeb..2ca62d6b 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack.cs @@ -16,11 +16,9 @@ internal sealed partial class Unpack : BitInput, IRarUnpack { private readonly BitInput Inp; - public Unpack() - { + public Unpack() => // to ease in porting Unpack50.cs Inp = this; - } public bool FileExtracted { get; private set; } @@ -723,11 +721,9 @@ internal sealed partial class Unpack : BitInput, IRarUnpack destUnpSize -= size; } - private void InsertOldDist(uint distance) - { + private void InsertOldDist(uint distance) => // TODO uint InsertOldDist((int)distance); - } private void InsertOldDist(int distance) { @@ -743,11 +739,9 @@ internal sealed partial class Unpack : BitInput, IRarUnpack lastLength = length; } - private void CopyString(uint length, uint distance) - { + private void CopyString(uint length, uint distance) => // TODO uint CopyString((int)length, (int)distance); - } private void CopyString(int length, int distance) { diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack15.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack15.cs index bac545db..8513c24b 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack15.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack15.cs @@ -356,15 +356,9 @@ internal partial class Unpack return (readCode != -1); } - private int getShortLen1(int pos) - { - return pos == 1 ? Buf60 + 3 : ShortLen1[pos]; - } + private int getShortLen1(int pos) => pos == 1 ? Buf60 + 3 : ShortLen1[pos]; - private int getShortLen2(int pos) - { - return pos == 3 ? Buf60 + 3 : ShortLen2[pos]; - } + private int getShortLen2(int pos) => pos == 3 ? Buf60 + 3 : ShortLen2[pos]; private void shortLZ() { diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack50.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack50.cs index 52757e12..bebaebee 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack50.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack50.cs @@ -1,4 +1,4 @@ -#if true +#if true using System; using System.Collections.Generic; using SharpCompress.Compressors.Rar.UnpackV1.Decode; @@ -107,66 +107,51 @@ internal partial class Unpack // TODO: rename var private int UnpPtr { - get { return unpPtr; } - set { unpPtr = value; } + get => unpPtr; + set => unpPtr = value; } private int ReadBorder { - get { return readBorder; } - set { readBorder = value; } + get => readBorder; + set => readBorder = value; } private long DestUnpSize { - get { return destUnpSize; } - set { destUnpSize = value; } + get => destUnpSize; + set => destUnpSize = value; } private long WrittenFileSize { - get { return writtenFileSize; } - set { writtenFileSize = value; } - } - private byte[] Window - { - get { return window; } + get => writtenFileSize; + set => writtenFileSize = value; } + private byte[] Window => window; + private uint LastLength { - get { return (uint)lastLength; } - set { lastLength = (int)value; } + get => (uint)lastLength; + set => lastLength = (int)value; } - private uint OldDistN(int i) - { - return (uint)oldDist[i]; - } + private uint OldDistN(int i) => (uint)oldDist[i]; - private void SetOldDistN(int i, uint value) - { - oldDist[i] = (int)value; - } + private void SetOldDistN(int i, uint value) => oldDist[i] = (int)value; private int WrPtr { - get { return wrPtr; } - set { wrPtr = value; } - } - private Unpack BlockHeader - { - get { return this; } - } - private Unpack Header - { - get { return this; } + get => wrPtr; + set => wrPtr = value; } + private Unpack BlockHeader => this; + + private Unpack Header => this; + private int ReadTop { - get { return readTop; } - set { readTop = value; } - } - private List Filters - { - get { return filters; } + get => readTop; + set => readTop = value; } + private List Filters => filters; // TODO: make sure these aren't already somewhere else public int BlockSize; diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/UnpackFilter.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/UnpackFilter.cs index adfa6856..5359ab24 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/UnpackFilter.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/UnpackFilter.cs @@ -7,21 +7,18 @@ internal class UnpackFilter public byte Type; public byte Channels; - internal UnpackFilter() - { - Program = new VMPreparedProgram(); - } + internal UnpackFilter() => Program = new VMPreparedProgram(); // TODO uint internal uint uBlockStart { - get { return (uint)BlockStart; } - set { BlockStart = (int)value; } + get => (uint)BlockStart; + set => BlockStart = (int)value; } internal uint uBlockLength { - get { return (uint)BlockLength; } - set { BlockLength = (int)value; } + get => (uint)BlockLength; + set => BlockLength = (int)value; } internal int BlockStart { get; set; } diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/UnpackUtility.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/UnpackUtility.cs index 563ca47b..09f5ee8f 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/UnpackUtility.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/UnpackUtility.cs @@ -1,4 +1,4 @@ -using System; +using System; using SharpCompress.Compressors.Rar.VM; @@ -7,10 +7,8 @@ namespace SharpCompress.Compressors.Rar.UnpackV1; internal static class UnpackUtility { //!!! TODO rename methods - internal static uint DecodeNumber(this BitInput input, Decode.Decode dec) - { - return (uint)input.decodeNumber(dec); - } + internal static uint DecodeNumber(this BitInput input, Decode.Decode dec) => + (uint)input.decodeNumber(dec); internal static int decodeNumber(this BitInput input, Decode.Decode dec) { diff --git a/src/SharpCompress/Compressors/Rar/UnpackV2017/BitInput.getbits_cpp.cs b/src/SharpCompress/Compressors/Rar/UnpackV2017/BitInput.getbits_cpp.cs index 58af921b..17368531 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV2017/BitInput.getbits_cpp.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV2017/BitInput.getbits_cpp.cs @@ -1,4 +1,4 @@ -#if !Rar2017_64bit +#if !Rar2017_64bit using size_t = System.UInt32; #else using nint = System.Int64; @@ -41,15 +41,11 @@ internal partial class BitInput //} // - public void faddbits(uint Bits) - { + public void faddbits(uint Bits) => // Function wrapped version of inline addbits to save code size. addbits(Bits); - } - public uint fgetbits() - { + public uint fgetbits() => // Function wrapped version of inline getbits to save code size. - return getbits(); - } + getbits(); } diff --git a/src/SharpCompress/Compressors/Rar/UnpackV2017/BitInput.getbits_hpp.cs b/src/SharpCompress/Compressors/Rar/UnpackV2017/BitInput.getbits_hpp.cs index 47409b0e..f245ea19 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV2017/BitInput.getbits_hpp.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV2017/BitInput.getbits_hpp.cs @@ -1,4 +1,4 @@ -namespace SharpCompress.Compressors.Rar.UnpackV2017; +namespace SharpCompress.Compressors.Rar.UnpackV2017; internal partial class BitInput { @@ -14,10 +14,7 @@ internal partial class BitInput public byte[] InBuf; // Dynamically allocated input buffer. - public void InitBitInput() - { - InAddr = InBit = 0; - } + public void InitBitInput() => InAddr = InBit = 0; // Move forward by 'Bits' bits. public void addbits(uint _Bits) diff --git a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.cs b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.cs index 93ed3e64..53db46d2 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.cs @@ -1,4 +1,4 @@ -#if !Rar2017_64bit +#if !Rar2017_64bit using size_t = System.UInt32; #else using nint = System.Int64; @@ -25,16 +25,12 @@ internal partial class Unpack : IRarUnpack } } - private int UnpIO_UnpRead(byte[] buf, int offset, int count) - { + private int UnpIO_UnpRead(byte[] buf, int offset, int count) => // NOTE: caller has logic to check for -1 for error we throw instead. - return readStream.Read(buf, offset, count); - } + readStream.Read(buf, offset, count); - private void UnpIO_UnpWrite(byte[] buf, size_t offset, uint count) - { + private void UnpIO_UnpWrite(byte[] buf, size_t offset, uint count) => writeStream.Write(buf, checked((int)offset), checked((int)count)); - } public void DoUnpack(FileHeader fileHeader, Stream readStream, Stream writeStream) { @@ -86,10 +82,7 @@ internal partial class Unpack : IRarUnpack public bool Suspended { get; set; } - public long DestSize - { - get => DestUnpSize; - } + public long DestSize => DestUnpSize; public int Char { @@ -110,8 +103,6 @@ internal partial class Unpack : IRarUnpack set => PPMEscChar = value; } - public static byte[] EnsureCapacity(byte[] array, int length) - { - return array.Length < length ? new byte[length] : array; - } + public static byte[] EnsureCapacity(byte[] array, int length) => + array.Length < length ? new byte[length] : array; } diff --git a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.rawint_hpp.cs b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.rawint_hpp.cs index cb572e9d..03614dde 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.rawint_hpp.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.rawint_hpp.cs @@ -1,4 +1,4 @@ -#if !Rar2017_64bit +#if !Rar2017_64bit #else using nint = System.Int64; using nuint = System.UInt64; @@ -21,12 +21,8 @@ internal partial class Unpack // return D[0]+(D[1]<<8); //} - private uint32 RawGet4(byte[] D, int offset) - { - return (uint)( - D[offset] + (D[offset + 1] << 8) + (D[offset + 2] << 16) + (D[offset + 3] << 24) - ); - } + private uint32 RawGet4(byte[] D, int offset) => + (uint)(D[offset] + (D[offset + 1] << 8) + (D[offset + 2] << 16) + (D[offset + 3] << 24)); //inline uint64 RawGet8(const void *Data) //{ diff --git a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack15_cpp.cs b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack15_cpp.cs index 4be34b90..dabb0e08 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack15_cpp.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack15_cpp.cs @@ -1,4 +1,4 @@ -using System; +using System; using static SharpCompress.Compressors.Rar.UnpackV2017.Unpack.Unpack15Local; namespace SharpCompress.Compressors.Rar.UnpackV2017; @@ -201,16 +201,10 @@ internal partial class Unpack } //#define GetShortLen1(pos) ((pos)==1 ? Buf60+3:ShortLen1[pos]) - private uint GetShortLen1(uint pos) - { - return ((pos) == 1 ? (uint)(Buf60 + 3) : ShortLen1[pos]); - } + private uint GetShortLen1(uint pos) => ((pos) == 1 ? (uint)(Buf60 + 3) : ShortLen1[pos]); //#define GetShortLen2(pos) ((pos)==3 ? Buf60+3:ShortLen2[pos]) - private uint GetShortLen2(uint pos) - { - return ((pos) == 3 ? (uint)(Buf60 + 3) : ShortLen2[pos]); - } + private uint GetShortLen2(uint pos) => ((pos) == 3 ? (uint)(Buf60 + 3) : ShortLen2[pos]); internal static class Unpack15Local { diff --git a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack50_cpp.cs b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack50_cpp.cs index 5f7bf613..f85921bd 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack50_cpp.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack50_cpp.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable #if !Rar2017_64bit using size_t = System.UInt32; @@ -866,9 +866,7 @@ internal partial class Unpack return true; } - private void InitFilters() - { + private void InitFilters() => //Filters.SoftReset(); Filters.Clear(); - } } diff --git a/src/SharpCompress/Compressors/Rar/UnpackV2017/unpack_hpp.cs b/src/SharpCompress/Compressors/Rar/UnpackV2017/unpack_hpp.cs index ddeefa86..18cd9697 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV2017/unpack_hpp.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV2017/unpack_hpp.cs @@ -252,7 +252,7 @@ internal partial class Unpack //ComprDataIO *UnpIO; //BitInput Inp; - private BitInput Inp { get { return this; } } // hopefully this gets inlined + private BitInput Inp => this; // hopefully this gets inlined #if RarV2017_RAR_SMP void InitMT(); diff --git a/src/SharpCompress/Compressors/Rar/VM/BitInput.cs b/src/SharpCompress/Compressors/Rar/VM/BitInput.cs index 39bbcc3f..fe349fe7 100644 --- a/src/SharpCompress/Compressors/Rar/VM/BitInput.cs +++ b/src/SharpCompress/Compressors/Rar/VM/BitInput.cs @@ -11,21 +11,18 @@ internal class BitInput // TODO: rename var public int InAddr { - get { return inAddr; } - set { inAddr = value; } + get => inAddr; + set => inAddr = value; } public int InBit { - get { return inBit; } - set { inBit = value; } + get => inBit; + set => inBit = value; } public bool ExternalBuffer; /// - internal BitInput() - { - InBuf = new byte[MAX_SIZE]; - } + internal BitInput() => InBuf = new byte[MAX_SIZE]; internal byte[] InBuf { get; } @@ -35,11 +32,9 @@ internal class BitInput inBit = 0; } - internal void faddbits(uint bits) - { + internal void faddbits(uint bits) => // TODO uint AddBits((int)bits); - } /// /// also named faddbits @@ -52,17 +47,13 @@ internal class BitInput inBit = bits & 7; } - internal uint fgetbits() - { + internal uint fgetbits() => // TODO uint - return (uint)GetBits(); - } + (uint)GetBits(); - internal uint getbits() - { + internal uint getbits() => // TODO uint - return (uint)GetBits(); - } + (uint)GetBits(); /// /// (also named fgetbits) @@ -70,15 +61,14 @@ internal class BitInput /// /// the bits (unsigned short) /// - internal int GetBits() - { + internal int GetBits() => // int BitField=0; // BitField|=(int)(inBuf[inAddr] << 16)&0xFF0000; // BitField|=(int)(inBuf[inAddr+1] << 8)&0xff00; // BitField|=(int)(inBuf[inAddr+2])&0xFF; // BitField >>>= (8-inBit); // return (BitField & 0xffff); - return ( + ( ( Utility.URShift( ( @@ -90,15 +80,11 @@ internal class BitInput ) ) & 0xffff ); - } /// Indicates an Overfow /// how many bytes to inc /// /// true if an Oververflow would occur /// - internal bool Overflow(int IncPtr) - { - return (inAddr + IncPtr >= MAX_SIZE); - } + internal bool Overflow(int IncPtr) => (inAddr + IncPtr >= MAX_SIZE); } diff --git a/src/SharpCompress/Compressors/Rar/VM/RarVM.cs b/src/SharpCompress/Compressors/Rar/VM/RarVM.cs index 07d406cb..48b25c5c 100644 --- a/src/SharpCompress/Compressors/Rar/VM/RarVM.cs +++ b/src/SharpCompress/Compressors/Rar/VM/RarVM.cs @@ -40,21 +40,13 @@ internal sealed class RarVM : BitInput private int IP; - internal RarVM() - { + internal RarVM() => //InitBlock(); Mem = null; - } - internal void init() - { - Mem ??= new byte[VM_MEMSIZE + 4]; - } + internal void init() => Mem ??= new byte[VM_MEMSIZE + 4]; - private bool IsVMMem(byte[] mem) - { - return Mem == mem; - } + private bool IsVMMem(byte[] mem) => Mem == mem; private int GetValue(bool byteMode, byte[] mem, int offset) { diff --git a/src/SharpCompress/Compressors/Xz/BinaryUtils.cs b/src/SharpCompress/Compressors/Xz/BinaryUtils.cs index b05c3bb1..8e08ff98 100644 --- a/src/SharpCompress/Compressors/Xz/BinaryUtils.cs +++ b/src/SharpCompress/Compressors/Xz/BinaryUtils.cs @@ -13,10 +13,8 @@ public static class BinaryUtils return BinaryPrimitives.ReadInt32LittleEndian(bytes); } - internal static uint ReadLittleEndianUInt32(this BinaryReader reader) - { - return unchecked((uint)ReadLittleEndianInt32(reader)); - } + internal static uint ReadLittleEndianUInt32(this BinaryReader reader) => + unchecked((uint)ReadLittleEndianInt32(reader)); public static int ReadLittleEndianInt32(this Stream stream) { @@ -29,10 +27,8 @@ public static class BinaryUtils return BinaryPrimitives.ReadInt32LittleEndian(bytes); } - internal static uint ReadLittleEndianUInt32(this Stream stream) - { - return unchecked((uint)ReadLittleEndianInt32(stream)); - } + internal static uint ReadLittleEndianUInt32(this Stream stream) => + unchecked((uint)ReadLittleEndianInt32(stream)); internal static byte[] ToBigEndianBytes(this uint uint32) { diff --git a/src/SharpCompress/Compressors/Xz/Crc32.cs b/src/SharpCompress/Compressors/Xz/Crc32.cs index 5df276ae..611238c5 100644 --- a/src/SharpCompress/Compressors/Xz/Crc32.cs +++ b/src/SharpCompress/Compressors/Xz/Crc32.cs @@ -12,20 +12,13 @@ public static class Crc32 private static uint[] defaultTable; - public static uint Compute(byte[] buffer) - { - return Compute(DefaultSeed, buffer); - } + public static uint Compute(byte[] buffer) => Compute(DefaultSeed, buffer); - public static uint Compute(uint seed, byte[] buffer) - { - return Compute(DefaultPolynomial, seed, buffer); - } + public static uint Compute(uint seed, byte[] buffer) => + Compute(DefaultPolynomial, seed, buffer); - public static uint Compute(uint polynomial, uint seed, byte[] buffer) - { - return ~CalculateHash(InitializeTable(polynomial), seed, buffer); - } + public static uint Compute(uint polynomial, uint seed, byte[] buffer) => + ~CalculateHash(InitializeTable(polynomial), seed, buffer); private static uint[] InitializeTable(uint polynomial) { diff --git a/src/SharpCompress/Compressors/Xz/Crc64.cs b/src/SharpCompress/Compressors/Xz/Crc64.cs index 6e578329..2c7df9d5 100644 --- a/src/SharpCompress/Compressors/Xz/Crc64.cs +++ b/src/SharpCompress/Compressors/Xz/Crc64.cs @@ -13,10 +13,7 @@ public static class Crc64 public const ulong Iso3309Polynomial = 0xD800000000000000; - public static ulong Compute(byte[] buffer) - { - return Compute(DefaultSeed, buffer); - } + public static ulong Compute(byte[] buffer) => Compute(DefaultSeed, buffer); public static ulong Compute(ulong seed, byte[] buffer) { diff --git a/src/SharpCompress/Compressors/Xz/Filters/ArmFilter.cs b/src/SharpCompress/Compressors/Xz/Filters/ArmFilter.cs index e30109f1..af1e99d3 100644 --- a/src/SharpCompress/Compressors/Xz/Filters/ArmFilter.cs +++ b/src/SharpCompress/Compressors/Xz/Filters/ArmFilter.cs @@ -52,8 +52,5 @@ public class ArmFilter : BlockFilter return bytesRead; } - public override void SetBaseStream(Stream stream) - { - BaseStream = stream; - } + public override void SetBaseStream(Stream stream) => BaseStream = stream; } diff --git a/src/SharpCompress/Compressors/Xz/Filters/ArmThumbFilter.cs b/src/SharpCompress/Compressors/Xz/Filters/ArmThumbFilter.cs index 586e3779..f3ec7b1b 100644 --- a/src/SharpCompress/Compressors/Xz/Filters/ArmThumbFilter.cs +++ b/src/SharpCompress/Compressors/Xz/Filters/ArmThumbFilter.cs @@ -52,8 +52,5 @@ public class ArmThumbFilter : BlockFilter return bytesRead; } - public override void SetBaseStream(Stream stream) - { - BaseStream = stream; - } + public override void SetBaseStream(Stream stream) => BaseStream = stream; } diff --git a/src/SharpCompress/Compressors/Xz/Filters/IA64Filter.cs b/src/SharpCompress/Compressors/Xz/Filters/IA64Filter.cs index b1f1b66c..dc04c71b 100644 --- a/src/SharpCompress/Compressors/Xz/Filters/IA64Filter.cs +++ b/src/SharpCompress/Compressors/Xz/Filters/IA64Filter.cs @@ -52,8 +52,5 @@ public class IA64Filter : BlockFilter return bytesRead; } - public override void SetBaseStream(Stream stream) - { - BaseStream = stream; - } + public override void SetBaseStream(Stream stream) => BaseStream = stream; } diff --git a/src/SharpCompress/Compressors/Xz/Filters/Lzma2Filter.cs b/src/SharpCompress/Compressors/Xz/Filters/Lzma2Filter.cs index 7b4a2a1c..bed59b76 100644 --- a/src/SharpCompress/Compressors/Xz/Filters/Lzma2Filter.cs +++ b/src/SharpCompress/Compressors/Xz/Filters/Lzma2Filter.cs @@ -48,18 +48,11 @@ public class Lzma2Filter : BlockFilter public override void ValidateFilter() { } - public override void SetBaseStream(Stream stream) - { + public override void SetBaseStream(Stream stream) => BaseStream = new LzmaStream(new[] { _dictionarySize }, stream); - } - public override int Read(byte[] buffer, int offset, int count) - { - return BaseStream.Read(buffer, offset, count); - } + public override int Read(byte[] buffer, int offset, int count) => + BaseStream.Read(buffer, offset, count); - public override int ReadByte() - { - return BaseStream.ReadByte(); - } + public override int ReadByte() => BaseStream.ReadByte(); } diff --git a/src/SharpCompress/Compressors/Xz/Filters/PowerPCFilter.cs b/src/SharpCompress/Compressors/Xz/Filters/PowerPCFilter.cs index dfd7caa1..7a03a3fe 100644 --- a/src/SharpCompress/Compressors/Xz/Filters/PowerPCFilter.cs +++ b/src/SharpCompress/Compressors/Xz/Filters/PowerPCFilter.cs @@ -52,8 +52,5 @@ public class PowerPCFilter : BlockFilter return bytesRead; } - public override void SetBaseStream(Stream stream) - { - BaseStream = stream; - } + public override void SetBaseStream(Stream stream) => BaseStream = stream; } diff --git a/src/SharpCompress/Compressors/Xz/Filters/SparcFilter.cs b/src/SharpCompress/Compressors/Xz/Filters/SparcFilter.cs index 141acb46..9b74d344 100644 --- a/src/SharpCompress/Compressors/Xz/Filters/SparcFilter.cs +++ b/src/SharpCompress/Compressors/Xz/Filters/SparcFilter.cs @@ -52,8 +52,5 @@ public class SparcFilter : BlockFilter return bytesRead; } - public override void SetBaseStream(Stream stream) - { - BaseStream = stream; - } + public override void SetBaseStream(Stream stream) => BaseStream = stream; } diff --git a/src/SharpCompress/Compressors/Xz/Filters/X86Filter.cs b/src/SharpCompress/Compressors/Xz/Filters/X86Filter.cs index 2713a344..74dbfb1d 100644 --- a/src/SharpCompress/Compressors/Xz/Filters/X86Filter.cs +++ b/src/SharpCompress/Compressors/Xz/Filters/X86Filter.cs @@ -54,8 +54,5 @@ public class X86Filter : BlockFilter return bytesRead; } - public override void SetBaseStream(Stream stream) - { - BaseStream = stream; - } + public override void SetBaseStream(Stream stream) => BaseStream = stream; } diff --git a/src/SharpCompress/Compressors/Xz/ReadOnlyStream.cs b/src/SharpCompress/Compressors/Xz/ReadOnlyStream.cs index c890b22d..71614df9 100644 --- a/src/SharpCompress/Compressors/Xz/ReadOnlyStream.cs +++ b/src/SharpCompress/Compressors/Xz/ReadOnlyStream.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable using System; using System.IO; @@ -23,23 +23,12 @@ public abstract class ReadOnlyStream : Stream set => throw new NotSupportedException(); } - public override void Flush() - { - throw new NotSupportedException(); - } + public override void Flush() => throw new NotSupportedException(); - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } + public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException(); - public override void SetLength(long value) - { - throw new NotSupportedException(); - } + public override void SetLength(long value) => throw new NotSupportedException(); - public override void Write(byte[] buffer, int offset, int count) - { + public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException(); - } } diff --git a/src/SharpCompress/Compressors/Xz/XZFooter.cs b/src/SharpCompress/Compressors/Xz/XZFooter.cs index 8632ec7e..9751fc2b 100644 --- a/src/SharpCompress/Compressors/Xz/XZFooter.cs +++ b/src/SharpCompress/Compressors/Xz/XZFooter.cs @@ -1,6 +1,5 @@ using System; using System.IO; -using System.Linq; using System.Text; using SharpCompress.IO; diff --git a/src/SharpCompress/Compressors/Xz/XZHeader.cs b/src/SharpCompress/Compressors/Xz/XZHeader.cs index 16277dc6..a5ed8c4a 100644 --- a/src/SharpCompress/Compressors/Xz/XZHeader.cs +++ b/src/SharpCompress/Compressors/Xz/XZHeader.cs @@ -1,4 +1,3 @@ -using System; using System.IO; using System.Linq; using System.Text; @@ -14,10 +13,7 @@ public class XZHeader public CheckType BlockCheckType { get; private set; } public int BlockCheckSize => ((((int)BlockCheckType) + 2) / 3) * 4; - public XZHeader(BinaryReader reader) - { - _reader = reader; - } + public XZHeader(BinaryReader reader) => _reader = reader; public static XZHeader FromStream(Stream stream) { diff --git a/src/SharpCompress/Compressors/Xz/XZStream.cs b/src/SharpCompress/Compressors/Xz/XZStream.cs index b95b5081..78e97a10 100644 --- a/src/SharpCompress/Compressors/Xz/XZStream.cs +++ b/src/SharpCompress/Compressors/Xz/XZStream.cs @@ -77,18 +77,12 @@ public sealed class XZStream : XZReadOnlyStream HeaderIsRead = true; } - private void ReadIndex() - { - Index = XZIndex.FromStream(BaseStream, true); - // TODO veryfy Index - } + private void ReadIndex() => Index = XZIndex.FromStream(BaseStream, true); - private void ReadFooter() - { - Footer = XZFooter.FromStream(BaseStream); - // TODO verify footer - } + // TODO veryfy Index + private void ReadFooter() => Footer = XZFooter.FromStream(BaseStream); + // TODO verify footer private int ReadBlocks(byte[] buffer, int offset, int count) { var bytesRead = 0; @@ -124,8 +118,6 @@ public sealed class XZStream : XZReadOnlyStream return bytesRead; } - private void NextBlock() - { + private void NextBlock() => _currentBlock = new XZBlock(BaseStream, Header.BlockCheckType, Header.BlockCheckSize); - } } diff --git a/src/SharpCompress/Crypto/Crc32Stream.cs b/src/SharpCompress/Crypto/Crc32Stream.cs index 66d9f3c5..1360e1d5 100644 --- a/src/SharpCompress/Crypto/Crc32Stream.cs +++ b/src/SharpCompress/Crypto/Crc32Stream.cs @@ -29,10 +29,7 @@ public sealed class Crc32Stream : Stream public Stream WrappedStream => stream; - public override void Flush() - { - stream.Flush(); - } + public override void Flush() => stream.Flush(); public override int Read(byte[] buffer, int offset, int count) => throw new NotSupportedException(); @@ -75,20 +72,13 @@ public sealed class Crc32Stream : Stream public uint Crc => ~hash; - public static uint Compute(byte[] buffer) - { - return Compute(DefaultSeed, buffer); - } + public static uint Compute(byte[] buffer) => Compute(DefaultSeed, buffer); - public static uint Compute(uint seed, byte[] buffer) - { - return Compute(DefaultPolynomial, seed, buffer); - } + public static uint Compute(uint seed, byte[] buffer) => + Compute(DefaultPolynomial, seed, buffer); - public static uint Compute(uint polynomial, uint seed, ReadOnlySpan buffer) - { - return ~CalculateCrc(InitializeTable(polynomial), seed, buffer); - } + public static uint Compute(uint polynomial, uint seed, ReadOnlySpan buffer) => + ~CalculateCrc(InitializeTable(polynomial), seed, buffer); private static uint[] InitializeTable(uint polynomial) { @@ -136,8 +126,6 @@ public sealed class Crc32Stream : Stream return crc; } - private static uint CalculateCrc(uint[] table, uint crc, byte b) - { - return (crc >> 8) ^ table[(crc ^ b) & 0xFF]; - } + private static uint CalculateCrc(uint[] table, uint crc, byte b) => + (crc >> 8) ^ table[(crc ^ b) & 0xFF]; } diff --git a/src/SharpCompress/Crypto/KeyParameter.cs b/src/SharpCompress/Crypto/KeyParameter.cs index e3a7934c..fce334f9 100644 --- a/src/SharpCompress/Crypto/KeyParameter.cs +++ b/src/SharpCompress/Crypto/KeyParameter.cs @@ -1,4 +1,4 @@ -using System; +using System; namespace SharpCompress.Crypto; @@ -35,8 +35,5 @@ public class KeyParameter : ICipherParameters Array.Copy(key, keyOff, this.key, 0, keyLen); } - public byte[] GetKey() - { - return (byte[])key.Clone(); - } + public byte[] GetKey() => (byte[])key.Clone(); } diff --git a/src/SharpCompress/Crypto/RijndaelEngine.cs b/src/SharpCompress/Crypto/RijndaelEngine.cs index bbcc3da1..7635d7a0 100644 --- a/src/SharpCompress/Crypto/RijndaelEngine.cs +++ b/src/SharpCompress/Crypto/RijndaelEngine.cs @@ -1,4 +1,4 @@ -using System; +using System; namespace SharpCompress.Crypto; @@ -1773,10 +1773,7 @@ public sealed class RijndaelEngine : IBlockCipher public bool IsPartialBlockOkay => false; - public int GetBlockSize() - { - return BC / 2; - } + public int GetBlockSize() => BC / 2; public int ProcessBlock(ReadOnlySpan input, Span output) { diff --git a/src/SharpCompress/Factories/Factory.cs b/src/SharpCompress/Factories/Factory.cs index b092a23a..7ec68508 100644 --- a/src/SharpCompress/Factories/Factory.cs +++ b/src/SharpCompress/Factories/Factory.cs @@ -51,10 +51,7 @@ public abstract class Factory : IFactory public abstract bool IsArchive(Stream stream, string? password = null); /// - public virtual FileInfo? GetFilePart(int index, FileInfo part1) - { - return null; - } + public virtual FileInfo? GetFilePart(int index, FileInfo part1) => null; /// /// Tries to open an from a . diff --git a/src/SharpCompress/Factories/GZipFactory.cs b/src/SharpCompress/Factories/GZipFactory.cs index 1c90a88f..5e522f5b 100644 --- a/src/SharpCompress/Factories/GZipFactory.cs +++ b/src/SharpCompress/Factories/GZipFactory.cs @@ -41,42 +41,32 @@ public class GZipFactory } /// - public override bool IsArchive(Stream stream, string? password = null) - { - return GZipArchive.IsGZipFile(stream); - } + public override bool IsArchive(Stream stream, string? password = null) => + GZipArchive.IsGZipFile(stream); #endregion #region IArchiveFactory /// - public IArchive Open(Stream stream, ReaderOptions? readerOptions = null) - { - return GZipArchive.Open(stream, readerOptions); - } + public IArchive Open(Stream stream, ReaderOptions? readerOptions = null) => + GZipArchive.Open(stream, readerOptions); /// - public IArchive Open(FileInfo fileInfo, ReaderOptions? readerOptions = null) - { - return GZipArchive.Open(fileInfo, readerOptions); - } + public IArchive Open(FileInfo fileInfo, ReaderOptions? readerOptions = null) => + GZipArchive.Open(fileInfo, readerOptions); #endregion #region IMultiArchiveFactory /// - public IArchive Open(IReadOnlyList streams, ReaderOptions? readerOptions = null) - { - return GZipArchive.Open(streams, readerOptions); - } + public IArchive Open(IReadOnlyList streams, ReaderOptions? readerOptions = null) => + GZipArchive.Open(streams, readerOptions); /// - public IArchive Open(IReadOnlyList fileInfos, ReaderOptions? readerOptions = null) - { - return GZipArchive.Open(fileInfos, readerOptions); - } + public IArchive Open(IReadOnlyList fileInfos, ReaderOptions? readerOptions = null) => + GZipArchive.Open(fileInfos, readerOptions); #endregion @@ -112,10 +102,8 @@ public class GZipFactory } /// - public IReader OpenReader(Stream stream, ReaderOptions? options) - { - return GZipReader.Open(stream, options); - } + public IReader OpenReader(Stream stream, ReaderOptions? options) => + GZipReader.Open(stream, options); #endregion @@ -136,10 +124,7 @@ public class GZipFactory #region IWriteableArchiveFactory /// - public IWritableArchive CreateWriteableArchive() - { - return GZipArchive.Create(); - } + public IWritableArchive CreateWriteableArchive() => GZipArchive.Create(); #endregion } diff --git a/src/SharpCompress/Factories/RarFactory.cs b/src/SharpCompress/Factories/RarFactory.cs index 77c04932..cfdb7ff2 100644 --- a/src/SharpCompress/Factories/RarFactory.cs +++ b/src/SharpCompress/Factories/RarFactory.cs @@ -29,58 +29,44 @@ public class RarFactory : Factory, IArchiveFactory, IMultiArchiveFactory, IReade } /// - public override bool IsArchive(Stream stream, string? password = null) - { - return RarArchive.IsRarFile(stream); - } + public override bool IsArchive(Stream stream, string? password = null) => + RarArchive.IsRarFile(stream); /// - public override FileInfo? GetFilePart(int index, FileInfo part1) - { - return RarArchiveVolumeFactory.GetFilePart(index, part1); - } + public override FileInfo? GetFilePart(int index, FileInfo part1) => + RarArchiveVolumeFactory.GetFilePart(index, part1); #endregion #region IArchiveFactory /// - public IArchive Open(Stream stream, ReaderOptions? readerOptions = null) - { - return RarArchive.Open(stream, readerOptions); - } + public IArchive Open(Stream stream, ReaderOptions? readerOptions = null) => + RarArchive.Open(stream, readerOptions); /// - public IArchive Open(FileInfo fileInfo, ReaderOptions? readerOptions = null) - { - return RarArchive.Open(fileInfo, readerOptions); - } + public IArchive Open(FileInfo fileInfo, ReaderOptions? readerOptions = null) => + RarArchive.Open(fileInfo, readerOptions); #endregion #region IMultiArchiveFactory /// - public IArchive Open(IReadOnlyList streams, ReaderOptions? readerOptions = null) - { - return RarArchive.Open(streams, readerOptions); - } + public IArchive Open(IReadOnlyList streams, ReaderOptions? readerOptions = null) => + RarArchive.Open(streams, readerOptions); /// - public IArchive Open(IReadOnlyList fileInfos, ReaderOptions? readerOptions = null) - { - return RarArchive.Open(fileInfos, readerOptions); - } + public IArchive Open(IReadOnlyList fileInfos, ReaderOptions? readerOptions = null) => + RarArchive.Open(fileInfos, readerOptions); #endregion #region IReaderFactory /// - public IReader OpenReader(Stream stream, ReaderOptions? options) - { - return RarReader.Open(stream, options); - } + public IReader OpenReader(Stream stream, ReaderOptions? options) => + RarReader.Open(stream, options); #endregion } diff --git a/src/SharpCompress/Factories/SevenZipFactory.cs b/src/SharpCompress/Factories/SevenZipFactory.cs index 7e06d9e0..cfc99d57 100644 --- a/src/SharpCompress/Factories/SevenZipFactory.cs +++ b/src/SharpCompress/Factories/SevenZipFactory.cs @@ -28,42 +28,32 @@ public class SevenZipFactory : Factory, IArchiveFactory, IMultiArchiveFactory } /// - public override bool IsArchive(Stream stream, string? password = null) - { - return SevenZipArchive.IsSevenZipFile(stream); - } + public override bool IsArchive(Stream stream, string? password = null) => + SevenZipArchive.IsSevenZipFile(stream); #endregion #region IArchiveFactory /// - public IArchive Open(Stream stream, ReaderOptions? readerOptions = null) - { - return SevenZipArchive.Open(stream, readerOptions); - } + public IArchive Open(Stream stream, ReaderOptions? readerOptions = null) => + SevenZipArchive.Open(stream, readerOptions); /// - public IArchive Open(FileInfo fileInfo, ReaderOptions? readerOptions = null) - { - return SevenZipArchive.Open(fileInfo, readerOptions); - } + public IArchive Open(FileInfo fileInfo, ReaderOptions? readerOptions = null) => + SevenZipArchive.Open(fileInfo, readerOptions); #endregion #region IMultiArchiveFactory /// - public IArchive Open(IReadOnlyList streams, ReaderOptions? readerOptions = null) - { - return SevenZipArchive.Open(streams, readerOptions); - } + public IArchive Open(IReadOnlyList streams, ReaderOptions? readerOptions = null) => + SevenZipArchive.Open(streams, readerOptions); /// - public IArchive Open(IReadOnlyList fileInfos, ReaderOptions? readerOptions = null) - { - return SevenZipArchive.Open(fileInfos, readerOptions); - } + public IArchive Open(IReadOnlyList fileInfos, ReaderOptions? readerOptions = null) => + SevenZipArchive.Open(fileInfos, readerOptions); #endregion diff --git a/src/SharpCompress/Factories/TarFactory.cs b/src/SharpCompress/Factories/TarFactory.cs index 747ec17f..61965b86 100644 --- a/src/SharpCompress/Factories/TarFactory.cs +++ b/src/SharpCompress/Factories/TarFactory.cs @@ -67,42 +67,32 @@ public class TarFactory } /// - public override bool IsArchive(Stream stream, string? password = null) - { - return TarArchive.IsTarFile(stream); - } + public override bool IsArchive(Stream stream, string? password = null) => + TarArchive.IsTarFile(stream); #endregion #region IArchiveFactory /// - public IArchive Open(Stream stream, ReaderOptions? readerOptions = null) - { - return TarArchive.Open(stream, readerOptions); - } + public IArchive Open(Stream stream, ReaderOptions? readerOptions = null) => + TarArchive.Open(stream, readerOptions); /// - public IArchive Open(FileInfo fileInfo, ReaderOptions? readerOptions = null) - { - return TarArchive.Open(fileInfo, readerOptions); - } + public IArchive Open(FileInfo fileInfo, ReaderOptions? readerOptions = null) => + TarArchive.Open(fileInfo, readerOptions); #endregion #region IMultiArchiveFactory /// - public IArchive Open(IReadOnlyList streams, ReaderOptions? readerOptions = null) - { - return TarArchive.Open(streams, readerOptions); - } + public IArchive Open(IReadOnlyList streams, ReaderOptions? readerOptions = null) => + TarArchive.Open(streams, readerOptions); /// - public IArchive Open(IReadOnlyList fileInfos, ReaderOptions? readerOptions = null) - { - return TarArchive.Open(fileInfos, readerOptions); - } + public IArchive Open(IReadOnlyList fileInfos, ReaderOptions? readerOptions = null) => + TarArchive.Open(fileInfos, readerOptions); #endregion @@ -175,30 +165,23 @@ public class TarFactory } /// - public IReader OpenReader(Stream stream, ReaderOptions? options) - { - return TarReader.Open(stream, options); - } + public IReader OpenReader(Stream stream, ReaderOptions? options) => + TarReader.Open(stream, options); #endregion #region IWriterFactory /// - public IWriter Open(Stream stream, WriterOptions writerOptions) - { - return new TarWriter(stream, new TarWriterOptions(writerOptions)); - } + public IWriter Open(Stream stream, WriterOptions writerOptions) => + new TarWriter(stream, new TarWriterOptions(writerOptions)); #endregion #region IWriteableArchiveFactory /// - public IWritableArchive CreateWriteableArchive() - { - return TarArchive.Create(); - } + public IWritableArchive CreateWriteableArchive() => TarArchive.Create(); #endregion } diff --git a/src/SharpCompress/Factories/ZipFactory.cs b/src/SharpCompress/Factories/ZipFactory.cs index 64162b68..dca697dc 100644 --- a/src/SharpCompress/Factories/ZipFactory.cs +++ b/src/SharpCompress/Factories/ZipFactory.cs @@ -69,72 +69,55 @@ public class ZipFactory } /// - public override FileInfo? GetFilePart(int index, FileInfo part1) - { - return ZipArchiveVolumeFactory.GetFilePart(index, part1); - } + public override FileInfo? GetFilePart(int index, FileInfo part1) => + ZipArchiveVolumeFactory.GetFilePart(index, part1); #endregion #region IArchiveFactory /// - public IArchive Open(Stream stream, ReaderOptions? readerOptions = null) - { - return ZipArchive.Open(stream, readerOptions); - } + public IArchive Open(Stream stream, ReaderOptions? readerOptions = null) => + ZipArchive.Open(stream, readerOptions); /// - public IArchive Open(FileInfo fileInfo, ReaderOptions? readerOptions = null) - { - return ZipArchive.Open(fileInfo, readerOptions); - } + public IArchive Open(FileInfo fileInfo, ReaderOptions? readerOptions = null) => + ZipArchive.Open(fileInfo, readerOptions); #endregion #region IMultiArchiveFactory /// - public IArchive Open(IReadOnlyList streams, ReaderOptions? readerOptions = null) - { - return ZipArchive.Open(streams, readerOptions); - } + public IArchive Open(IReadOnlyList streams, ReaderOptions? readerOptions = null) => + ZipArchive.Open(streams, readerOptions); /// - public IArchive Open(IReadOnlyList fileInfos, ReaderOptions? readerOptions = null) - { - return ZipArchive.Open(fileInfos, readerOptions); - } + public IArchive Open(IReadOnlyList fileInfos, ReaderOptions? readerOptions = null) => + ZipArchive.Open(fileInfos, readerOptions); #endregion #region IReaderFactory /// - public IReader OpenReader(Stream stream, ReaderOptions? options) - { - return ZipReader.Open(stream, options); - } + public IReader OpenReader(Stream stream, ReaderOptions? options) => + ZipReader.Open(stream, options); #endregion #region IWriterFactory /// - public IWriter Open(Stream stream, WriterOptions writerOptions) - { - return new ZipWriter(stream, new ZipWriterOptions(writerOptions)); - } + public IWriter Open(Stream stream, WriterOptions writerOptions) => + new ZipWriter(stream, new ZipWriterOptions(writerOptions)); #endregion #region IWriteableArchiveFactory /// - public IWritableArchive CreateWriteableArchive() - { - return ZipArchive.Create(); - } + public IWritableArchive CreateWriteableArchive() => ZipArchive.Create(); #endregion } diff --git a/src/SharpCompress/IO/BufferedSubStream.cs b/src/SharpCompress/IO/BufferedSubStream.cs index 37e7e0bb..99e2bfef 100644 --- a/src/SharpCompress/IO/BufferedSubStream.cs +++ b/src/SharpCompress/IO/BufferedSubStream.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; namespace SharpCompress.IO; @@ -26,10 +26,7 @@ internal class BufferedSubStream : NonDisposingStream public override bool CanWrite => false; - public override void Flush() - { - throw new NotSupportedException(); - } + public override void Flush() => throw new NotSupportedException(); public override long Length => BytesLeftToRead; @@ -70,18 +67,10 @@ internal class BufferedSubStream : NonDisposingStream return count; } - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } + public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException(); - public override void SetLength(long value) - { - throw new NotSupportedException(); - } + public override void SetLength(long value) => throw new NotSupportedException(); - public override void Write(byte[] buffer, int offset, int count) - { + public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException(); - } } diff --git a/src/SharpCompress/IO/CountingWritableSubStream.cs b/src/SharpCompress/IO/CountingWritableSubStream.cs index 5a3a990d..206eae7c 100644 --- a/src/SharpCompress/IO/CountingWritableSubStream.cs +++ b/src/SharpCompress/IO/CountingWritableSubStream.cs @@ -15,10 +15,7 @@ internal class CountingWritableSubStream : NonDisposingStream public override bool CanWrite => true; - public override void Flush() - { - Stream.Flush(); - } + public override void Flush() => Stream.Flush(); public override long Length => throw new NotSupportedException(); @@ -28,20 +25,12 @@ internal class CountingWritableSubStream : NonDisposingStream set => throw new NotSupportedException(); } - public override int Read(byte[] buffer, int offset, int count) - { + public override int Read(byte[] buffer, int offset, int count) => throw new NotSupportedException(); - } - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } + public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException(); - public override void SetLength(long value) - { - throw new NotSupportedException(); - } + public override void SetLength(long value) => throw new NotSupportedException(); public override void Write(byte[] buffer, int offset, int count) { diff --git a/src/SharpCompress/IO/ListeningStream.cs b/src/SharpCompress/IO/ListeningStream.cs index 4aeb5347..a1bf715b 100644 --- a/src/SharpCompress/IO/ListeningStream.cs +++ b/src/SharpCompress/IO/ListeningStream.cs @@ -1,4 +1,4 @@ -using System.IO; +using System.IO; using SharpCompress.Common; namespace SharpCompress.IO; @@ -31,10 +31,7 @@ internal class ListeningStream : Stream public override bool CanWrite => Stream.CanWrite; - public override void Flush() - { - Stream.Flush(); - } + public override void Flush() => Stream.Flush(); public override long Length => Stream.Length; @@ -65,18 +62,10 @@ internal class ListeningStream : Stream return value; } - public override long Seek(long offset, SeekOrigin origin) - { - return Stream.Seek(offset, origin); - } + public override long Seek(long offset, SeekOrigin origin) => Stream.Seek(offset, origin); - public override void SetLength(long value) - { - Stream.SetLength(value); - } + public override void SetLength(long value) => Stream.SetLength(value); - public override void Write(byte[] buffer, int offset, int count) - { + public override void Write(byte[] buffer, int offset, int count) => Stream.Write(buffer, offset, count); - } } diff --git a/src/SharpCompress/IO/MarkingBinaryReader.cs b/src/SharpCompress/IO/MarkingBinaryReader.cs index 144a702b..833effc5 100644 --- a/src/SharpCompress/IO/MarkingBinaryReader.cs +++ b/src/SharpCompress/IO/MarkingBinaryReader.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Buffers.Binary; using System.IO; @@ -10,30 +10,17 @@ internal class MarkingBinaryReader : BinaryReader public virtual long CurrentReadByteCount { get; protected set; } - public virtual void Mark() - { - CurrentReadByteCount = 0; - } + public virtual void Mark() => CurrentReadByteCount = 0; - public override int Read() - { + public override int Read() => throw new NotSupportedException(); + + public override int Read(byte[] buffer, int index, int count) => throw new NotSupportedException(); - } - public override int Read(byte[] buffer, int index, int count) - { + public override int Read(char[] buffer, int index, int count) => throw new NotSupportedException(); - } - public override int Read(char[] buffer, int index, int count) - { - throw new NotSupportedException(); - } - - public override bool ReadBoolean() - { - return ReadByte() != 0; - } + public override bool ReadBoolean() => ReadByte() != 0; // NOTE: there is a somewhat fragile dependency on the internals of this class // with RarCrcBinaryReader and RarCryptoBinaryReader. @@ -67,65 +54,29 @@ internal class MarkingBinaryReader : BinaryReader return bytes; } - public override char ReadChar() - { - throw new NotSupportedException(); - } + public override char ReadChar() => throw new NotSupportedException(); - public override char[] ReadChars(int count) - { - throw new NotSupportedException(); - } + public override char[] ReadChars(int count) => throw new NotSupportedException(); - public override double ReadDouble() - { - throw new NotSupportedException(); - } + public override double ReadDouble() => throw new NotSupportedException(); - public override short ReadInt16() - { - return BinaryPrimitives.ReadInt16LittleEndian(ReadBytes(2)); - } + public override short ReadInt16() => BinaryPrimitives.ReadInt16LittleEndian(ReadBytes(2)); - public override int ReadInt32() - { - return BinaryPrimitives.ReadInt32LittleEndian(ReadBytes(4)); - } + public override int ReadInt32() => BinaryPrimitives.ReadInt32LittleEndian(ReadBytes(4)); - public override long ReadInt64() - { - return BinaryPrimitives.ReadInt64LittleEndian(ReadBytes(8)); - } + public override long ReadInt64() => BinaryPrimitives.ReadInt64LittleEndian(ReadBytes(8)); - public override sbyte ReadSByte() - { - return (sbyte)ReadByte(); - } + public override sbyte ReadSByte() => (sbyte)ReadByte(); - public override float ReadSingle() - { - throw new NotSupportedException(); - } + public override float ReadSingle() => throw new NotSupportedException(); - public override string ReadString() - { - throw new NotSupportedException(); - } + public override string ReadString() => throw new NotSupportedException(); - public override ushort ReadUInt16() - { - return BinaryPrimitives.ReadUInt16LittleEndian(ReadBytes(2)); - } + public override ushort ReadUInt16() => BinaryPrimitives.ReadUInt16LittleEndian(ReadBytes(2)); - public override uint ReadUInt32() - { - return BinaryPrimitives.ReadUInt32LittleEndian(ReadBytes(4)); - } + public override uint ReadUInt32() => BinaryPrimitives.ReadUInt32LittleEndian(ReadBytes(4)); - public override ulong ReadUInt64() - { - return BinaryPrimitives.ReadUInt64LittleEndian(ReadBytes(8)); - } + public override ulong ReadUInt64() => BinaryPrimitives.ReadUInt64LittleEndian(ReadBytes(8)); // RAR5 style variable length encoded value // maximum value of 0xffffffffffffffff (64 bits) @@ -135,11 +86,9 @@ internal class MarkingBinaryReader : BinaryReader // and highest bit in every byte is the continuation flag. If highest bit is 0, this is the last byte in sequence. // So first byte contains 7 least significant bits of integer and continuation flag. Second byte, if present, // contains next 7 bits and so on. - public ulong ReadRarVInt(int maxBytes = 10) - { + public ulong ReadRarVInt(int maxBytes = 10) => // hopefully this gets inlined - return DoReadRarVInt((maxBytes - 1) * 7); - } + DoReadRarVInt((maxBytes - 1) * 7); private ulong DoReadRarVInt(int maxShift) { @@ -167,23 +116,17 @@ internal class MarkingBinaryReader : BinaryReader throw new FormatException("malformed vint"); } - public uint ReadRarVIntUInt32(int maxBytes = 5) - { + public uint ReadRarVIntUInt32(int maxBytes = 5) => // hopefully this gets inlined - return DoReadRarVIntUInt32((maxBytes - 1) * 7); - } + DoReadRarVIntUInt32((maxBytes - 1) * 7); - public ushort ReadRarVIntUInt16(int maxBytes = 3) - { + public ushort ReadRarVIntUInt16(int maxBytes = 3) => // hopefully this gets inlined - return checked((ushort)DoReadRarVIntUInt32((maxBytes - 1) * 7)); - } + checked((ushort)DoReadRarVIntUInt32((maxBytes - 1) * 7)); - public byte ReadRarVIntByte(int maxBytes = 2) - { + public byte ReadRarVIntByte(int maxBytes = 2) => // hopefully this gets inlined - return checked((byte)DoReadRarVIntUInt32((maxBytes - 1) * 7)); - } + checked((byte)DoReadRarVIntUInt32((maxBytes - 1) * 7)); private uint DoReadRarVIntUInt32(int maxShift) { diff --git a/src/SharpCompress/IO/NonDisposingStream.cs b/src/SharpCompress/IO/NonDisposingStream.cs index 78063c78..334296d7 100644 --- a/src/SharpCompress/IO/NonDisposingStream.cs +++ b/src/SharpCompress/IO/NonDisposingStream.cs @@ -43,10 +43,7 @@ public class NonDisposingStream : Stream public override bool CanWrite => Stream.CanWrite; - public override void Flush() - { - Stream.Flush(); - } + public override void Flush() => Stream.Flush(); public override long Length => Stream.Length; @@ -56,37 +53,21 @@ public class NonDisposingStream : Stream set => Stream.Position = value; } - public override int Read(byte[] buffer, int offset, int count) - { - return Stream.Read(buffer, offset, count); - } + public override int Read(byte[] buffer, int offset, int count) => + Stream.Read(buffer, offset, count); - public override long Seek(long offset, SeekOrigin origin) - { - return Stream.Seek(offset, origin); - } + public override long Seek(long offset, SeekOrigin origin) => Stream.Seek(offset, origin); - public override void SetLength(long value) - { - Stream.SetLength(value); - } + public override void SetLength(long value) => Stream.SetLength(value); - public override void Write(byte[] buffer, int offset, int count) - { + public override void Write(byte[] buffer, int offset, int count) => Stream.Write(buffer, offset, count); - } #if !NETFRAMEWORK && !NETSTANDARD2_0 - public override int Read(Span buffer) - { - return Stream.Read(buffer); - } + public override int Read(Span buffer) => Stream.Read(buffer); - public override void Write(ReadOnlySpan buffer) - { - Stream.Write(buffer); - } + public override void Write(ReadOnlySpan buffer) => Stream.Write(buffer); #endif } diff --git a/src/SharpCompress/IO/ReadOnlySubStream.cs b/src/SharpCompress/IO/ReadOnlySubStream.cs index ce8709d2..bb095925 100644 --- a/src/SharpCompress/IO/ReadOnlySubStream.cs +++ b/src/SharpCompress/IO/ReadOnlySubStream.cs @@ -25,10 +25,7 @@ internal class ReadOnlySubStream : NonDisposingStream public override bool CanWrite => false; - public override void Flush() - { - throw new NotSupportedException(); - } + public override void Flush() => throw new NotSupportedException(); public override long Length => throw new NotSupportedException(); @@ -79,18 +76,10 @@ internal class ReadOnlySubStream : NonDisposingStream } #endif - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } + public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException(); - public override void SetLength(long value) - { - throw new NotSupportedException(); - } + public override void SetLength(long value) => throw new NotSupportedException(); - public override void Write(byte[] buffer, int offset, int count) - { + public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException(); - } } diff --git a/src/SharpCompress/IO/RewindableStream.cs b/src/SharpCompress/IO/RewindableStream.cs index aab9f459..ccdc8ee0 100644 --- a/src/SharpCompress/IO/RewindableStream.cs +++ b/src/SharpCompress/IO/RewindableStream.cs @@ -10,10 +10,7 @@ public class RewindableStream : Stream private bool isRewound; private bool isDisposed; - public RewindableStream(Stream stream) - { - this.stream = stream; - } + public RewindableStream(Stream stream) => this.stream = stream; internal bool IsRecording { get; private set; } @@ -78,10 +75,7 @@ public class RewindableStream : Stream public override bool CanWrite => false; - public override void Flush() - { - throw new NotSupportedException(); - } + public override void Flush() => throw new NotSupportedException(); public override long Length => stream.Length; @@ -146,18 +140,10 @@ public class RewindableStream : Stream return read; } - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } + public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException(); - public override void SetLength(long value) - { - throw new NotSupportedException(); - } + public override void SetLength(long value) => throw new NotSupportedException(); - public override void Write(byte[] buffer, int offset, int count) - { + public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException(); - } } diff --git a/src/SharpCompress/IO/SourceStream.cs b/src/SharpCompress/IO/SourceStream.cs index d02770c4..9344ad8d 100644 --- a/src/SharpCompress/IO/SourceStream.cs +++ b/src/SharpCompress/IO/SourceStream.cs @@ -131,10 +131,7 @@ public class SourceStream : Stream set => Seek(value, SeekOrigin.Begin); } - public override void Flush() - { - Current.Flush(); - } + public override void Flush() => Current.Flush(); public override int Read(byte[] buffer, int offset, int count) { @@ -211,15 +208,10 @@ public class SourceStream : Stream return pos; } - public override void SetLength(long value) - { - throw new NotImplementedException(); - } + public override void SetLength(long value) => throw new NotImplementedException(); - public override void Write(byte[] buffer, int offset, int count) - { + public override void Write(byte[] buffer, int offset, int count) => throw new NotImplementedException(); - } public override void Close() { diff --git a/src/SharpCompress/Lazy.cs b/src/SharpCompress/Lazy.cs index d7e5159a..7a6abd55 100644 --- a/src/SharpCompress/Lazy.cs +++ b/src/SharpCompress/Lazy.cs @@ -10,10 +10,7 @@ public class Lazy private bool _evaluated; private T _value; - public Lazy(Func lazyFunc) - { - _lazyFunc = lazyFunc; - } + public Lazy(Func lazyFunc) => _lazyFunc = lazyFunc; public T Value { diff --git a/src/SharpCompress/LazyReadOnlyCollection.cs b/src/SharpCompress/LazyReadOnlyCollection.cs index 6fc4ff87..8f5ee834 100644 --- a/src/SharpCompress/LazyReadOnlyCollection.cs +++ b/src/SharpCompress/LazyReadOnlyCollection.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable using System; using System.Collections; @@ -12,10 +12,7 @@ internal sealed class LazyReadOnlyCollection : ICollection private readonly IEnumerator source; private bool fullyLoaded; - public LazyReadOnlyCollection(IEnumerable source) - { - this.source = source.GetEnumerator(); - } + public LazyReadOnlyCollection(IEnumerable source) => this.source = source.GetEnumerator(); private class LazyLoader : IEnumerator { @@ -23,10 +20,8 @@ internal sealed class LazyReadOnlyCollection : ICollection private bool disposed; private int index = -1; - internal LazyLoader(LazyReadOnlyCollection lazyReadOnlyCollection) - { + internal LazyLoader(LazyReadOnlyCollection lazyReadOnlyCollection) => this.lazyReadOnlyCollection = lazyReadOnlyCollection; - } #region IEnumerator Members @@ -67,10 +62,7 @@ internal sealed class LazyReadOnlyCollection : ICollection return false; } - public void Reset() - { - throw new NotSupportedException(); - } + public void Reset() => throw new NotSupportedException(); #endregion } @@ -84,22 +76,13 @@ internal sealed class LazyReadOnlyCollection : ICollection } } - internal IEnumerable GetLoaded() - { - return backing; - } + internal IEnumerable GetLoaded() => backing; #region ICollection Members - public void Add(T item) - { - throw new NotSupportedException(); - } + public void Add(T item) => throw new NotSupportedException(); - public void Clear() - { - throw new NotSupportedException(); - } + public void Clear() => throw new NotSupportedException(); public bool Contains(T item) { @@ -124,29 +107,20 @@ internal sealed class LazyReadOnlyCollection : ICollection public bool IsReadOnly => true; - public bool Remove(T item) - { - throw new NotSupportedException(); - } + public bool Remove(T item) => throw new NotSupportedException(); #endregion #region IEnumerable Members //TODO check for concurrent access - public IEnumerator GetEnumerator() - { - return new LazyLoader(this); - } + public IEnumerator GetEnumerator() => new LazyLoader(this); #endregion #region IEnumerable Members - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); #endregion } diff --git a/src/SharpCompress/Polyfills/StringExtensions.cs b/src/SharpCompress/Polyfills/StringExtensions.cs index 72d0abc6..57d1e1bc 100644 --- a/src/SharpCompress/Polyfills/StringExtensions.cs +++ b/src/SharpCompress/Polyfills/StringExtensions.cs @@ -1,18 +1,13 @@ -#if NETFRAMEWORK || NETSTANDARD2_0 +#if NETFRAMEWORK || NETSTANDARD2_0 namespace SharpCompress; internal static class StringExtensions { - internal static bool EndsWith(this string text, char value) - { - return text.Length > 0 && text[text.Length - 1] == value; - } + internal static bool EndsWith(this string text, char value) => + text.Length > 0 && text[text.Length - 1] == value; - internal static bool Contains(this string text, char value) - { - return text.IndexOf(value) > -1; - } + internal static bool Contains(this string text, char value) => text.IndexOf(value) > -1; } #endif diff --git a/src/SharpCompress/ReadOnlyCollection.cs b/src/SharpCompress/ReadOnlyCollection.cs index b4c46716..745a59aa 100644 --- a/src/SharpCompress/ReadOnlyCollection.cs +++ b/src/SharpCompress/ReadOnlyCollection.cs @@ -8,47 +8,23 @@ public class ReadOnlyCollection : ICollection { private readonly ICollection collection; - public ReadOnlyCollection(ICollection collection) - { - this.collection = collection; - } + public ReadOnlyCollection(ICollection collection) => this.collection = collection; - public void Add(T item) - { - throw new NotSupportedException(); - } + public void Add(T item) => throw new NotSupportedException(); - public void Clear() - { - throw new NotSupportedException(); - } + public void Clear() => throw new NotSupportedException(); - public bool Contains(T item) - { - return collection.Contains(item); - } + public bool Contains(T item) => collection.Contains(item); - public void CopyTo(T[] array, int arrayIndex) - { - collection.CopyTo(array, arrayIndex); - } + public void CopyTo(T[] array, int arrayIndex) => collection.CopyTo(array, arrayIndex); public int Count => collection.Count; public bool IsReadOnly => true; - public bool Remove(T item) - { - throw new NotSupportedException(); - } + public bool Remove(T item) => throw new NotSupportedException(); - public IEnumerator GetEnumerator() - { - return collection.GetEnumerator(); - } + public IEnumerator GetEnumerator() => collection.GetEnumerator(); - IEnumerator IEnumerable.GetEnumerator() - { - throw new NotSupportedException(); - } + IEnumerator IEnumerable.GetEnumerator() => throw new NotSupportedException(); } diff --git a/src/SharpCompress/Readers/AbstractReader.cs b/src/SharpCompress/Readers/AbstractReader.cs index 10cebc12..86150744 100644 --- a/src/SharpCompress/Readers/AbstractReader.cs +++ b/src/SharpCompress/Readers/AbstractReader.cs @@ -109,15 +109,9 @@ public abstract class AbstractReader : IReader, IReaderExtracti return entriesForCurrentReadStream.MoveNext(); } - protected virtual Stream RequestInitialStream() - { - return Volume.Stream; - } + protected virtual Stream RequestInitialStream() => Volume.Stream; - internal virtual bool NextEntryForCurrentStream() - { - return entriesForCurrentReadStream!.MoveNext(); - } + internal virtual bool NextEntryForCurrentStream() => entriesForCurrentReadStream!.MoveNext(); protected abstract IEnumerable GetEntries(Stream stream); @@ -196,15 +190,11 @@ public abstract class AbstractReader : IReader, IReaderExtracti /// /// Retains a reference to the entry stream, so we can check whether it completed later. /// - protected EntryStream CreateEntryStream(Stream decompressed) - { - return new EntryStream(this, decompressed); - } + protected EntryStream CreateEntryStream(Stream decompressed) => + new EntryStream(this, decompressed); - protected virtual EntryStream GetEntryStream() - { - return CreateEntryStream(Entry.Parts.First().GetCompressedStream()); - } + protected virtual EntryStream GetEntryStream() => + CreateEntryStream(Entry.Parts.First().GetCompressedStream()); #endregion @@ -213,8 +203,7 @@ public abstract class AbstractReader : IReader, IReaderExtracti void IExtractionListener.FireCompressedBytesRead( long currentPartCompressedBytes, long compressedReadBytes - ) - { + ) => CompressedBytesRead?.Invoke( this, new CompressedBytesReadEventArgs( @@ -222,14 +211,12 @@ public abstract class AbstractReader : IReader, IReaderExtracti compressedBytesRead: compressedReadBytes ) ); - } void IExtractionListener.FireFilePartExtractionBegin( string name, long size, long compressedSize - ) - { + ) => FilePartExtractionBegin?.Invoke( this, new FilePartExtractionBeginEventArgs( @@ -238,14 +225,12 @@ public abstract class AbstractReader : IReader, IReaderExtracti name: name ) ); - } void IReaderExtractionListener.FireEntryExtractionProgress( Entry entry, long bytesTransferred, int iterations - ) - { + ) => EntryExtractionProgress?.Invoke( this, new ReaderExtractionEventArgs( @@ -253,5 +238,4 @@ public abstract class AbstractReader : IReader, IReaderExtracti new ReaderProgress(entry, bytesTransferred, iterations) ) ); - } } diff --git a/src/SharpCompress/Readers/GZip/GZipReader.cs b/src/SharpCompress/Readers/GZip/GZipReader.cs index c757e351..84129d20 100644 --- a/src/SharpCompress/Readers/GZip/GZipReader.cs +++ b/src/SharpCompress/Readers/GZip/GZipReader.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.IO; using SharpCompress.Common; using SharpCompress.Common.GZip; @@ -7,10 +7,8 @@ namespace SharpCompress.Readers.GZip; public class GZipReader : AbstractReader { - internal GZipReader(Stream stream, ReaderOptions options) : base(options, ArchiveType.GZip) - { + internal GZipReader(Stream stream, ReaderOptions options) : base(options, ArchiveType.GZip) => Volume = new GZipVolume(stream, options); - } public override GZipVolume Volume { get; } @@ -30,8 +28,6 @@ public class GZipReader : AbstractReader #endregion Open - protected override IEnumerable GetEntries(Stream stream) - { - return GZipEntry.GetEntries(stream, Options); - } + protected override IEnumerable GetEntries(Stream stream) => + GZipEntry.GetEntries(stream, Options); } diff --git a/src/SharpCompress/Readers/IReaderExtensions.cs b/src/SharpCompress/Readers/IReaderExtensions.cs index 5ef89352..0e51d72a 100644 --- a/src/SharpCompress/Readers/IReaderExtensions.cs +++ b/src/SharpCompress/Readers/IReaderExtensions.cs @@ -1,4 +1,4 @@ -using System.IO; +using System.IO; using SharpCompress.Common; namespace SharpCompress.Readers; @@ -39,15 +39,13 @@ public static class IReaderExtensions this IReader reader, string destinationDirectory, ExtractionOptions? options = null - ) - { + ) => ExtractionMethods.WriteEntryToDirectory( reader.Entry, destinationDirectory, options, reader.WriteEntryToFile ); - } /// /// Extract to specific file @@ -56,8 +54,7 @@ public static class IReaderExtensions this IReader reader, string destinationFileName, ExtractionOptions? options = null - ) - { + ) => ExtractionMethods.WriteEntryToFile( reader.Entry, destinationFileName, @@ -68,5 +65,4 @@ public static class IReaderExtensions reader.WriteEntryTo(fs); } ); - } } diff --git a/src/SharpCompress/Readers/Rar/MultiVolumeRarReader.cs b/src/SharpCompress/Readers/Rar/MultiVolumeRarReader.cs index 2c29fb5f..76899e0c 100644 --- a/src/SharpCompress/Readers/Rar/MultiVolumeRarReader.cs +++ b/src/SharpCompress/Readers/Rar/MultiVolumeRarReader.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable using System.Collections; using System.Collections.Generic; @@ -15,10 +15,7 @@ internal class MultiVolumeRarReader : RarReader private Stream tempStream; internal MultiVolumeRarReader(IEnumerable streams, ReaderOptions options) - : base(options) - { - this.streams = streams.GetEnumerator(); - } + : base(options) => this.streams = streams.GetEnumerator(); internal override void ValidateArchive(RarVolume archive) { } @@ -68,15 +65,9 @@ internal class MultiVolumeRarReader : RarReader this.tempStream = tempStream; } - public IEnumerator GetEnumerator() - { - return this; - } + public IEnumerator GetEnumerator() => this; - IEnumerator IEnumerable.GetEnumerator() - { - return this; - } + IEnumerator IEnumerable.GetEnumerator() => this; public FilePart Current { get; private set; } diff --git a/src/SharpCompress/Readers/Rar/NonSeekableStreamFilePart.cs b/src/SharpCompress/Readers/Rar/NonSeekableStreamFilePart.cs index 344ca994..09753b95 100644 --- a/src/SharpCompress/Readers/Rar/NonSeekableStreamFilePart.cs +++ b/src/SharpCompress/Readers/Rar/NonSeekableStreamFilePart.cs @@ -9,10 +9,7 @@ internal class NonSeekableStreamFilePart : RarFilePart internal NonSeekableStreamFilePart(MarkHeader mh, FileHeader fh, int index = 0) : base(mh, fh, index) { } - internal override Stream GetCompressedStream() - { - return FileHeader.PackedStream; - } + internal override Stream GetCompressedStream() => FileHeader.PackedStream; internal override string FilePartName => "Unknown Stream - File Entry: " + FileHeader.FileName; } diff --git a/src/SharpCompress/Readers/Rar/RarReader.cs b/src/SharpCompress/Readers/Rar/RarReader.cs index 6eb49b2d..71d671a3 100644 --- a/src/SharpCompress/Readers/Rar/RarReader.cs +++ b/src/SharpCompress/Readers/Rar/RarReader.cs @@ -58,10 +58,8 @@ public abstract class RarReader : AbstractReader } } - protected virtual IEnumerable CreateFilePartEnumerableForCurrentEntry() - { - return Entry.Parts; - } + protected virtual IEnumerable CreateFilePartEnumerableForCurrentEntry() => + Entry.Parts; protected override EntryStream GetEntryStream() { diff --git a/src/SharpCompress/Readers/Rar/RarReaderVolume.cs b/src/SharpCompress/Readers/Rar/RarReaderVolume.cs index b0f82bc3..85beb897 100644 --- a/src/SharpCompress/Readers/Rar/RarReaderVolume.cs +++ b/src/SharpCompress/Readers/Rar/RarReaderVolume.cs @@ -11,13 +11,8 @@ public class RarReaderVolume : RarVolume internal RarReaderVolume(Stream stream, ReaderOptions options, int index = 0) : base(StreamingMode.Streaming, stream, options, index) { } - internal override RarFilePart CreateFilePart(MarkHeader markHeader, FileHeader fileHeader) - { - return new NonSeekableStreamFilePart(markHeader, fileHeader, Index); - } + internal override RarFilePart CreateFilePart(MarkHeader markHeader, FileHeader fileHeader) => + new NonSeekableStreamFilePart(markHeader, fileHeader, Index); - internal override IEnumerable ReadFileParts() - { - return GetVolumeFileParts(); - } + internal override IEnumerable ReadFileParts() => GetVolumeFileParts(); } diff --git a/src/SharpCompress/Readers/Rar/SingleVolumeRarReader.cs b/src/SharpCompress/Readers/Rar/SingleVolumeRarReader.cs index b7a9eff3..f3ab98b4 100644 --- a/src/SharpCompress/Readers/Rar/SingleVolumeRarReader.cs +++ b/src/SharpCompress/Readers/Rar/SingleVolumeRarReader.cs @@ -1,4 +1,4 @@ -using System.IO; +using System.IO; using SharpCompress.Common; using SharpCompress.Common.Rar; @@ -8,10 +8,8 @@ internal class SingleVolumeRarReader : RarReader { private readonly Stream stream; - internal SingleVolumeRarReader(Stream stream, ReaderOptions options) : base(options) - { + internal SingleVolumeRarReader(Stream stream, ReaderOptions options) : base(options) => this.stream = stream; - } internal override void ValidateArchive(RarVolume archive) { @@ -23,8 +21,5 @@ internal class SingleVolumeRarReader : RarReader } } - protected override Stream RequestInitialStream() - { - return stream; - } + protected override Stream RequestInitialStream() => stream; } diff --git a/src/SharpCompress/Readers/Tar/TarReader.cs b/src/SharpCompress/Readers/Tar/TarReader.cs index b72b5982..c9802e46 100644 --- a/src/SharpCompress/Readers/Tar/TarReader.cs +++ b/src/SharpCompress/Readers/Tar/TarReader.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using SharpCompress.Archives.GZip; @@ -12,128 +12,119 @@ using SharpCompress.IO; using SharpCompress.Compressors.LZMA; using SharpCompress.Compressors.Xz; -namespace SharpCompress.Readers.Tar +namespace SharpCompress.Readers.Tar; + +public class TarReader : AbstractReader { - public class TarReader : AbstractReader + private readonly CompressionType compressionType; + + internal TarReader(Stream stream, ReaderOptions options, CompressionType compressionType) + : base(options, ArchiveType.Tar) { - private readonly CompressionType compressionType; + this.compressionType = compressionType; + Volume = new TarVolume(stream, options); + } - internal TarReader(Stream stream, ReaderOptions options, CompressionType compressionType) - : base(options, ArchiveType.Tar) + public override TarVolume Volume { get; } + + protected override Stream RequestInitialStream() + { + var stream = base.RequestInitialStream(); + switch (compressionType) { - this.compressionType = compressionType; - Volume = new TarVolume(stream, options); - } - - public override TarVolume Volume { get; } - - protected override Stream RequestInitialStream() - { - var stream = base.RequestInitialStream(); - switch (compressionType) + case CompressionType.BZip2: { - case CompressionType.BZip2: - { - return new BZip2Stream(stream, CompressionMode.Decompress, false); - } - case CompressionType.GZip: - { - return new GZipStream(stream, CompressionMode.Decompress); - } - case CompressionType.LZip: - { - return new LZipStream(stream, CompressionMode.Decompress); - } - case CompressionType.Xz: - { - return new XZStream(stream); - } - case CompressionType.None: - { - return stream; - } - default: - { - throw new NotSupportedException("Invalid compression type: " + compressionType); - } + return new BZip2Stream(stream, CompressionMode.Decompress, false); } - } - - #region Open - - /// - /// Opens a TarReader for Non-seeking usage with a single volume - /// - /// - /// - /// - public static TarReader Open(Stream stream, ReaderOptions? options = null) - { - stream.CheckNotNull(nameof(stream)); - options = options ?? new ReaderOptions(); - RewindableStream rewindableStream = new RewindableStream(stream); - rewindableStream.StartRecording(); - if (GZipArchive.IsGZipFile(rewindableStream)) + case CompressionType.GZip: { - rewindableStream.Rewind(false); - GZipStream testStream = new GZipStream( - rewindableStream, - CompressionMode.Decompress - ); - if (TarArchive.IsTarFile(testStream)) - { - rewindableStream.Rewind(true); - return new TarReader(rewindableStream, options, CompressionType.GZip); - } - throw new InvalidFormatException("Not a tar file."); + return new GZipStream(stream, CompressionMode.Decompress); } - - rewindableStream.Rewind(false); - if (BZip2Stream.IsBZip2(rewindableStream)) + case CompressionType.LZip: { - rewindableStream.Rewind(false); - BZip2Stream testStream = new BZip2Stream( - rewindableStream, - CompressionMode.Decompress, - false - ); - if (TarArchive.IsTarFile(testStream)) - { - rewindableStream.Rewind(true); - return new TarReader(rewindableStream, options, CompressionType.BZip2); - } - throw new InvalidFormatException("Not a tar file."); + return new LZipStream(stream, CompressionMode.Decompress); } - - rewindableStream.Rewind(false); - if (LZipStream.IsLZipFile(rewindableStream)) + case CompressionType.Xz: { - rewindableStream.Rewind(false); - LZipStream testStream = new LZipStream( - rewindableStream, - CompressionMode.Decompress - ); - if (TarArchive.IsTarFile(testStream)) - { - rewindableStream.Rewind(true); - return new TarReader(rewindableStream, options, CompressionType.LZip); - } - throw new InvalidFormatException("Not a tar file."); + return new XZStream(stream); + } + case CompressionType.None: + { + return stream; + } + default: + { + throw new NotSupportedException("Invalid compression type: " + compressionType); } - rewindableStream.Rewind(true); - return new TarReader(rewindableStream, options, CompressionType.None); - } - - #endregion Open - - protected override IEnumerable GetEntries(Stream stream) - { - return TarEntry.GetEntries( - StreamingMode.Streaming, - stream, - compressionType, - Options.ArchiveEncoding - ); } } + + #region Open + + /// + /// Opens a TarReader for Non-seeking usage with a single volume + /// + /// + /// + /// + public static TarReader Open(Stream stream, ReaderOptions? options = null) + { + stream.CheckNotNull(nameof(stream)); + options = options ?? new ReaderOptions(); + RewindableStream rewindableStream = new RewindableStream(stream); + rewindableStream.StartRecording(); + if (GZipArchive.IsGZipFile(rewindableStream)) + { + rewindableStream.Rewind(false); + GZipStream testStream = new GZipStream(rewindableStream, CompressionMode.Decompress); + if (TarArchive.IsTarFile(testStream)) + { + rewindableStream.Rewind(true); + return new TarReader(rewindableStream, options, CompressionType.GZip); + } + throw new InvalidFormatException("Not a tar file."); + } + + rewindableStream.Rewind(false); + if (BZip2Stream.IsBZip2(rewindableStream)) + { + rewindableStream.Rewind(false); + BZip2Stream testStream = new BZip2Stream( + rewindableStream, + CompressionMode.Decompress, + false + ); + if (TarArchive.IsTarFile(testStream)) + { + rewindableStream.Rewind(true); + return new TarReader(rewindableStream, options, CompressionType.BZip2); + } + throw new InvalidFormatException("Not a tar file."); + } + + rewindableStream.Rewind(false); + if (LZipStream.IsLZipFile(rewindableStream)) + { + rewindableStream.Rewind(false); + LZipStream testStream = new LZipStream(rewindableStream, CompressionMode.Decompress); + if (TarArchive.IsTarFile(testStream)) + { + rewindableStream.Rewind(true); + return new TarReader(rewindableStream, options, CompressionType.LZip); + } + throw new InvalidFormatException("Not a tar file."); + } + rewindableStream.Rewind(true); + return new TarReader(rewindableStream, options, CompressionType.None); + } + + #endregion Open + + protected override IEnumerable GetEntries(Stream stream) => + TarEntry.GetEntries( + StreamingMode.Streaming, + stream, + compressionType, + Options.ArchiveEncoding + ); } diff --git a/src/SharpCompress/Utility.cs b/src/SharpCompress/Utility.cs index 99b5d8e9..9471c3e1 100644 --- a/src/SharpCompress/Utility.cs +++ b/src/SharpCompress/Utility.cs @@ -9,10 +9,8 @@ namespace SharpCompress; [CLSCompliant(false)] public static class Utility { - public static ReadOnlyCollection ToReadOnly(this ICollection items) - { - return new ReadOnlyCollection(items); - } + public static ReadOnlyCollection ToReadOnly(this ICollection items) => + new ReadOnlyCollection(items); /// /// Performs an unsigned bitwise right shift with the specified number @@ -258,10 +256,8 @@ public static class Utility ); } - public static DateTime DosDateToDateTime(uint iTime) - { - return DosDateToDateTime((ushort)(iTime / 65536), (ushort)(iTime % 65536)); - } + public static DateTime DosDateToDateTime(uint iTime) => + DosDateToDateTime((ushort)(iTime / 65536), (ushort)(iTime % 65536)); /// /// Convert Unix time value to a DateTime object. @@ -320,15 +316,10 @@ public static class Utility } } - private static bool ReadTransferBlock(Stream source, byte[] array, out int count) - { - return (count = source.Read(array, 0, array.Length)) != 0; - } + private static bool ReadTransferBlock(Stream source, byte[] array, out int count) => + (count = source.Read(array, 0, array.Length)) != 0; - private static byte[] GetTransferByteArray() - { - return ArrayPool.Shared.Rent(81920); - } + private static byte[] GetTransferByteArray() => ArrayPool.Shared.Rent(81920); public static bool ReadFully(this Stream stream, byte[] buffer) { @@ -360,23 +351,18 @@ public static class Utility return (total >= buffer.Length); } - public static string TrimNulls(this string source) - { - return source.Replace('\0', ' ').Trim(); - } + public static string TrimNulls(this string source) => source.Replace('\0', ' ').Trim(); /// /// Swap the endianness of a UINT32 /// /// The UINT32 you want to swap his endianness /// Return the new UINT32 in the other endianness format - public static uint SwapUINT32(uint number) - { - return (number >> 24) - | ((number << 8) & 0x00FF0000) - | ((number >> 8) & 0x0000FF00) - | (number << 24); - } + public static uint SwapUINT32(uint number) => + (number >> 24) + | ((number << 8) & 0x00FF0000) + | ((number >> 8) & 0x0000FF00) + | (number << 24); /// /// Insert a little endian UINT32 into a byte array diff --git a/src/SharpCompress/Writers/AbstractWriter.cs b/src/SharpCompress/Writers/AbstractWriter.cs index 0fe95c5b..209c49f7 100644 --- a/src/SharpCompress/Writers/AbstractWriter.cs +++ b/src/SharpCompress/Writers/AbstractWriter.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable using System; using System.IO; @@ -16,10 +16,7 @@ public abstract class AbstractWriter : IWriter WriterOptions = writerOptions; } - protected void InitalizeStream(Stream stream) - { - OutputStream = stream; - } + protected void InitalizeStream(Stream stream) => OutputStream = stream; protected Stream OutputStream { get; private set; } diff --git a/src/SharpCompress/Writers/IWriterExtensions.cs b/src/SharpCompress/Writers/IWriterExtensions.cs index f61daf13..56f3966a 100644 --- a/src/SharpCompress/Writers/IWriterExtensions.cs +++ b/src/SharpCompress/Writers/IWriterExtensions.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; using System.Linq; @@ -6,10 +6,8 @@ namespace SharpCompress.Writers; public static class IWriterExtensions { - public static void Write(this IWriter writer, string entryPath, Stream source) - { + public static void Write(this IWriter writer, string entryPath, Stream source) => writer.Write(entryPath, source, null); - } public static void Write(this IWriter writer, string entryPath, FileInfo source) { @@ -21,20 +19,15 @@ public static class IWriterExtensions writer.Write(entryPath, stream, source.LastWriteTime); } - public static void Write(this IWriter writer, string entryPath, string source) - { + public static void Write(this IWriter writer, string entryPath, string source) => writer.Write(entryPath, new FileInfo(source)); - } public static void WriteAll( this IWriter writer, string directory, string searchPattern = "*", SearchOption option = SearchOption.TopDirectoryOnly - ) - { - writer.WriteAll(directory, searchPattern, null, option); - } + ) => writer.WriteAll(directory, searchPattern, null, option); public static void WriteAll( this IWriter writer, diff --git a/src/SharpCompress/Writers/Tar/TarWriter.cs b/src/SharpCompress/Writers/Tar/TarWriter.cs index 8151c3f3..068aeee1 100644 --- a/src/SharpCompress/Writers/Tar/TarWriter.cs +++ b/src/SharpCompress/Writers/Tar/TarWriter.cs @@ -58,10 +58,8 @@ public class TarWriter : AbstractWriter InitalizeStream(destination); } - public override void Write(string filename, Stream source, DateTime? modificationTime) - { + public override void Write(string filename, Stream source, DateTime? modificationTime) => Write(filename, source, modificationTime, null); - } private string NormalizeFilename(string filename) { diff --git a/src/SharpCompress/Writers/Tar/TarWriterOptions.cs b/src/SharpCompress/Writers/Tar/TarWriterOptions.cs index c95ceba4..ca51ebb6 100755 --- a/src/SharpCompress/Writers/Tar/TarWriterOptions.cs +++ b/src/SharpCompress/Writers/Tar/TarWriterOptions.cs @@ -10,13 +10,8 @@ public class TarWriterOptions : WriterOptions public bool FinalizeArchiveOnClose { get; } public TarWriterOptions(CompressionType compressionType, bool finalizeArchiveOnClose) - : base(compressionType) - { - FinalizeArchiveOnClose = finalizeArchiveOnClose; - } + : base(compressionType) => FinalizeArchiveOnClose = finalizeArchiveOnClose; - internal TarWriterOptions(WriterOptions options) : this(options.CompressionType, true) - { + internal TarWriterOptions(WriterOptions options) : this(options.CompressionType, true) => ArchiveEncoding = options.ArchiveEncoding; - } } diff --git a/src/SharpCompress/Writers/WriterOptions.cs b/src/SharpCompress/Writers/WriterOptions.cs index 01b21bea..9d323c2b 100644 --- a/src/SharpCompress/Writers/WriterOptions.cs +++ b/src/SharpCompress/Writers/WriterOptions.cs @@ -1,18 +1,13 @@ -using SharpCompress.Common; +using SharpCompress.Common; namespace SharpCompress.Writers; public class WriterOptions : OptionsBase { - public WriterOptions(CompressionType compressionType) - { - CompressionType = compressionType; - } + public WriterOptions(CompressionType compressionType) => CompressionType = compressionType; public CompressionType CompressionType { get; set; } - public static implicit operator WriterOptions(CompressionType compressionType) - { - return new WriterOptions(compressionType); - } + public static implicit operator WriterOptions(CompressionType compressionType) => + new WriterOptions(compressionType); } diff --git a/src/SharpCompress/Writers/Zip/ZipWriter.cs b/src/SharpCompress/Writers/Zip/ZipWriter.cs index b5d8a300..e1fd222c 100644 --- a/src/SharpCompress/Writers/Zip/ZipWriter.cs +++ b/src/SharpCompress/Writers/Zip/ZipWriter.cs @@ -45,10 +45,7 @@ public class ZipWriter : AbstractWriter InitalizeStream(destination); } - private PpmdProperties PpmdProperties - { - get { return ppmdProps ??= new PpmdProperties(); } - } + private PpmdProperties PpmdProperties => ppmdProps ??= new PpmdProperties(); protected override void Dispose(bool isDisposing) { @@ -93,14 +90,12 @@ public class ZipWriter : AbstractWriter } } - public override void Write(string entryPath, Stream source, DateTime? modificationTime) - { + public override void Write(string entryPath, Stream source, DateTime? modificationTime) => Write( entryPath, source, new ZipWriterEntryOptions() { ModificationDateTime = modificationTime } ); - } public void Write(string entryPath, Stream source, ZipWriterEntryOptions zipWriterEntryOptions) { @@ -524,25 +519,15 @@ public class ZipWriter : AbstractWriter } } - public override void Flush() - { - writeStream.Flush(); - } + public override void Flush() => writeStream.Flush(); - public override int Read(byte[] buffer, int offset, int count) - { + public override int Read(byte[] buffer, int offset, int count) => throw new NotSupportedException(); - } - public override long Seek(long offset, SeekOrigin origin) - { + public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException(); - } - public override void SetLength(long value) - { - throw new NotSupportedException(); - } + public override void SetLength(long value) => throw new NotSupportedException(); public override void Write(byte[] buffer, int offset, int count) { diff --git a/tests/SharpCompress.Test/ArchiveTests.cs b/tests/SharpCompress.Test/ArchiveTests.cs index e12ac339..c44271e1 100644 --- a/tests/SharpCompress.Test/ArchiveTests.cs +++ b/tests/SharpCompress.Test/ArchiveTests.cs @@ -82,13 +82,11 @@ public class ArchiveTests : ReaderTests protected void ArchiveStreamRead( ReaderOptions? readerOptions = null, params string[] testArchives - ) - { + ) => ArchiveStreamRead( readerOptions, testArchives.Select(x => Path.Combine(TEST_ARCHIVES_PATH, x)) ); - } protected void ArchiveStreamRead(ReaderOptions? readerOptions, IEnumerable testArchives) { @@ -122,13 +120,11 @@ public class ArchiveTests : ReaderTests protected void ArchiveStreamMultiRead( ReaderOptions? readerOptions = null, params string[] testArchives - ) - { + ) => ArchiveStreamMultiRead( readerOptions, testArchives.Select(x => Path.Combine(TEST_ARCHIVES_PATH, x)) ); - } protected void ArchiveStreamMultiRead( ReaderOptions? readerOptions, @@ -163,13 +159,11 @@ public class ArchiveTests : ReaderTests protected void ArchiveOpenStreamRead( ReaderOptions? readerOptions = null, params string[] testArchives - ) - { + ) => ArchiveOpenStreamRead( readerOptions, testArchives.Select(x => Path.Combine(TEST_ARCHIVES_PATH, x)) ); - } protected void ArchiveOpenStreamRead( ReaderOptions? readerOptions, @@ -205,14 +199,12 @@ public class ArchiveTests : ReaderTests int[][] results, ReaderOptions? readerOptions = null, params string[] testArchives - ) - { + ) => ArchiveOpenEntryVolumeIndexTest( results, readerOptions, testArchives.Select(x => Path.Combine(TEST_ARCHIVES_PATH, x)) ); - } protected void ArchiveOpenEntryVolumeIndexTest( int[][] results, diff --git a/tests/SharpCompress.Test/Filters/BranchExecTests.cs b/tests/SharpCompress.Test/Filters/BranchExecTests.cs index e979d537..5c576dcc 100644 --- a/tests/SharpCompress.Test/Filters/BranchExecTests.cs +++ b/tests/SharpCompress.Test/Filters/BranchExecTests.cs @@ -1184,10 +1184,8 @@ public class BranchExecTests 0x00, }; - private void CompareBuffer(byte[] testBuffer, byte[] targetBuffer) - { + private void CompareBuffer(byte[] testBuffer, byte[] targetBuffer) => Assert.Equal(testBuffer, targetBuffer); - } [Fact] public void X86ConverterDecodeTest() diff --git a/tests/SharpCompress.Test/GZip/GZipArchiveTests.cs b/tests/SharpCompress.Test/GZip/GZipArchiveTests.cs index 46270985..e47c339c 100644 --- a/tests/SharpCompress.Test/GZip/GZipArchiveTests.cs +++ b/tests/SharpCompress.Test/GZip/GZipArchiveTests.cs @@ -9,10 +9,7 @@ namespace SharpCompress.Test.GZip; public class GZipArchiveTests : ArchiveTests { - public GZipArchiveTests() - { - UseExtensionInsteadOfNameToVerify = true; - } + public GZipArchiveTests() => UseExtensionInsteadOfNameToVerify = true; [Fact] public void GZip_Archive_Generic() diff --git a/tests/SharpCompress.Test/GZip/GZipReaderTests.cs b/tests/SharpCompress.Test/GZip/GZipReaderTests.cs index 6890d4c6..b5a3d501 100644 --- a/tests/SharpCompress.Test/GZip/GZipReaderTests.cs +++ b/tests/SharpCompress.Test/GZip/GZipReaderTests.cs @@ -7,16 +7,10 @@ namespace SharpCompress.Test.GZip; public class GZipReaderTests : ReaderTests { - public GZipReaderTests() - { - UseExtensionInsteadOfNameToVerify = true; - } + public GZipReaderTests() => UseExtensionInsteadOfNameToVerify = true; [Fact] - public void GZip_Reader_Generic() - { - Read("Tar.tar.gz", CompressionType.GZip); - } + public void GZip_Reader_Generic() => Read("Tar.tar.gz", CompressionType.GZip); [Fact] public void GZip_Reader_Generic2() diff --git a/tests/SharpCompress.Test/GZip/GZipWriterTests.cs b/tests/SharpCompress.Test/GZip/GZipWriterTests.cs index 360c5b65..7fbf0b5b 100644 --- a/tests/SharpCompress.Test/GZip/GZipWriterTests.cs +++ b/tests/SharpCompress.Test/GZip/GZipWriterTests.cs @@ -1,4 +1,4 @@ -using System.IO; +using System.IO; using SharpCompress.Common; using SharpCompress.Writers; using SharpCompress.Writers.GZip; @@ -8,10 +8,7 @@ namespace SharpCompress.Test.GZip; public class GZipWriterTests : WriterTests { - public GZipWriterTests() : base(ArchiveType.GZip) - { - UseExtensionInsteadOfNameToVerify = true; - } + public GZipWriterTests() : base(ArchiveType.GZip) => UseExtensionInsteadOfNameToVerify = true; [Fact] public void GZip_Writer_Generic() @@ -54,14 +51,12 @@ public class GZipWriterTests : WriterTests } [Fact] - public void GZip_Writer_Generic_Bad_Compression() - { + public void GZip_Writer_Generic_Bad_Compression() => Assert.Throws(() => { using Stream stream = File.OpenWrite(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz")); using var writer = WriterFactory.Open(stream, ArchiveType.GZip, CompressionType.BZip2); }); - } [Fact] public void GZip_Writer_Entry_Path_With_Dir() diff --git a/tests/SharpCompress.Test/Mocks/FlushOnDisposeStream.cs b/tests/SharpCompress.Test/Mocks/FlushOnDisposeStream.cs index 5e2c4db2..194e7788 100644 --- a/tests/SharpCompress.Test/Mocks/FlushOnDisposeStream.cs +++ b/tests/SharpCompress.Test/Mocks/FlushOnDisposeStream.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; namespace SharpCompress.Test.Mocks; @@ -11,10 +11,7 @@ public class FlushOnDisposeStream : Stream, IDisposable { private Stream inner; - public FlushOnDisposeStream(Stream innerStream) - { - inner = innerStream; - } + public FlushOnDisposeStream(Stream innerStream) => inner = innerStream; public override bool CanRead => inner.CanRead; @@ -30,30 +27,18 @@ public class FlushOnDisposeStream : Stream, IDisposable set => inner.Position = value; } - public override void Flush() - { - throw new NotImplementedException(); - } + public override void Flush() => throw new NotImplementedException(); - public override int Read(byte[] buffer, int offset, int count) - { - return inner.Read(buffer, offset, count); - } + public override int Read(byte[] buffer, int offset, int count) => + inner.Read(buffer, offset, count); - public override long Seek(long offset, SeekOrigin origin) - { + public override long Seek(long offset, SeekOrigin origin) => throw new NotImplementedException(); - } - public override void SetLength(long value) - { - throw new NotImplementedException(); - } + public override void SetLength(long value) => throw new NotImplementedException(); - public override void Write(byte[] buffer, int offset, int count) - { + public override void Write(byte[] buffer, int offset, int count) => throw new NotImplementedException(); - } protected override void Dispose(bool disposing) { diff --git a/tests/SharpCompress.Test/Mocks/ForwardOnlyStream.cs b/tests/SharpCompress.Test/Mocks/ForwardOnlyStream.cs index 68301db1..cef93a38 100644 --- a/tests/SharpCompress.Test/Mocks/ForwardOnlyStream.cs +++ b/tests/SharpCompress.Test/Mocks/ForwardOnlyStream.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; namespace SharpCompress.Test.Mocks; @@ -9,10 +9,7 @@ public class ForwardOnlyStream : Stream public bool IsDisposed { get; private set; } - public ForwardOnlyStream(Stream stream) - { - this.stream = stream; - } + public ForwardOnlyStream(Stream stream) => this.stream = stream; protected override void Dispose(bool disposing) { @@ -32,10 +29,7 @@ public class ForwardOnlyStream : Stream public override bool CanSeek => false; public override bool CanWrite => false; - public override void Flush() - { - throw new NotSupportedException(); - } + public override void Flush() => throw new NotSupportedException(); public override long Length => throw new NotSupportedException(); @@ -45,23 +39,13 @@ public class ForwardOnlyStream : Stream set => throw new NotSupportedException(); } - public override int Read(byte[] buffer, int offset, int count) - { - return stream.Read(buffer, offset, count); - } + public override int Read(byte[] buffer, int offset, int count) => + stream.Read(buffer, offset, count); - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } + public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException(); - public override void SetLength(long value) - { - throw new NotSupportedException(); - } + public override void SetLength(long value) => throw new NotSupportedException(); - public override void Write(byte[] buffer, int offset, int count) - { + public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException(); - } } diff --git a/tests/SharpCompress.Test/Mocks/TestStream.cs b/tests/SharpCompress.Test/Mocks/TestStream.cs index bd49ebc3..f79c5b9d 100644 --- a/tests/SharpCompress.Test/Mocks/TestStream.cs +++ b/tests/SharpCompress.Test/Mocks/TestStream.cs @@ -1,4 +1,4 @@ -using System.IO; +using System.IO; namespace SharpCompress.Test.Mocks; @@ -32,10 +32,7 @@ public class TestStream : Stream public override bool CanWrite { get; } - public override void Flush() - { - stream.Flush(); - } + public override void Flush() => stream.Flush(); public override long Length => stream.Length; @@ -45,23 +42,13 @@ public class TestStream : Stream set => stream.Position = value; } - public override int Read(byte[] buffer, int offset, int count) - { - return stream.Read(buffer, offset, count); - } + public override int Read(byte[] buffer, int offset, int count) => + stream.Read(buffer, offset, count); - public override long Seek(long offset, SeekOrigin origin) - { - return stream.Seek(offset, origin); - } + public override long Seek(long offset, SeekOrigin origin) => stream.Seek(offset, origin); - public override void SetLength(long value) - { - stream.SetLength(value); - } + public override void SetLength(long value) => stream.SetLength(value); - public override void Write(byte[] buffer, int offset, int count) - { + public override void Write(byte[] buffer, int offset, int count) => stream.Write(buffer, offset, count); - } } diff --git a/tests/SharpCompress.Test/Rar/RarArchiveTests.cs b/tests/SharpCompress.Test/Rar/RarArchiveTests.cs index 686eb708..0936a8ed 100644 --- a/tests/SharpCompress.Test/Rar/RarArchiveTests.cs +++ b/tests/SharpCompress.Test/Rar/RarArchiveTests.cs @@ -1,12 +1,9 @@ -using System.Collections.Generic; using System.IO; using System.Linq; -using System.Text; using SharpCompress.Archives; using SharpCompress.Archives.Rar; using SharpCompress.Common; using SharpCompress.Compressors.LZMA.Utilites; -using SharpCompress.Factories; using SharpCompress.Readers; using Xunit; @@ -15,19 +12,15 @@ namespace SharpCompress.Test.Rar; public class RarArchiveTests : ArchiveTests { [Fact] - public void Rar_EncryptedFileAndHeader_Archive() - { + public void Rar_EncryptedFileAndHeader_Archive() => ReadRarPassword("Rar.encrypted_filesAndHeader.rar", "test"); - } [Fact] - public void Rar_EncryptedFileAndHeader_NoPasswordExceptionTest() - { + public void Rar_EncryptedFileAndHeader_NoPasswordExceptionTest() => Assert.Throws( typeof(CryptographicException), () => ReadRarPassword("Rar.encrypted_filesAndHeader.rar", null) ); - } /*[Fact] public void Rar5_EncryptedFileAndHeader_Archive() @@ -36,19 +29,15 @@ public class RarArchiveTests : ArchiveTests }*/ [Fact] - public void Rar5_EncryptedFileAndHeader_NoPasswordExceptionTest() - { + public void Rar5_EncryptedFileAndHeader_NoPasswordExceptionTest() => Assert.Throws( typeof(CryptographicException), () => ReadRarPassword("Rar5.encrypted_filesAndHeader.rar", null) ); - } [Fact] - public void Rar_EncryptedFileOnly_Archive() - { + public void Rar_EncryptedFileOnly_Archive() => ReadRarPassword("Rar.encrypted_filesOnly.rar", "test"); - } /*[Fact] public void Rar5_EncryptedFileOnly_Archive() @@ -57,10 +46,7 @@ public class RarArchiveTests : ArchiveTests }*/ [Fact] - public void Rar_Encrypted_Archive() - { - ReadRarPassword("Rar.Encrypted.rar", "test"); - } + public void Rar_Encrypted_Archive() => ReadRarPassword("Rar.Encrypted.rar", "test"); /*[Fact] public void Rar5_Encrypted_Archive() @@ -94,12 +80,10 @@ public class RarArchiveTests : ArchiveTests } [Fact] - public void Rar_Multi_Archive_Encrypted() - { + public void Rar_Multi_Archive_Encrypted() => Assert.Throws( () => ArchiveFileReadPassword("Rar.EncryptedParts.part01.rar", "test") ); - } protected void ArchiveFileReadPassword(string archiveName, string password) { @@ -122,34 +106,20 @@ public class RarArchiveTests : ArchiveTests } [Fact] - public void Rar_None_ArchiveStreamRead() - { - ArchiveStreamRead("Rar.none.rar"); - } + public void Rar_None_ArchiveStreamRead() => ArchiveStreamRead("Rar.none.rar"); [Fact] - public void Rar5_None_ArchiveStreamRead() - { - ArchiveStreamRead("Rar5.none.rar"); - } + public void Rar5_None_ArchiveStreamRead() => ArchiveStreamRead("Rar5.none.rar"); [Fact] - public void Rar_ArchiveStreamRead() - { - ArchiveStreamRead("Rar.rar"); - } + public void Rar_ArchiveStreamRead() => ArchiveStreamRead("Rar.rar"); [Fact] - public void Rar5_ArchiveStreamRead() - { - ArchiveStreamRead("Rar5.rar"); - } + public void Rar5_ArchiveStreamRead() => ArchiveStreamRead("Rar5.rar"); [Fact] - public void Rar_test_invalid_exttime_ArchiveStreamRead() - { + public void Rar_test_invalid_exttime_ArchiveStreamRead() => DoRar_test_invalid_exttime_ArchiveStreamRead("Rar.test_invalid_exttime.rar"); - } private void DoRar_test_invalid_exttime_ArchiveStreamRead(string filename) { @@ -182,16 +152,10 @@ public class RarArchiveTests : ArchiveTests } [Fact] - public void Rar_IsSolidArchiveCheck() - { - DoRar_IsSolidArchiveCheck("Rar.rar"); - } + public void Rar_IsSolidArchiveCheck() => DoRar_IsSolidArchiveCheck("Rar.rar"); [Fact] - public void Rar5_IsSolidArchiveCheck() - { - DoRar_IsSolidArchiveCheck("Rar5.rar"); - } + public void Rar5_IsSolidArchiveCheck() => DoRar_IsSolidArchiveCheck("Rar5.rar"); private void DoRar_IsSolidArchiveCheck(string filename) { @@ -211,48 +175,7 @@ public class RarArchiveTests : ArchiveTests } [Fact] - public void QuickTest() - { - var textItems = new List(); - using var reader = new RarFactory().OpenReader( - new FileInfo("/Users/adam/Downloads/Kuuki_Aether_chinesevcv_1.0.rar").OpenRead(), - null - ); - textItems.Clear(); - while (reader.MoveToNextEntry()) - { - var entry = reader.Entry; - if (!(entry.Key.EndsWith("character.txt") || entry.Key.EndsWith("oto.ini"))) - { - continue; - } - using var stream = reader.OpenEntryStream(); - // Crashes here - using var streamReader = new StreamReader(stream, Encoding.UTF8); - textItems.Add($"------ {entry.Key} ------"); - var count = 0; - while (count < 256 && !streamReader.EndOfStream) - { - var line = streamReader.ReadLine(); - if (!string.IsNullOrWhiteSpace(line)) - { - textItems.Add(line); - count++; - } - } - - if (!streamReader.EndOfStream) - { - textItems.Add($"..."); - } - } - } - - [Fact] - public void Rar_IsSolidEntryStreamCheck() - { - DoRar_IsSolidEntryStreamCheck("Rar.solid.rar"); - } + public void Rar_IsSolidEntryStreamCheck() => DoRar_IsSolidEntryStreamCheck("Rar.solid.rar"); //Extract the 2nd file in a solid archive to check that the first file is skipped properly private void DoRar_IsSolidEntryStreamCheck(string filename) @@ -282,34 +205,23 @@ public class RarArchiveTests : ArchiveTests } [Fact] - public void Rar_Solid_ArchiveStreamRead() - { - ArchiveStreamRead("Rar.solid.rar"); - } + public void Rar_Solid_ArchiveStreamRead() => ArchiveStreamRead("Rar.solid.rar"); [Fact] - public void Rar5_Solid_ArchiveStreamRead() - { - ArchiveStreamRead("Rar5.solid.rar"); - } + public void Rar5_Solid_ArchiveStreamRead() => ArchiveStreamRead("Rar5.solid.rar"); [Fact] - public void Rar_Solid_StreamRead_Extract_All() - { + public void Rar_Solid_StreamRead_Extract_All() => ArchiveStreamReadExtractAll("Rar.solid.rar", CompressionType.Rar); - } [Fact] - public void Rar5_Solid_StreamRead_Extract_All() - { + public void Rar5_Solid_StreamRead_Extract_All() => ArchiveStreamReadExtractAll("Rar5.solid.rar", CompressionType.Rar); - } [Fact] - public void Rar_Multi_ArchiveStreamRead() - { + public void Rar_Multi_ArchiveStreamRead() => DoRar_Multi_ArchiveStreamRead( - new string[] + new[] { "Rar.multi.part01.rar", "Rar.multi.part02.rar", @@ -320,13 +232,11 @@ public class RarArchiveTests : ArchiveTests }, false ); - } [Fact] - public void Rar5_Multi_ArchiveStreamRead() - { + public void Rar5_Multi_ArchiveStreamRead() => DoRar_Multi_ArchiveStreamRead( - new string[] + new[] { "Rar5.multi.part01.rar", "Rar5.multi.part02.rar", @@ -337,7 +247,6 @@ public class RarArchiveTests : ArchiveTests }, false ); - } private void DoRar_Multi_ArchiveStreamRead(string[] archives, bool isSolid) { @@ -355,10 +264,9 @@ public class RarArchiveTests : ArchiveTests } [Fact] - public void Rar5_MultiSolid_ArchiveStreamRead() - { + public void Rar5_MultiSolid_ArchiveStreamRead() => DoRar_Multi_ArchiveStreamRead( - new string[] + new[] { "Rar.multi.solid.part01.rar", "Rar.multi.solid.part02.rar", @@ -369,43 +277,26 @@ public class RarArchiveTests : ArchiveTests }, true ); - } [Fact] - public void RarNoneArchiveFileRead() - { - ArchiveFileRead("Rar.none.rar"); - } + public void RarNoneArchiveFileRead() => ArchiveFileRead("Rar.none.rar"); [Fact] - public void Rar5NoneArchiveFileRead() - { - ArchiveFileRead("Rar5.none.rar"); - } + public void Rar5NoneArchiveFileRead() => ArchiveFileRead("Rar5.none.rar"); [Fact] - public void Rar_ArchiveFileRead() - { - ArchiveFileRead("Rar.rar"); - } + public void Rar_ArchiveFileRead() => ArchiveFileRead("Rar.rar"); [Fact] - public void Rar5_ArchiveFileRead() - { - ArchiveFileRead("Rar5.rar"); - } + public void Rar5_ArchiveFileRead() => ArchiveFileRead("Rar5.rar"); [Fact] - public void Rar_ArchiveFileRead_HasDirectories() - { + public void Rar_ArchiveFileRead_HasDirectories() => DoRar_ArchiveFileRead_HasDirectories("Rar.rar"); - } [Fact] - public void Rar5_ArchiveFileRead_HasDirectories() - { + public void Rar5_ArchiveFileRead_HasDirectories() => DoRar_ArchiveFileRead_HasDirectories("Rar5.rar"); - } private void DoRar_ArchiveFileRead_HasDirectories(string filename) { @@ -437,22 +328,15 @@ public class RarArchiveTests : ArchiveTests } [Fact] - public void Rar_Solid_ArchiveFileRead() - { - ArchiveFileRead("Rar.solid.rar"); - } + public void Rar_Solid_ArchiveFileRead() => ArchiveFileRead("Rar.solid.rar"); [Fact] - public void Rar5_Solid_ArchiveFileRead() - { - ArchiveFileRead("Rar5.solid.rar"); - } + public void Rar5_Solid_ArchiveFileRead() => ArchiveFileRead("Rar5.solid.rar"); [Fact] - public void Rar2_Multi_ArchiveStreamRead() - { + public void Rar2_Multi_ArchiveStreamRead() => DoRar_Multi_ArchiveStreamRead( - new string[] + new[] { "Rar2.multi.rar", "Rar2.multi.r00", @@ -464,19 +348,12 @@ public class RarArchiveTests : ArchiveTests }, false ); - } [Fact] - public void Rar2_Multi_ArchiveFileRead() - { - ArchiveFileRead("Rar2.multi.rar"); //r00, r01... - } + public void Rar2_Multi_ArchiveFileRead() => ArchiveFileRead("Rar2.multi.rar"); //r00, r01... [Fact] - public void Rar2_ArchiveFileRead() - { - ArchiveFileRead("Rar2.rar"); - } + public void Rar2_ArchiveFileRead() => ArchiveFileRead("Rar2.rar"); [Fact] public void Rar2_ArchiveVersionTest() @@ -509,23 +386,16 @@ public class RarArchiveTests : ArchiveTests } [Fact] - public void Rar4_Multi_ArchiveFileRead() - { - ArchiveFileRead("Rar4.multi.part01.rar"); - } + public void Rar4_Multi_ArchiveFileRead() => ArchiveFileRead("Rar4.multi.part01.rar"); [Fact] - public void Rar4_ArchiveFileRead() - { - ArchiveFileRead("Rar4.rar"); - } + public void Rar4_ArchiveFileRead() => ArchiveFileRead("Rar4.rar"); [Fact] - public void Rar_GetPartsSplit() - { + public void Rar_GetPartsSplit() => //uses first part to search for all parts and compares against this array ArchiveGetParts( - new string[] + new[] { "Rar4.split.001", "Rar4.split.002", @@ -535,14 +405,12 @@ public class RarArchiveTests : ArchiveTests "Rar4.split.006" } ); - } [Fact] - public void Rar_GetPartsOld() - { + public void Rar_GetPartsOld() => //uses first part to search for all parts and compares against this array ArchiveGetParts( - new string[] + new[] { "Rar2.multi.rar", "Rar2.multi.r00", @@ -553,14 +421,12 @@ public class RarArchiveTests : ArchiveTests "Rar2.multi.r05" } ); - } [Fact] - public void Rar_GetPartsNew() - { + public void Rar_GetPartsNew() => //uses first part to search for all parts and compares against this array ArchiveGetParts( - new string[] + new[] { "Rar4.multi.part01.rar", "Rar4.multi.part02.rar", @@ -571,13 +437,11 @@ public class RarArchiveTests : ArchiveTests "Rar4.multi.part07.rar" } ); - } [Fact] - public void Rar4_Multi_ArchiveStreamRead() - { + public void Rar4_Multi_ArchiveStreamRead() => DoRar_Multi_ArchiveStreamRead( - new string[] + new[] { "Rar4.multi.part01.rar", "Rar4.multi.part02.rar", @@ -589,15 +453,13 @@ public class RarArchiveTests : ArchiveTests }, false ); - } //no extension to test the lib identifies the archive by content not ext [Fact] - public void Rar4_Split_ArchiveStreamRead() - { + public void Rar4_Split_ArchiveStreamRead() => ArchiveStreamMultiRead( null, - new string[] + new[] { "Rar4.split.001", "Rar4.split.002", @@ -607,40 +469,32 @@ public class RarArchiveTests : ArchiveTests "Rar4.split.006" } ); - } //will detect and load other files [Fact] - public void Rar4_Multi_ArchiveFirstFileRead() - { - ArchiveFileRead("Rar4.multi.part01.rar"); - //"Rar4.multi.part02.rar", - //"Rar4.multi.part03.rar", - //"Rar4.multi.part04.rar", - //"Rar4.multi.part05.rar", - //"Rar4.multi.part06.rar", - //"Rar4.multi.part07.rar" - } + public void Rar4_Multi_ArchiveFirstFileRead() => ArchiveFileRead("Rar4.multi.part01.rar"); + //"Rar4.multi.part02.rar", + //"Rar4.multi.part03.rar", + //"Rar4.multi.part04.rar", + //"Rar4.multi.part05.rar", + //"Rar4.multi.part06.rar", + //"Rar4.multi.part07.rar" //will detect and load other files [Fact] - public void Rar4_Split_ArchiveFirstFileRead() - { - ArchiveFileRead("Rar4.split.001"); - //"Rar4.split.002", - //"Rar4.split.003", - //"Rar4.split.004", - //"Rar4.split.005", - //"Rar4.split.006" - } + public void Rar4_Split_ArchiveFirstFileRead() => ArchiveFileRead("Rar4.split.001"); + //"Rar4.split.002", + //"Rar4.split.003", + //"Rar4.split.004", + //"Rar4.split.005", + //"Rar4.split.006" //will detect and load other files [Fact] - public void Rar4_Split_ArchiveStreamFirstFileRead() - { + public void Rar4_Split_ArchiveStreamFirstFileRead() => ArchiveStreamMultiRead( null, - new string[] + new[] { "Rar4.split.001", //"Rar4.split.002", @@ -650,12 +504,10 @@ public class RarArchiveTests : ArchiveTests //"Rar4.split.006" } ); - } //open with ArchiveFactory.Open and stream [Fact] - public void Rar4_Split_ArchiveOpen() - { + public void Rar4_Split_ArchiveOpen() => ArchiveOpenStreamRead( null, "Rar4.split.001", @@ -665,12 +517,10 @@ public class RarArchiveTests : ArchiveTests "Rar4.split.005", "Rar4.split.006" ); - } //open with ArchiveFactory.Open and stream [Fact] - public void Rar4_Multi_ArchiveOpen() - { + public void Rar4_Multi_ArchiveOpen() => ArchiveOpenStreamRead( null, "Rar4.multi.part01.rar", @@ -681,11 +531,9 @@ public class RarArchiveTests : ArchiveTests "Rar4.multi.part06.rar", "Rar4.multi.part07.rar" ); - } [Fact] - public void Rar4_Multi_ArchiveOpenEntryVolumeIndexTest() - { + public void Rar4_Multi_ArchiveOpenEntryVolumeIndexTest() => ArchiveOpenEntryVolumeIndexTest( new[] { @@ -702,31 +550,18 @@ public class RarArchiveTests : ArchiveTests "Rar4.multi.part06.rar", "Rar4.multi.part07.rar" ); - } [Fact] - public void Rar_Multi_ArchiveFileRead() - { - ArchiveFileRead("Rar.multi.part01.rar"); - } + public void Rar_Multi_ArchiveFileRead() => ArchiveFileRead("Rar.multi.part01.rar"); [Fact] - public void Rar5_Multi_ArchiveFileRead() - { - ArchiveFileRead("Rar5.multi.part01.rar"); - } + public void Rar5_Multi_ArchiveFileRead() => ArchiveFileRead("Rar5.multi.part01.rar"); [Fact] - public void Rar_IsFirstVolume_True() - { - DoRar_IsFirstVolume_True("Rar.multi.part01.rar"); - } + public void Rar_IsFirstVolume_True() => DoRar_IsFirstVolume_True("Rar.multi.part01.rar"); [Fact] - public void Rar5_IsFirstVolume_True() - { - DoRar_IsFirstVolume_True("Rar5.multi.part01.rar"); - } + public void Rar5_IsFirstVolume_True() => DoRar_IsFirstVolume_True("Rar5.multi.part01.rar"); private void DoRar_IsFirstVolume_True(string firstFilename) { @@ -736,16 +571,10 @@ public class RarArchiveTests : ArchiveTests } [Fact] - public void Rar_IsFirstVolume_False() - { - DoRar_IsFirstVolume_False("Rar.multi.part03.rar"); - } + public void Rar_IsFirstVolume_False() => DoRar_IsFirstVolume_False("Rar.multi.part03.rar"); [Fact] - public void Rar5_IsFirstVolume_False() - { - DoRar_IsFirstVolume_False("Rar5.multi.part03.rar"); - } + public void Rar5_IsFirstVolume_False() => DoRar_IsFirstVolume_False("Rar5.multi.part03.rar"); private void DoRar_IsFirstVolume_False(string notFirstFilename) { diff --git a/tests/SharpCompress.Test/Rar/RarHeaderFactoryTest.cs b/tests/SharpCompress.Test/Rar/RarHeaderFactoryTest.cs index 2bf90768..f2b1913c 100644 --- a/tests/SharpCompress.Test/Rar/RarHeaderFactoryTest.cs +++ b/tests/SharpCompress.Test/Rar/RarHeaderFactoryTest.cs @@ -13,37 +13,25 @@ public class RarHeaderFactoryTest : TestBase { private readonly RarHeaderFactory rarHeaderFactory; - public RarHeaderFactoryTest() - { + public RarHeaderFactoryTest() => rarHeaderFactory = new RarHeaderFactory( StreamingMode.Seekable, new ReaderOptions { LeaveStreamOpen = true } ); - } [Fact] - public void Rar_ReadHeaders_RecognizeEncryptedFlag() - { + public void Rar_ReadHeaders_RecognizeEncryptedFlag() => ReadEncryptedFlag("Rar.encrypted_filesAndHeader.rar", true); - } [Fact] - public void Rar5_ReadHeaders_RecognizeEncryptedFlag() - { + public void Rar5_ReadHeaders_RecognizeEncryptedFlag() => ReadEncryptedFlag("Rar5.encrypted_filesAndHeader.rar", true); - } [Fact] - public void Rar_ReadHeaders_RecognizeNoEncryptedFlag() - { - ReadEncryptedFlag("Rar.rar", false); - } + public void Rar_ReadHeaders_RecognizeNoEncryptedFlag() => ReadEncryptedFlag("Rar.rar", false); [Fact] - public void Rar5_ReadHeaders_RecognizeNoEncryptedFlag() - { - ReadEncryptedFlag("Rar5.rar", false); - } + public void Rar5_ReadHeaders_RecognizeNoEncryptedFlag() => ReadEncryptedFlag("Rar5.rar", false); private void ReadEncryptedFlag(string testArchive, bool isEncrypted) { diff --git a/tests/SharpCompress.Test/Rar/RarReaderTests.cs b/tests/SharpCompress.Test/Rar/RarReaderTests.cs index 5e98eee0..45744270 100644 --- a/tests/SharpCompress.Test/Rar/RarReaderTests.cs +++ b/tests/SharpCompress.Test/Rar/RarReaderTests.cs @@ -11,10 +11,9 @@ namespace SharpCompress.Test.Rar; public class RarReaderTests : ReaderTests { [Fact] - public void Rar_Multi_Reader() - { + public void Rar_Multi_Reader() => DoRar_Multi_Reader( - new string[] + new[] { "Rar.multi.part01.rar", "Rar.multi.part02.rar", @@ -24,13 +23,11 @@ public class RarReaderTests : ReaderTests "Rar.multi.part06.rar" } ); - } [Fact] - public void Rar5_Multi_Reader() - { + public void Rar5_Multi_Reader() => DoRar_Multi_Reader( - new string[] + new[] { "Rar5.multi.part01.rar", "Rar5.multi.part02.rar", @@ -40,7 +37,6 @@ public class RarReaderTests : ReaderTests "Rar5.multi.part06.rar" } ); - } private void DoRar_Multi_Reader(string[] archives) { @@ -64,10 +60,9 @@ public class RarReaderTests : ReaderTests } [Fact] - public void Rar_Multi_Reader_Encrypted() - { + public void Rar_Multi_Reader_Encrypted() => DoRar_Multi_Reader_Encrypted( - new string[] + new[] { "Rar.EncryptedParts.part01.rar", "Rar.EncryptedParts.part02.rar", @@ -77,10 +72,8 @@ public class RarReaderTests : ReaderTests "Rar.EncryptedParts.part06.rar" } ); - } - private void DoRar_Multi_Reader_Encrypted(string[] archives) - { + private void DoRar_Multi_Reader_Encrypted(string[] archives) => Assert.Throws(() => { using ( @@ -102,13 +95,11 @@ public class RarReaderTests : ReaderTests } VerifyFiles(); }); - } [Fact] - public void Rar_Multi_Reader_Delete_Files() - { + public void Rar_Multi_Reader_Delete_Files() => DoRar_Multi_Reader_Delete_Files( - new string[] + new[] { "Rar.multi.part01.rar", "Rar.multi.part02.rar", @@ -118,13 +109,11 @@ public class RarReaderTests : ReaderTests "Rar.multi.part06.rar" } ); - } [Fact] - public void Rar5_Multi_Reader_Delete_Files() - { + public void Rar5_Multi_Reader_Delete_Files() => DoRar_Multi_Reader_Delete_Files( - new string[] + new[] { "Rar5.multi.part01.rar", "Rar5.multi.part02.rar", @@ -134,7 +123,6 @@ public class RarReaderTests : ReaderTests "Rar5.multi.part06.rar" } ); - } private void DoRar_Multi_Reader_Delete_Files(string[] archives) { @@ -172,34 +160,20 @@ public class RarReaderTests : ReaderTests } [Fact] - public void Rar_None_Reader() - { - Read("Rar.none.rar", CompressionType.Rar); - } + public void Rar_None_Reader() => Read("Rar.none.rar", CompressionType.Rar); [Fact] - public void Rar5_None_Reader() - { - Read("Rar5.none.rar", CompressionType.Rar); - } + public void Rar5_None_Reader() => Read("Rar5.none.rar", CompressionType.Rar); [Fact] - public void Rar_Reader() - { - Read("Rar.rar", CompressionType.Rar); - } + public void Rar_Reader() => Read("Rar.rar", CompressionType.Rar); [Fact] - public void Rar5_Reader() - { - Read("Rar5.rar", CompressionType.Rar); - } + public void Rar5_Reader() => Read("Rar5.rar", CompressionType.Rar); [Fact] - public void Rar_EncryptedFileAndHeader_Reader() - { + public void Rar_EncryptedFileAndHeader_Reader() => ReadRar("Rar.encrypted_filesAndHeader.rar", "test"); - } /*[Fact] public void Rar5_EncryptedFileAndHeader_Reader() @@ -208,10 +182,7 @@ public class RarReaderTests : ReaderTests }*/ [Fact] - public void Rar_EncryptedFileOnly_Reader() - { - ReadRar("Rar.encrypted_filesOnly.rar", "test"); - } + public void Rar_EncryptedFileOnly_Reader() => ReadRar("Rar.encrypted_filesOnly.rar", "test"); /*[Fact] public void Rar5_EncryptedFileOnly_Reader() @@ -220,10 +191,7 @@ public class RarReaderTests : ReaderTests }*/ [Fact] - public void Rar_Encrypted_Reader() - { - ReadRar("Rar.Encrypted.rar", "test"); - } + public void Rar_Encrypted_Reader() => ReadRar("Rar.Encrypted.rar", "test"); /*[Fact] public void Rar5_Encrypted_Reader() @@ -231,22 +199,14 @@ public class RarReaderTests : ReaderTests ReadRar("Rar5.encrypted_filesOnly.rar", "test"); }*/ - private void ReadRar(string testArchive, string password) - { + private void ReadRar(string testArchive, string password) => Read(testArchive, CompressionType.Rar, new ReaderOptions { Password = password }); - } [Fact] - public void Rar_Entry_Stream() - { - DoRar_Entry_Stream("Rar.rar"); - } + public void Rar_Entry_Stream() => DoRar_Entry_Stream("Rar.rar"); [Fact] - public void Rar5_Entry_Stream() - { - DoRar_Entry_Stream("Rar5.rar"); - } + public void Rar5_Entry_Stream() => DoRar_Entry_Stream("Rar5.rar"); private void DoRar_Entry_Stream(string filename) { @@ -322,28 +282,16 @@ public class RarReaderTests : ReaderTests } [Fact] - public void Rar_Solid_Reader() - { - Read("Rar.solid.rar", CompressionType.Rar); - } + public void Rar_Solid_Reader() => Read("Rar.solid.rar", CompressionType.Rar); [Fact] - public void Rar5_Solid_Reader() - { - Read("Rar5.solid.rar", CompressionType.Rar); - } + public void Rar5_Solid_Reader() => Read("Rar5.solid.rar", CompressionType.Rar); [Fact] - public void Rar_Solid_Skip_Reader() - { - DoRar_Solid_Skip_Reader("Rar.solid.rar"); - } + public void Rar_Solid_Skip_Reader() => DoRar_Solid_Skip_Reader("Rar.solid.rar"); [Fact] - public void Rar5_Solid_Skip_Reader() - { - DoRar_Solid_Skip_Reader("Rar5.solid.rar"); - } + public void Rar5_Solid_Skip_Reader() => DoRar_Solid_Skip_Reader("Rar5.solid.rar"); private void DoRar_Solid_Skip_Reader(string filename) { @@ -363,16 +311,10 @@ public class RarReaderTests : ReaderTests } [Fact] - public void Rar_Reader_Skip() - { - DoRar_Reader_Skip("Rar.rar"); - } + public void Rar_Reader_Skip() => DoRar_Reader_Skip("Rar.rar"); [Fact] - public void Rar5_Reader_Skip() - { - DoRar_Reader_Skip("Rar5.rar"); - } + public void Rar5_Reader_Skip() => DoRar_Reader_Skip("Rar5.rar"); private void DoRar_Reader_Skip(string filename) { diff --git a/tests/SharpCompress.Test/SevenZip/SevenZipArchiveTests.cs b/tests/SharpCompress.Test/SevenZip/SevenZipArchiveTests.cs index 23b99a1a..22d45b2a 100644 --- a/tests/SharpCompress.Test/SevenZip/SevenZipArchiveTests.cs +++ b/tests/SharpCompress.Test/SevenZip/SevenZipArchiveTests.cs @@ -8,113 +8,68 @@ namespace SharpCompress.Test.SevenZip; public class SevenZipArchiveTests : ArchiveTests { [Fact] - public void SevenZipArchive_Solid_StreamRead() - { - ArchiveStreamRead("7Zip.solid.7z"); - } + public void SevenZipArchive_Solid_StreamRead() => ArchiveStreamRead("7Zip.solid.7z"); [Fact] - public void SevenZipArchive_NonSolid_StreamRead() - { - ArchiveStreamRead("7Zip.nonsolid.7z"); - } + public void SevenZipArchive_NonSolid_StreamRead() => ArchiveStreamRead("7Zip.nonsolid.7z"); [Fact] - public void SevenZipArchive_LZMA_StreamRead() - { - ArchiveStreamRead("7Zip.LZMA.7z"); - } + public void SevenZipArchive_LZMA_StreamRead() => ArchiveStreamRead("7Zip.LZMA.7z"); [Fact] - public void SevenZipArchive_LZMA_PathRead() - { - ArchiveFileRead("7Zip.LZMA.7z"); - } + public void SevenZipArchive_LZMA_PathRead() => ArchiveFileRead("7Zip.LZMA.7z"); [Fact] - public void SevenZipArchive_LZMAAES_StreamRead() - { + public void SevenZipArchive_LZMAAES_StreamRead() => ArchiveStreamRead("7Zip.LZMA.Aes.7z", new ReaderOptions() { Password = "testpassword" }); - } [Fact] - public void SevenZipArchive_LZMAAES_PathRead() - { + public void SevenZipArchive_LZMAAES_PathRead() => ArchiveFileRead("7Zip.LZMA.Aes.7z", new ReaderOptions() { Password = "testpassword" }); - } [Fact] - public void SevenZipArchive_LZMAAES_NoPasswordExceptionTest() - { + public void SevenZipArchive_LZMAAES_NoPasswordExceptionTest() => Assert.Throws( typeof(CryptographicException), () => ArchiveFileRead("7Zip.LZMA.Aes.7z", new ReaderOptions() { Password = null }) ); //was failing with ArgumentNullException not CryptographicException like rar - } [Fact] - public void SevenZipArchive_PPMd_StreamRead() - { - ArchiveStreamRead("7Zip.PPMd.7z"); - } + public void SevenZipArchive_PPMd_StreamRead() => ArchiveStreamRead("7Zip.PPMd.7z"); [Fact] - public void SevenZipArchive_PPMd_StreamRead_Extract_All() - { + public void SevenZipArchive_PPMd_StreamRead_Extract_All() => ArchiveStreamReadExtractAll("7Zip.PPMd.7z", CompressionType.PPMd); - } [Fact] - public void SevenZipArchive_PPMd_PathRead() - { - ArchiveFileRead("7Zip.PPMd.7z"); - } + public void SevenZipArchive_PPMd_PathRead() => ArchiveFileRead("7Zip.PPMd.7z"); [Fact] - public void SevenZipArchive_LZMA2_StreamRead() - { - ArchiveStreamRead("7Zip.LZMA2.7z"); - } + public void SevenZipArchive_LZMA2_StreamRead() => ArchiveStreamRead("7Zip.LZMA2.7z"); [Fact] - public void SevenZipArchive_LZMA2_PathRead() - { - ArchiveFileRead("7Zip.LZMA2.7z"); - } + public void SevenZipArchive_LZMA2_PathRead() => ArchiveFileRead("7Zip.LZMA2.7z"); [Fact] - public void SevenZipArchive_LZMA2AES_StreamRead() - { + public void SevenZipArchive_LZMA2AES_StreamRead() => ArchiveStreamRead("7Zip.LZMA2.Aes.7z", new ReaderOptions { Password = "testpassword" }); - } [Fact] - public void SevenZipArchive_LZMA2AES_PathRead() - { + public void SevenZipArchive_LZMA2AES_PathRead() => ArchiveFileRead("7Zip.LZMA2.Aes.7z", new ReaderOptions { Password = "testpassword" }); - } [Fact] - public void SevenZipArchive_BZip2_StreamRead() - { - ArchiveStreamRead("7Zip.BZip2.7z"); - } + public void SevenZipArchive_BZip2_StreamRead() => ArchiveStreamRead("7Zip.BZip2.7z"); [Fact] - public void SevenZipArchive_BZip2_PathRead() - { - ArchiveFileRead("7Zip.BZip2.7z"); - } + public void SevenZipArchive_BZip2_PathRead() => ArchiveFileRead("7Zip.BZip2.7z"); [Fact] - public void SevenZipArchive_LZMA_Time_Attributes_PathRead() - { + public void SevenZipArchive_LZMA_Time_Attributes_PathRead() => ArchiveFileReadEx("7Zip.LZMA.7z"); - } [Fact] - public void SevenZipArchive_BZip2_Split() - { + public void SevenZipArchive_BZip2_Split() => Assert.Throws( () => ArchiveStreamRead( @@ -128,12 +83,10 @@ public class SevenZipArchiveTests : ArchiveTests "Original.7z.007" ) ); - } //Same as archive as Original.7z.001 ... 007 files without the root directory 'Original\' in the archive - this caused the verify to fail [Fact] - public void SevenZipArchive_BZip2_Split_Working() - { + public void SevenZipArchive_BZip2_Split_Working() => ArchiveStreamMultiRead( null, "7Zip.BZip2.split.001", @@ -144,18 +97,16 @@ public class SevenZipArchiveTests : ArchiveTests "7Zip.BZip2.split.006", "7Zip.BZip2.split.007" ); - } //will detect and load other files [Fact] - public void SevenZipArchive_BZip2_Split_FirstFileRead() - { + public void SevenZipArchive_BZip2_Split_FirstFileRead() => ArchiveFileRead("7Zip.BZip2.split.001"); - //"7Zip.BZip2.split.002", - //"7Zip.BZip2.split.003", - //"7Zip.BZip2.split.004", - //"7Zip.BZip2.split.005", - //"7Zip.BZip2.split.006", - //"7Zip.BZip2.split.007" - } + + //"7Zip.BZip2.split.002", + //"7Zip.BZip2.split.003", + //"7Zip.BZip2.split.004", + //"7Zip.BZip2.split.005", + //"7Zip.BZip2.split.006", + //"7Zip.BZip2.split.007" } diff --git a/tests/SharpCompress.Test/Tar/TarArchiveTests.cs b/tests/SharpCompress.Test/Tar/TarArchiveTests.cs index 37dc7650..fd05d15e 100644 --- a/tests/SharpCompress.Test/Tar/TarArchiveTests.cs +++ b/tests/SharpCompress.Test/Tar/TarArchiveTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; using System.Linq; using SharpCompress.Archives; @@ -11,307 +11,294 @@ using SharpCompress.Readers; using SharpCompress.Writers.Tar; using SharpCompress.Readers.Tar; -namespace SharpCompress.Test.Tar +namespace SharpCompress.Test.Tar; + +public class TarArchiveTests : ArchiveTests { - public class TarArchiveTests : ArchiveTests + public TarArchiveTests() => UseExtensionInsteadOfNameToVerify = true; + + [Fact] + public void TarArchiveStreamRead() => ArchiveStreamRead("Tar.tar"); + + [Fact] + public void TarArchivePathRead() => ArchiveFileRead("Tar.tar"); + + [Fact] + public void Tar_FileName_Exactly_100_Characters() { - public TarArchiveTests() + string archive = "Tar_FileName_Exactly_100_Characters.tar"; + + // create the 100 char filename + string filename = + "filename_with_exactly_100_characters_______________________________________________________________X"; + + // Step 1: create a tar file containing a file with the test name + using (Stream stream = File.OpenWrite(Path.Combine(SCRATCH2_FILES_PATH, archive))) + using (var writer = WriterFactory.Open(stream, ArchiveType.Tar, CompressionType.None)) + using (Stream inputStream = new MemoryStream()) { - UseExtensionInsteadOfNameToVerify = true; + StreamWriter sw = new StreamWriter(inputStream); + sw.Write("dummy filecontent"); + sw.Flush(); + + inputStream.Position = 0; + writer.Write(filename, inputStream, null); } - [Fact] - public void TarArchiveStreamRead() + // Step 2: check if the written tar file can be read correctly + string unmodified = Path.Combine(SCRATCH2_FILES_PATH, archive); + using (var archive2 = TarArchive.Open(unmodified)) { - ArchiveStreamRead("Tar.tar"); - } + Assert.Equal(1, archive2.Entries.Count); + Assert.Contains(filename, archive2.Entries.Select(entry => entry.Key)); - [Fact] - public void TarArchivePathRead() - { - ArchiveFileRead("Tar.tar"); - } - - [Fact] - public void Tar_FileName_Exactly_100_Characters() - { - string archive = "Tar_FileName_Exactly_100_Characters.tar"; - - // create the 100 char filename - string filename = - "filename_with_exactly_100_characters_______________________________________________________________X"; - - // Step 1: create a tar file containing a file with the test name - using (Stream stream = File.OpenWrite(Path.Combine(SCRATCH2_FILES_PATH, archive))) - using (var writer = WriterFactory.Open(stream, ArchiveType.Tar, CompressionType.None)) - using (Stream inputStream = new MemoryStream()) + foreach (var entry in archive2.Entries) { - StreamWriter sw = new StreamWriter(inputStream); - sw.Write("dummy filecontent"); - sw.Flush(); - - inputStream.Position = 0; - writer.Write(filename, inputStream, null); - } - - // Step 2: check if the written tar file can be read correctly - string unmodified = Path.Combine(SCRATCH2_FILES_PATH, archive); - using (var archive2 = TarArchive.Open(unmodified)) - { - Assert.Equal(1, archive2.Entries.Count); - Assert.Contains(filename, archive2.Entries.Select(entry => entry.Key)); - - foreach (var entry in archive2.Entries) - { - Assert.Equal( - "dummy filecontent", - new StreamReader(entry.OpenEntryStream()).ReadLine() - ); - } - } - } - - [Fact] - public void Tar_NonUstarArchiveWithLongNameDoesNotSkipEntriesAfterTheLongOne() - { - string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "very long filename.tar"); - using (var archive = TarArchive.Open(unmodified)) - { - Assert.Equal(5, archive.Entries.Count); - Assert.Contains("very long filename/", archive.Entries.Select(entry => entry.Key)); - Assert.Contains( - "very long filename/very long filename very long filename very long filename very long filename very long filename very long filename very long filename very long filename very long filename very long filename.jpg", - archive.Entries.Select(entry => entry.Key) + Assert.Equal( + "dummy filecontent", + new StreamReader(entry.OpenEntryStream()).ReadLine() ); - Assert.Contains("z_file 1.txt", archive.Entries.Select(entry => entry.Key)); - Assert.Contains("z_file 2.txt", archive.Entries.Select(entry => entry.Key)); - Assert.Contains("z_file 3.txt", archive.Entries.Select(entry => entry.Key)); - } - } - - [Fact] - public void Tar_VeryLongFilepathReadback() - { - string archive = "Tar_VeryLongFilepathReadback.tar"; - - // create a very long filename - string longFilename = ""; - for (int i = 0; i < 600; i = longFilename.Length) - { - longFilename += i.ToString("D10") + "-"; - } - - longFilename += ".txt"; - - // Step 1: create a tar file containing a file with a long name - using (Stream stream = File.OpenWrite(Path.Combine(SCRATCH2_FILES_PATH, archive))) - using (var writer = WriterFactory.Open(stream, ArchiveType.Tar, CompressionType.None)) - using (Stream inputStream = new MemoryStream()) - { - StreamWriter sw = new StreamWriter(inputStream); - sw.Write("dummy filecontent"); - sw.Flush(); - - inputStream.Position = 0; - writer.Write(longFilename, inputStream, null); - } - - // Step 2: check if the written tar file can be read correctly - string unmodified = Path.Combine(SCRATCH2_FILES_PATH, archive); - using (var archive2 = TarArchive.Open(unmodified)) - { - Assert.Equal(1, archive2.Entries.Count); - Assert.Contains(longFilename, archive2.Entries.Select(entry => entry.Key)); - - foreach (var entry in archive2.Entries) - { - Assert.Equal( - "dummy filecontent", - new StreamReader(entry.OpenEntryStream()).ReadLine() - ); - } - } - } - - [Fact] - public void Tar_UstarArchivePathReadLongName() - { - string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "ustar with long names.tar"); - using (var archive = TarArchive.Open(unmodified)) - { - Assert.Equal(6, archive.Entries.Count); - Assert.Contains("Directory/", archive.Entries.Select(entry => entry.Key)); - Assert.Contains( - "Directory/Some file with veeeeeeeeeery loooooooooong name", - archive.Entries.Select(entry => entry.Key) - ); - Assert.Contains( - "Directory/Directory with veeeeeeeeeery loooooooooong name/", - archive.Entries.Select(entry => entry.Key) - ); - Assert.Contains( - "Directory/Directory with veeeeeeeeeery loooooooooong name/Some file with veeeeeeeeeery loooooooooong name", - archive.Entries.Select(entry => entry.Key) - ); - Assert.Contains( - "Directory/Directory with veeeeeeeeeery loooooooooong name/Directory with veeeeeeeeeery loooooooooong name/", - archive.Entries.Select(entry => entry.Key) - ); - Assert.Contains( - "Directory/Directory with veeeeeeeeeery loooooooooong name/Directory with veeeeeeeeeery loooooooooong name/Some file with veeeeeeeeeery loooooooooong name", - archive.Entries.Select(entry => entry.Key) - ); - } - } - - [Fact] - public void Tar_Create_New() - { - string scratchPath = Path.Combine(SCRATCH_FILES_PATH, "Tar.tar"); - string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Tar.noEmptyDirs.tar"); - - // var aropt = new Ar - - using (var archive = TarArchive.Create()) - { - archive.AddAllFromDirectory(ORIGINAL_FILES_PATH); - var twopt = new TarWriterOptions(CompressionType.None, true); - twopt.ArchiveEncoding = new ArchiveEncoding() - { - Default = Encoding.GetEncoding(866) - }; - archive.SaveTo(scratchPath, twopt); - } - CompareArchivesByPath(unmodified, scratchPath); - } - - [Fact] - public void Tar_Random_Write_Add() - { - string jpg = Path.Combine(ORIGINAL_FILES_PATH, "jpg", "test.jpg"); - string scratchPath = Path.Combine(SCRATCH_FILES_PATH, "Tar.mod.tar"); - string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Tar.mod.tar"); - string modified = Path.Combine(TEST_ARCHIVES_PATH, "Tar.noEmptyDirs.tar"); - - using (var archive = TarArchive.Open(unmodified)) - { - archive.AddEntry("jpg\\test.jpg", jpg); - archive.SaveTo(scratchPath, CompressionType.None); - } - CompareArchivesByPath(modified, scratchPath); - } - - [Fact] - public void Tar_Random_Write_Remove() - { - string scratchPath = Path.Combine(SCRATCH_FILES_PATH, "Tar.mod.tar"); - string modified = Path.Combine(TEST_ARCHIVES_PATH, "Tar.mod.tar"); - string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Tar.noEmptyDirs.tar"); - - using (var archive = TarArchive.Open(unmodified)) - { - var entry = archive.Entries.Single( - x => x.Key.EndsWith("jpg", StringComparison.OrdinalIgnoreCase) - ); - archive.RemoveEntry(entry); - archive.SaveTo(scratchPath, CompressionType.None); - } - CompareArchivesByPath(modified, scratchPath); - } - - [Fact] - public void Tar_Containing_Rar_Archive() - { - string archiveFullPath = Path.Combine(TEST_ARCHIVES_PATH, "Tar.ContainsRar.tar"); - using (Stream stream = File.OpenRead(archiveFullPath)) - using (IArchive archive = ArchiveFactory.Open(stream)) - { - Assert.True(archive.Type == ArchiveType.Tar); - } - } - - [Fact] - public void Tar_Empty_Archive() - { - string archiveFullPath = Path.Combine(TEST_ARCHIVES_PATH, "Tar.Empty.tar"); - using (Stream stream = File.OpenRead(archiveFullPath)) - using (IArchive archive = ArchiveFactory.Open(stream)) - { - Assert.True(archive.Type == ArchiveType.Tar); - } - } - - [Theory] - [InlineData(10)] - [InlineData(128)] - public void Tar_Japanese_Name(int length) - { - using (var mstm = new MemoryStream()) - { - var enc = new ArchiveEncoding() { Default = Encoding.UTF8 }; - var twopt = new TarWriterOptions(CompressionType.None, true); - twopt.ArchiveEncoding = enc; - var fname = new string((char)0x3042, length); - using (var tw = new TarWriter(mstm, twopt)) - using (var input = new MemoryStream(new byte[32])) - { - tw.Write(fname, input, null); - } - using (var inputMemory = new MemoryStream(mstm.ToArray())) - { - var tropt = new ReaderOptions() { ArchiveEncoding = enc }; - using (var tr = TarReader.Open(inputMemory, tropt)) - { - while (tr.MoveToNextEntry()) - { - Assert.Equal(fname, tr.Entry.Key); - } - } - } - } - } - - [Fact] - public void Tar_Read_One_At_A_Time() - { - var archiveEncoding = new ArchiveEncoding { Default = Encoding.UTF8, }; - var tarWriterOptions = new TarWriterOptions(CompressionType.None, true) - { - ArchiveEncoding = archiveEncoding, - }; - var testBytes = Encoding.UTF8.GetBytes("This is a test."); - - using (var memoryStream = new MemoryStream()) - { - using (var tarWriter = new TarWriter(memoryStream, tarWriterOptions)) - using (var testFileStream = new MemoryStream(testBytes)) - { - tarWriter.Write("test1.txt", testFileStream); - testFileStream.Position = 0; - tarWriter.Write("test2.txt", testFileStream); - } - - memoryStream.Position = 0; - - var numberOfEntries = 0; - - using (var archiveFactory = TarArchive.Open(memoryStream)) - { - foreach (var entry in archiveFactory.Entries) - { - ++numberOfEntries; - - using (var tarEntryStream = entry.OpenEntryStream()) - using (var testFileStream = new MemoryStream()) - { - tarEntryStream.CopyTo(testFileStream); - Assert.Equal(testBytes.Length, testFileStream.Length); - } - } - } - - Assert.Equal(2, numberOfEntries); } } } + + [Fact] + public void Tar_NonUstarArchiveWithLongNameDoesNotSkipEntriesAfterTheLongOne() + { + string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "very long filename.tar"); + using (var archive = TarArchive.Open(unmodified)) + { + Assert.Equal(5, archive.Entries.Count); + Assert.Contains("very long filename/", archive.Entries.Select(entry => entry.Key)); + Assert.Contains( + "very long filename/very long filename very long filename very long filename very long filename very long filename very long filename very long filename very long filename very long filename very long filename.jpg", + archive.Entries.Select(entry => entry.Key) + ); + Assert.Contains("z_file 1.txt", archive.Entries.Select(entry => entry.Key)); + Assert.Contains("z_file 2.txt", archive.Entries.Select(entry => entry.Key)); + Assert.Contains("z_file 3.txt", archive.Entries.Select(entry => entry.Key)); + } + } + + [Fact] + public void Tar_VeryLongFilepathReadback() + { + string archive = "Tar_VeryLongFilepathReadback.tar"; + + // create a very long filename + string longFilename = ""; + for (int i = 0; i < 600; i = longFilename.Length) + { + longFilename += i.ToString("D10") + "-"; + } + + longFilename += ".txt"; + + // Step 1: create a tar file containing a file with a long name + using (Stream stream = File.OpenWrite(Path.Combine(SCRATCH2_FILES_PATH, archive))) + using (var writer = WriterFactory.Open(stream, ArchiveType.Tar, CompressionType.None)) + using (Stream inputStream = new MemoryStream()) + { + StreamWriter sw = new StreamWriter(inputStream); + sw.Write("dummy filecontent"); + sw.Flush(); + + inputStream.Position = 0; + writer.Write(longFilename, inputStream, null); + } + + // Step 2: check if the written tar file can be read correctly + string unmodified = Path.Combine(SCRATCH2_FILES_PATH, archive); + using (var archive2 = TarArchive.Open(unmodified)) + { + Assert.Equal(1, archive2.Entries.Count); + Assert.Contains(longFilename, archive2.Entries.Select(entry => entry.Key)); + + foreach (var entry in archive2.Entries) + { + Assert.Equal( + "dummy filecontent", + new StreamReader(entry.OpenEntryStream()).ReadLine() + ); + } + } + } + + [Fact] + public void Tar_UstarArchivePathReadLongName() + { + string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "ustar with long names.tar"); + using (var archive = TarArchive.Open(unmodified)) + { + Assert.Equal(6, archive.Entries.Count); + Assert.Contains("Directory/", archive.Entries.Select(entry => entry.Key)); + Assert.Contains( + "Directory/Some file with veeeeeeeeeery loooooooooong name", + archive.Entries.Select(entry => entry.Key) + ); + Assert.Contains( + "Directory/Directory with veeeeeeeeeery loooooooooong name/", + archive.Entries.Select(entry => entry.Key) + ); + Assert.Contains( + "Directory/Directory with veeeeeeeeeery loooooooooong name/Some file with veeeeeeeeeery loooooooooong name", + archive.Entries.Select(entry => entry.Key) + ); + Assert.Contains( + "Directory/Directory with veeeeeeeeeery loooooooooong name/Directory with veeeeeeeeeery loooooooooong name/", + archive.Entries.Select(entry => entry.Key) + ); + Assert.Contains( + "Directory/Directory with veeeeeeeeeery loooooooooong name/Directory with veeeeeeeeeery loooooooooong name/Some file with veeeeeeeeeery loooooooooong name", + archive.Entries.Select(entry => entry.Key) + ); + } + } + + [Fact] + public void Tar_Create_New() + { + string scratchPath = Path.Combine(SCRATCH_FILES_PATH, "Tar.tar"); + string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Tar.noEmptyDirs.tar"); + + // var aropt = new Ar + + using (var archive = TarArchive.Create()) + { + archive.AddAllFromDirectory(ORIGINAL_FILES_PATH); + var twopt = new TarWriterOptions(CompressionType.None, true); + twopt.ArchiveEncoding = new ArchiveEncoding() { Default = Encoding.GetEncoding(866) }; + archive.SaveTo(scratchPath, twopt); + } + CompareArchivesByPath(unmodified, scratchPath); + } + + [Fact] + public void Tar_Random_Write_Add() + { + string jpg = Path.Combine(ORIGINAL_FILES_PATH, "jpg", "test.jpg"); + string scratchPath = Path.Combine(SCRATCH_FILES_PATH, "Tar.mod.tar"); + string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Tar.mod.tar"); + string modified = Path.Combine(TEST_ARCHIVES_PATH, "Tar.noEmptyDirs.tar"); + + using (var archive = TarArchive.Open(unmodified)) + { + archive.AddEntry("jpg\\test.jpg", jpg); + archive.SaveTo(scratchPath, CompressionType.None); + } + CompareArchivesByPath(modified, scratchPath); + } + + [Fact] + public void Tar_Random_Write_Remove() + { + string scratchPath = Path.Combine(SCRATCH_FILES_PATH, "Tar.mod.tar"); + string modified = Path.Combine(TEST_ARCHIVES_PATH, "Tar.mod.tar"); + string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Tar.noEmptyDirs.tar"); + + using (var archive = TarArchive.Open(unmodified)) + { + var entry = archive.Entries.Single( + x => x.Key.EndsWith("jpg", StringComparison.OrdinalIgnoreCase) + ); + archive.RemoveEntry(entry); + archive.SaveTo(scratchPath, CompressionType.None); + } + CompareArchivesByPath(modified, scratchPath); + } + + [Fact] + public void Tar_Containing_Rar_Archive() + { + string archiveFullPath = Path.Combine(TEST_ARCHIVES_PATH, "Tar.ContainsRar.tar"); + using (Stream stream = File.OpenRead(archiveFullPath)) + using (IArchive archive = ArchiveFactory.Open(stream)) + { + Assert.True(archive.Type == ArchiveType.Tar); + } + } + + [Fact] + public void Tar_Empty_Archive() + { + string archiveFullPath = Path.Combine(TEST_ARCHIVES_PATH, "Tar.Empty.tar"); + using (Stream stream = File.OpenRead(archiveFullPath)) + using (IArchive archive = ArchiveFactory.Open(stream)) + { + Assert.True(archive.Type == ArchiveType.Tar); + } + } + + [Theory] + [InlineData(10)] + [InlineData(128)] + public void Tar_Japanese_Name(int length) + { + using (var mstm = new MemoryStream()) + { + var enc = new ArchiveEncoding() { Default = Encoding.UTF8 }; + var twopt = new TarWriterOptions(CompressionType.None, true); + twopt.ArchiveEncoding = enc; + var fname = new string((char)0x3042, length); + using (var tw = new TarWriter(mstm, twopt)) + using (var input = new MemoryStream(new byte[32])) + { + tw.Write(fname, input, null); + } + using (var inputMemory = new MemoryStream(mstm.ToArray())) + { + var tropt = new ReaderOptions() { ArchiveEncoding = enc }; + using (var tr = TarReader.Open(inputMemory, tropt)) + { + while (tr.MoveToNextEntry()) + { + Assert.Equal(fname, tr.Entry.Key); + } + } + } + } + } + + [Fact] + public void Tar_Read_One_At_A_Time() + { + var archiveEncoding = new ArchiveEncoding { Default = Encoding.UTF8, }; + var tarWriterOptions = new TarWriterOptions(CompressionType.None, true) + { + ArchiveEncoding = archiveEncoding, + }; + var testBytes = Encoding.UTF8.GetBytes("This is a test."); + + using (var memoryStream = new MemoryStream()) + { + using (var tarWriter = new TarWriter(memoryStream, tarWriterOptions)) + using (var testFileStream = new MemoryStream(testBytes)) + { + tarWriter.Write("test1.txt", testFileStream); + testFileStream.Position = 0; + tarWriter.Write("test2.txt", testFileStream); + } + + memoryStream.Position = 0; + + var numberOfEntries = 0; + + using (var archiveFactory = TarArchive.Open(memoryStream)) + { + foreach (var entry in archiveFactory.Entries) + { + ++numberOfEntries; + + using (var tarEntryStream = entry.OpenEntryStream()) + using (var testFileStream = new MemoryStream()) + { + tarEntryStream.CopyTo(testFileStream); + Assert.Equal(testBytes.Length, testFileStream.Length); + } + } + } + + Assert.Equal(2, numberOfEntries); + } + } } diff --git a/tests/SharpCompress.Test/Tar/TarReaderTests.cs b/tests/SharpCompress.Test/Tar/TarReaderTests.cs index 52ad2b33..a92a3c0a 100644 --- a/tests/SharpCompress.Test/Tar/TarReaderTests.cs +++ b/tests/SharpCompress.Test/Tar/TarReaderTests.cs @@ -7,271 +7,248 @@ using SharpCompress.Readers.Tar; using SharpCompress.Test.Mocks; using Xunit; -namespace SharpCompress.Test.Tar +namespace SharpCompress.Test.Tar; + +public class TarReaderTests : ReaderTests { - public class TarReaderTests : ReaderTests + public TarReaderTests() => UseExtensionInsteadOfNameToVerify = true; + + [Fact] + public void Tar_Reader() => Read("Tar.tar", CompressionType.None); + + [Fact] + public void Tar_Skip() { - public TarReaderTests() - { - UseExtensionInsteadOfNameToVerify = true; - } - - [Fact] - public void Tar_Reader() - { - Read("Tar.tar", CompressionType.None); - } - - [Fact] - public void Tar_Skip() - { - using ( - Stream stream = new ForwardOnlyStream( - File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar")) - ) + using ( + Stream stream = new ForwardOnlyStream( + File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar")) ) - using (IReader reader = ReaderFactory.Open(stream)) + ) + using (IReader reader = ReaderFactory.Open(stream)) + { + int x = 0; + while (reader.MoveToNextEntry()) { - int x = 0; - while (reader.MoveToNextEntry()) + if (!reader.Entry.IsDirectory) { - if (!reader.Entry.IsDirectory) + x++; + if (x % 2 == 0) { - x++; - if (x % 2 == 0) + reader.WriteEntryToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } + ); + } + } + } + } + } + + [Fact] + public void Tar_BZip2_Reader() => Read("Tar.tar.bz2", CompressionType.BZip2); + + [Fact] + public void Tar_GZip_Reader() => Read("Tar.tar.gz", CompressionType.GZip); + + [Fact] + public void Tar_LZip_Reader() => Read("Tar.tar.lz", CompressionType.LZip); + + [Fact] + public void Tar_Xz_Reader() => Read("Tar.tar.xz", CompressionType.Xz); + + [Fact] + public void Tar_BZip2_Entry_Stream() + { + using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.bz2"))) + using (var reader = TarReader.Open(stream)) + { + while (reader.MoveToNextEntry()) + { + if (!reader.Entry.IsDirectory) + { + Assert.Equal(CompressionType.BZip2, reader.Entry.CompressionType); + using (var entryStream = reader.OpenEntryStream()) + { + string file = Path.GetFileName(reader.Entry.Key); + string folder = + Path.GetDirectoryName(reader.Entry.Key) + ?? throw new ArgumentNullException(); + string destdir = Path.Combine(SCRATCH_FILES_PATH, folder); + if (!Directory.Exists(destdir)) { - reader.WriteEntryToDirectory( - SCRATCH_FILES_PATH, - new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } - ); + Directory.CreateDirectory(destdir); + } + string destinationFileName = Path.Combine(destdir, file); + + using (FileStream fs = File.OpenWrite(destinationFileName)) + { + entryStream.TransferTo(fs); } } } } } + VerifyFiles(); + } - [Fact] - public void Tar_BZip2_Reader() - { - Read("Tar.tar.bz2", CompressionType.BZip2); - } + [Fact] + public void Tar_LongNamesWithLongNameExtension() + { + var filePaths = new List(); - [Fact] - public void Tar_GZip_Reader() - { - Read("Tar.tar.gz", CompressionType.GZip); - } - - [Fact] - public void Tar_LZip_Reader() - { - Read("Tar.tar.lz", CompressionType.LZip); - } - - [Fact] - public void Tar_Xz_Reader() - { - Read("Tar.tar.xz", CompressionType.Xz); - } - - [Fact] - public void Tar_BZip2_Entry_Stream() - { - using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.bz2"))) - using (var reader = TarReader.Open(stream)) - { - while (reader.MoveToNextEntry()) - { - if (!reader.Entry.IsDirectory) - { - Assert.Equal(CompressionType.BZip2, reader.Entry.CompressionType); - using (var entryStream = reader.OpenEntryStream()) - { - string file = Path.GetFileName(reader.Entry.Key); - string folder = - Path.GetDirectoryName(reader.Entry.Key) - ?? throw new ArgumentNullException(); - string destdir = Path.Combine(SCRATCH_FILES_PATH, folder); - if (!Directory.Exists(destdir)) - { - Directory.CreateDirectory(destdir); - } - string destinationFileName = Path.Combine(destdir, file); - - using (FileStream fs = File.OpenWrite(destinationFileName)) - { - entryStream.TransferTo(fs); - } - } - } - } - } - VerifyFiles(); - } - - [Fact] - public void Tar_LongNamesWithLongNameExtension() - { - var filePaths = new List(); - - using ( - Stream stream = File.OpenRead( - Path.Combine(TEST_ARCHIVES_PATH, "Tar.LongPathsWithLongNameExtension.tar") - ) + using ( + Stream stream = File.OpenRead( + Path.Combine(TEST_ARCHIVES_PATH, "Tar.LongPathsWithLongNameExtension.tar") ) - using (var reader = TarReader.Open(stream)) + ) + using (var reader = TarReader.Open(stream)) + { + while (reader.MoveToNextEntry()) { - while (reader.MoveToNextEntry()) + if (!reader.Entry.IsDirectory) { - if (!reader.Entry.IsDirectory) + filePaths.Add(reader.Entry.Key); + } + } + } + + Assert.Equal(3, filePaths.Count); + Assert.Contains("a.txt", filePaths); + Assert.Contains( + "wp-content/plugins/gravityformsextend/lib/Aws/Symfony/Component/ClassLoader/Tests/Fixtures/Apc/beta/Apc/ApcPrefixCollision/A/B/Bar.php", + filePaths + ); + Assert.Contains( + "wp-content/plugins/gravityformsextend/lib/Aws/Symfony/Component/ClassLoader/Tests/Fixtures/Apc/beta/Apc/ApcPrefixCollision/A/B/Foo.php", + filePaths + ); + } + + [Fact] + public void Tar_BZip2_Skip_Entry_Stream() + { + using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.bz2"))) + using (var reader = TarReader.Open(stream)) + { + List names = new List(); + while (reader.MoveToNextEntry()) + { + if (!reader.Entry.IsDirectory) + { + Assert.Equal(CompressionType.BZip2, reader.Entry.CompressionType); + using (var entryStream = reader.OpenEntryStream()) { - filePaths.Add(reader.Entry.Key); + entryStream.SkipEntry(); + names.Add(reader.Entry.Key); } } } - - Assert.Equal(3, filePaths.Count); - Assert.Contains("a.txt", filePaths); - Assert.Contains( - "wp-content/plugins/gravityformsextend/lib/Aws/Symfony/Component/ClassLoader/Tests/Fixtures/Apc/beta/Apc/ApcPrefixCollision/A/B/Bar.php", - filePaths - ); - Assert.Contains( - "wp-content/plugins/gravityformsextend/lib/Aws/Symfony/Component/ClassLoader/Tests/Fixtures/Apc/beta/Apc/ApcPrefixCollision/A/B/Foo.php", - filePaths - ); + Assert.Equal(3, names.Count); } + } - [Fact] - public void Tar_BZip2_Skip_Entry_Stream() + [Fact] + public void Tar_Containing_Rar_Reader() + { + string archiveFullPath = Path.Combine(TEST_ARCHIVES_PATH, "Tar.ContainsRar.tar"); + using (Stream stream = File.OpenRead(archiveFullPath)) + using (IReader reader = ReaderFactory.Open(stream)) { - using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.bz2"))) - using (var reader = TarReader.Open(stream)) + Assert.True(reader.ArchiveType == ArchiveType.Tar); + } + } + + [Fact] + public void Tar_With_TarGz_With_Flushed_EntryStream() + { + string archiveFullPath = Path.Combine(TEST_ARCHIVES_PATH, "Tar.ContainsTarGz.tar"); + using (Stream stream = File.OpenRead(archiveFullPath)) + using (IReader reader = ReaderFactory.Open(stream)) + { + Assert.True(reader.MoveToNextEntry()); + Assert.Equal("inner.tar.gz", reader.Entry.Key); + + using (var entryStream = reader.OpenEntryStream()) { - List names = new List(); - while (reader.MoveToNextEntry()) + using (FlushOnDisposeStream flushingStream = new FlushOnDisposeStream(entryStream)) { - if (!reader.Entry.IsDirectory) + // Extract inner.tar.gz + using (var innerReader = ReaderFactory.Open(flushingStream)) { - Assert.Equal(CompressionType.BZip2, reader.Entry.CompressionType); - using (var entryStream = reader.OpenEntryStream()) - { - entryStream.SkipEntry(); - names.Add(reader.Entry.Key); - } - } - } - Assert.Equal(3, names.Count); - } - } - - [Fact] - public void Tar_Containing_Rar_Reader() - { - string archiveFullPath = Path.Combine(TEST_ARCHIVES_PATH, "Tar.ContainsRar.tar"); - using (Stream stream = File.OpenRead(archiveFullPath)) - using (IReader reader = ReaderFactory.Open(stream)) - { - Assert.True(reader.ArchiveType == ArchiveType.Tar); - } - } - - [Fact] - public void Tar_With_TarGz_With_Flushed_EntryStream() - { - string archiveFullPath = Path.Combine(TEST_ARCHIVES_PATH, "Tar.ContainsTarGz.tar"); - using (Stream stream = File.OpenRead(archiveFullPath)) - using (IReader reader = ReaderFactory.Open(stream)) - { - Assert.True(reader.MoveToNextEntry()); - Assert.Equal("inner.tar.gz", reader.Entry.Key); - - using (var entryStream = reader.OpenEntryStream()) - { - using ( - FlushOnDisposeStream flushingStream = new FlushOnDisposeStream(entryStream) - ) - { - // Extract inner.tar.gz - using (var innerReader = ReaderFactory.Open(flushingStream)) - { - Assert.True(innerReader.MoveToNextEntry()); - Assert.Equal("test", innerReader.Entry.Key); - } + Assert.True(innerReader.MoveToNextEntry()); + Assert.Equal("test", innerReader.Entry.Key); } } } } + } #if !NETFRAMEWORK - [Fact] - public void Tar_GZip_With_Symlink_Entries() + [Fact] + public void Tar_GZip_With_Symlink_Entries() + { + var isWindows = System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform( + System.Runtime.InteropServices.OSPlatform.Windows + ); + using ( + Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "TarWithSymlink.tar.gz")) + ) + using (var reader = TarReader.Open(stream)) { - var isWindows = System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform( - System.Runtime.InteropServices.OSPlatform.Windows - ); - using ( - Stream stream = File.OpenRead( - Path.Combine(TEST_ARCHIVES_PATH, "TarWithSymlink.tar.gz") - ) - ) - using (var reader = TarReader.Open(stream)) + List names = new List(); + while (reader.MoveToNextEntry()) { - List names = new List(); - while (reader.MoveToNextEntry()) + if (reader.Entry.IsDirectory) { - if (reader.Entry.IsDirectory) + continue; + } + reader.WriteEntryToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() { - continue; - } - reader.WriteEntryToDirectory( - SCRATCH_FILES_PATH, - new ExtractionOptions() + ExtractFullPath = true, + Overwrite = true, + WriteSymbolicLink = (sourcePath, targetPath) => { - ExtractFullPath = true, - Overwrite = true, - WriteSymbolicLink = (sourcePath, targetPath) => + if (!isWindows) { - if (!isWindows) + var link = new Mono.Unix.UnixSymbolicLinkInfo(sourcePath); + if (File.Exists(sourcePath)) { - var link = new Mono.Unix.UnixSymbolicLinkInfo(sourcePath); - if (File.Exists(sourcePath)) - { - link.Delete(); // equivalent to ln -s -f - } - link.CreateSymbolicLinkTo(targetPath); + link.Delete(); // equivalent to ln -s -f } + link.CreateSymbolicLinkTo(targetPath); } } - ); - if (!isWindows) + } + ); + if (!isWindows) + { + if (reader.Entry.LinkTarget != null) { - if (reader.Entry.LinkTarget != null) + var path = System.IO.Path.Combine(SCRATCH_FILES_PATH, reader.Entry.Key); + var link = new Mono.Unix.UnixSymbolicLinkInfo(path); + if (link.HasContents) { - var path = System.IO.Path.Combine(SCRATCH_FILES_PATH, reader.Entry.Key); - var link = new Mono.Unix.UnixSymbolicLinkInfo(path); - if (link.HasContents) - { - // need to convert the link to an absolute path for comparison - var target = reader.Entry.LinkTarget; - var realTarget = System.IO.Path.GetFullPath( - System.IO.Path.Combine( - $"{System.IO.Path.GetDirectoryName(path)}", - target - ) - ); + // need to convert the link to an absolute path for comparison + var target = reader.Entry.LinkTarget; + var realTarget = System.IO.Path.GetFullPath( + System.IO.Path.Combine( + $"{System.IO.Path.GetDirectoryName(path)}", + target + ) + ); - Assert.Equal(realTarget, link.GetContents().ToString()); - } - else - { - Assert.True(false, "Symlink has no target"); - } + Assert.Equal(realTarget, link.GetContents().ToString()); + } + else + { + Assert.True(false, "Symlink has no target"); } } } } } -#endif } +#endif } diff --git a/tests/SharpCompress.Test/Tar/TarWriterTests.cs b/tests/SharpCompress.Test/Tar/TarWriterTests.cs index 98ed2e19..4be9f9d8 100644 --- a/tests/SharpCompress.Test/Tar/TarWriterTests.cs +++ b/tests/SharpCompress.Test/Tar/TarWriterTests.cs @@ -1,4 +1,4 @@ -using System.IO; +using System.IO; using System.Text; using SharpCompress.Common; using SharpCompress.Writers.Tar; @@ -8,51 +8,40 @@ namespace SharpCompress.Test.Tar; public class TarWriterTests : WriterTests { - public TarWriterTests() : base(ArchiveType.Tar) - { - UseExtensionInsteadOfNameToVerify = true; - } + public TarWriterTests() : base(ArchiveType.Tar) => UseExtensionInsteadOfNameToVerify = true; [Fact] - public void Tar_Writer() - { + public void Tar_Writer() => Write( CompressionType.None, "Tar.noEmptyDirs.tar", "Tar.noEmptyDirs.tar", Encoding.GetEncoding(866) ); - } [Fact] - public void Tar_BZip2_Writer() - { + public void Tar_BZip2_Writer() => Write( CompressionType.BZip2, "Tar.noEmptyDirs.tar.bz2", "Tar.noEmptyDirs.tar.bz2", Encoding.GetEncoding(866) ); - } [Fact] - public void Tar_LZip_Writer() - { + public void Tar_LZip_Writer() => Write( CompressionType.LZip, "Tar.noEmptyDirs.tar.lz", "Tar.noEmptyDirs.tar.lz", Encoding.GetEncoding(866) ); - } [Fact] - public void Tar_Rar_Write() - { + public void Tar_Rar_Write() => Assert.Throws( () => Write(CompressionType.Rar, "Zip.ppmd.noEmptyDirs.zip", "Zip.ppmd.noEmptyDirs.zip") ); - } [Theory] [InlineData(true)] diff --git a/tests/SharpCompress.Test/TestBase.cs b/tests/SharpCompress.Test/TestBase.cs index 51900b33..ddfd0096 100644 --- a/tests/SharpCompress.Test/TestBase.cs +++ b/tests/SharpCompress.Test/TestBase.cs @@ -43,10 +43,7 @@ public class TestBase : IDisposable Directory.CreateDirectory(SCRATCH2_FILES_PATH); } - public void Dispose() - { - Directory.Delete(SCRATCH_BASE_PATH, true); - } + public void Dispose() => Directory.Delete(SCRATCH_BASE_PATH, true); public void VerifyFiles() { diff --git a/tests/SharpCompress.Test/WriterTests.cs b/tests/SharpCompress.Test/WriterTests.cs index db2c4911..64ed6d2c 100644 --- a/tests/SharpCompress.Test/WriterTests.cs +++ b/tests/SharpCompress.Test/WriterTests.cs @@ -11,10 +11,7 @@ public class WriterTests : TestBase { private readonly ArchiveType type; - protected WriterTests(ArchiveType type) - { - this.type = type; - } + protected WriterTests(ArchiveType type) => this.type = type; protected void Write( CompressionType compressionType, diff --git a/tests/SharpCompress.Test/Xz/Crc32Tests.cs b/tests/SharpCompress.Test/Xz/Crc32Tests.cs index 7476b748..52b71078 100644 --- a/tests/SharpCompress.Test/Xz/Crc32Tests.cs +++ b/tests/SharpCompress.Test/Xz/Crc32Tests.cs @@ -1,4 +1,3 @@ -using System; using System.Text; using SharpCompress.Compressors.Xz; using Xunit; diff --git a/tests/SharpCompress.Test/Xz/Crc64Tests.cs b/tests/SharpCompress.Test/Xz/Crc64Tests.cs index 6b9cb31e..79912e48 100644 --- a/tests/SharpCompress.Test/Xz/Crc64Tests.cs +++ b/tests/SharpCompress.Test/Xz/Crc64Tests.cs @@ -1,4 +1,3 @@ -using System; using System.Text; using SharpCompress.Compressors.Xz; using Xunit; diff --git a/tests/SharpCompress.Test/Xz/Filters/Lzma2Tests.cs b/tests/SharpCompress.Test/Xz/Filters/Lzma2Tests.cs index fd6caf61..83eed21c 100644 --- a/tests/SharpCompress.Test/Xz/Filters/Lzma2Tests.cs +++ b/tests/SharpCompress.Test/Xz/Filters/Lzma2Tests.cs @@ -3,70 +3,63 @@ using Xunit; using System.IO; using SharpCompress.Compressors.Xz.Filters; -namespace SharpCompress.Test.Xz.Filters +namespace SharpCompress.Test.Xz.Filters; + +public class Lzma2Tests : XZTestsBase { - public class Lzma2Tests : XZTestsBase + private readonly Lzma2Filter filter; + + public Lzma2Tests() => filter = new Lzma2Filter(); + + [Fact] + public void IsOnlyAllowedLast() { - private readonly Lzma2Filter filter; + Assert.True(filter.AllowAsLast); + Assert.False(filter.AllowAsNonLast); + } - public Lzma2Tests() - { - filter = new Lzma2Filter(); - } + [Fact] + public void ChangesStreamSize() => Assert.True(filter.ChangesDataSize); - [Fact] - public void IsOnlyAllowedLast() - { - Assert.True(filter.AllowAsLast); - Assert.False(filter.AllowAsNonLast); - } + [Theory] + [InlineData(0, (uint)4 * 1024)] + [InlineData(1, (uint)6 * 1024)] + [InlineData(2, (uint)8 * 1024)] + [InlineData(3, (uint)12 * 1024)] + [InlineData(38, (uint)2 * 1024 * 1024 * 1024)] + [InlineData(39, (uint)3 * 1024 * 1024 * 1024)] + [InlineData(40, (uint)(1024 * 1024 * 1024 - 1) * 4 + 3)] + public void CalculatesDictionarySize(byte inByte, uint dicSize) + { + filter.Init(new[] { inByte }); + Assert.Equal(filter.DictionarySize, dicSize); + } - [Fact] - public void ChangesStreamSize() + [Fact] + public void CalculatesDictionarySizeError() + { + uint temp; + filter.Init(new byte[] { 41 }); + var ex = Assert.Throws(() => { - Assert.True(filter.ChangesDataSize); - } + temp = filter.DictionarySize; + }); + Assert.Equal("Dictionary size greater than UInt32.Max", ex.Message); + } - [Theory] - [InlineData(0, (uint)4 * 1024)] - [InlineData(1, (uint)6 * 1024)] - [InlineData(2, (uint)8 * 1024)] - [InlineData(3, (uint)12 * 1024)] - [InlineData(38, (uint)2 * 1024 * 1024 * 1024)] - [InlineData(39, (uint)3 * 1024 * 1024 * 1024)] - [InlineData(40, (uint)(1024 * 1024 * 1024 - 1) * 4 + 3)] - public void CalculatesDictionarySize(byte inByte, uint dicSize) - { - filter.Init(new[] { inByte }); - Assert.Equal(filter.DictionarySize, dicSize); - } + [Theory] + [InlineData(new byte[] { })] + [InlineData(new byte[] { 0, 0 })] + public void OnlyAcceptsOneByte(byte[] bytes) + { + var ex = Assert.Throws(() => filter.Init(bytes)); + Assert.Equal("LZMA properties unexpected length", ex.Message); + } - [Fact] - public void CalculatesDictionarySizeError() - { - uint temp; - filter.Init(new byte[] { 41 }); - var ex = Assert.Throws(() => - { - temp = filter.DictionarySize; - }); - Assert.Equal("Dictionary size greater than UInt32.Max", ex.Message); - } - - [Theory] - [InlineData(new byte[] { })] - [InlineData(new byte[] { 0, 0 })] - public void OnlyAcceptsOneByte(byte[] bytes) - { - var ex = Assert.Throws(() => filter.Init(bytes)); - Assert.Equal("LZMA properties unexpected length", ex.Message); - } - - [Fact] - public void ReservedBytesThrow() - { - var ex = Assert.Throws(() => filter.Init(new byte[] { 0xC0 })); - Assert.Equal("Reserved bits used in LZMA properties", ex.Message); - } + [Fact] + public void ReservedBytesThrow() + { + var ex = Assert.Throws(() => filter.Init(new byte[] { 0xC0 })); + Assert.Equal("Reserved bits used in LZMA properties", ex.Message); } } diff --git a/tests/SharpCompress.Test/Xz/XZBlockTests.cs b/tests/SharpCompress.Test/Xz/XZBlockTests.cs index 4218fa36..87e68d93 100644 --- a/tests/SharpCompress.Test/Xz/XZBlockTests.cs +++ b/tests/SharpCompress.Test/Xz/XZBlockTests.cs @@ -7,15 +7,9 @@ namespace SharpCompress.Test.Xz; public class XZBlockTests : XZTestsBase { - protected override void Rewind(Stream stream) - { - stream.Position = 12; - } + protected override void Rewind(Stream stream) => stream.Position = 12; - protected override void RewindIndexed(Stream stream) - { - stream.Position = 12; - } + protected override void RewindIndexed(Stream stream) => stream.Position = 12; private byte[] ReadBytes(XZBlock block, int bytesToRead) { diff --git a/tests/SharpCompress.Test/Xz/XZHeaderTests.cs b/tests/SharpCompress.Test/Xz/XZHeaderTests.cs index db1f876d..3fa9dc86 100644 --- a/tests/SharpCompress.Test/Xz/XZHeaderTests.cs +++ b/tests/SharpCompress.Test/Xz/XZHeaderTests.cs @@ -2,87 +2,86 @@ using SharpCompress.Compressors.Xz; using System.IO; using Xunit; -namespace SharpCompress.Test.Xz +namespace SharpCompress.Test.Xz; + +public class XZHeaderTests : XZTestsBase { - public class XZHeaderTests : XZTestsBase + [Fact] + public void ChecksMagicNumber() { - [Fact] - public void ChecksMagicNumber() + var bytes = (byte[])Compressed.Clone(); + bytes[3]++; + using (Stream badMagicNumberStream = new MemoryStream(bytes)) { - var bytes = (byte[])Compressed.Clone(); - bytes[3]++; - using (Stream badMagicNumberStream = new MemoryStream(bytes)) - { - BinaryReader br = new BinaryReader(badMagicNumberStream); - var header = new XZHeader(br); - var ex = Assert.Throws(() => - { - header.Process(); - }); - Assert.Equal("Invalid XZ Stream", ex.Message); - } - } - - [Fact] - public void CorruptHeaderThrows() - { - var bytes = (byte[])Compressed.Clone(); - bytes[8]++; - using (Stream badCrcStream = new MemoryStream(bytes)) - { - BinaryReader br = new BinaryReader(badCrcStream); - var header = new XZHeader(br); - var ex = Assert.Throws(() => - { - header.Process(); - }); - Assert.Equal("Stream header corrupt", ex.Message); - } - } - - [Fact] - public void BadVersionIfCrcOkButStreamFlagUnknown() - { - var bytes = (byte[])Compressed.Clone(); - byte[] streamFlags = { 0x00, 0xF4 }; - byte[] crc = Crc32.Compute(streamFlags).ToLittleEndianBytes(); - streamFlags.CopyTo(bytes, 6); - crc.CopyTo(bytes, 8); - using (Stream badFlagStream = new MemoryStream(bytes)) - { - BinaryReader br = new BinaryReader(badFlagStream); - var header = new XZHeader(br); - var ex = Assert.Throws(() => - { - header.Process(); - }); - Assert.Equal("Unknown XZ Stream Version", ex.Message); - } - } - - [Fact] - public void ProcessesBlockCheckType() - { - BinaryReader br = new BinaryReader(CompressedStream); + BinaryReader br = new BinaryReader(badMagicNumberStream); var header = new XZHeader(br); - header.Process(); - Assert.Equal(CheckType.CRC64, header.BlockCheckType); - } - - [Fact] - public void CanCalculateBlockCheckSize() - { - BinaryReader br = new BinaryReader(CompressedStream); - var header = new XZHeader(br); - header.Process(); - Assert.Equal(8, header.BlockCheckSize); - } - - [Fact] - public void ProcessesStreamHeaderFromFactory() - { - var header = XZHeader.FromStream(CompressedStream); - Assert.Equal(CheckType.CRC64, header.BlockCheckType); + var ex = Assert.Throws(() => + { + header.Process(); + }); + Assert.Equal("Invalid XZ Stream", ex.Message); } } + + [Fact] + public void CorruptHeaderThrows() + { + var bytes = (byte[])Compressed.Clone(); + bytes[8]++; + using (Stream badCrcStream = new MemoryStream(bytes)) + { + BinaryReader br = new BinaryReader(badCrcStream); + var header = new XZHeader(br); + var ex = Assert.Throws(() => + { + header.Process(); + }); + Assert.Equal("Stream header corrupt", ex.Message); + } + } + + [Fact] + public void BadVersionIfCrcOkButStreamFlagUnknown() + { + var bytes = (byte[])Compressed.Clone(); + byte[] streamFlags = { 0x00, 0xF4 }; + byte[] crc = Crc32.Compute(streamFlags).ToLittleEndianBytes(); + streamFlags.CopyTo(bytes, 6); + crc.CopyTo(bytes, 8); + using (Stream badFlagStream = new MemoryStream(bytes)) + { + BinaryReader br = new BinaryReader(badFlagStream); + var header = new XZHeader(br); + var ex = Assert.Throws(() => + { + header.Process(); + }); + Assert.Equal("Unknown XZ Stream Version", ex.Message); + } + } + + [Fact] + public void ProcessesBlockCheckType() + { + BinaryReader br = new BinaryReader(CompressedStream); + var header = new XZHeader(br); + header.Process(); + Assert.Equal(CheckType.CRC64, header.BlockCheckType); + } + + [Fact] + public void CanCalculateBlockCheckSize() + { + BinaryReader br = new BinaryReader(CompressedStream); + var header = new XZHeader(br); + header.Process(); + Assert.Equal(8, header.BlockCheckSize); + } + + [Fact] + public void ProcessesStreamHeaderFromFactory() + { + var header = XZHeader.FromStream(CompressedStream); + Assert.Equal(CheckType.CRC64, header.BlockCheckType); + } } diff --git a/tests/SharpCompress.Test/Xz/XZIndexTests.cs b/tests/SharpCompress.Test/Xz/XZIndexTests.cs index ecc249e0..9c9d15bf 100644 --- a/tests/SharpCompress.Test/Xz/XZIndexTests.cs +++ b/tests/SharpCompress.Test/Xz/XZIndexTests.cs @@ -1,114 +1,104 @@ -using SharpCompress.Compressors.Xz; +using SharpCompress.Compressors.Xz; using System.IO; using Xunit; -namespace SharpCompress.Test.Xz +namespace SharpCompress.Test.Xz; + +public class XZIndexTests : XZTestsBase { - public class XZIndexTests : XZTestsBase + protected override void RewindEmpty(Stream stream) => stream.Position = 12; + + protected override void Rewind(Stream stream) => stream.Position = 356; + + protected override void RewindIndexed(Stream stream) => stream.Position = 612; + + [Fact] + public void RecordsStreamStartOnInit() { - protected override void RewindEmpty(Stream stream) + using (Stream badStream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5 })) { - stream.Position = 12; - } - - protected override void Rewind(Stream stream) - { - stream.Position = 356; - } - - protected override void RewindIndexed(Stream stream) - { - stream.Position = 612; - } - - [Fact] - public void RecordsStreamStartOnInit() - { - using (Stream badStream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5 })) - { - BinaryReader br = new BinaryReader(badStream); - var index = new XZIndex(br, false); - Assert.Equal(0, index.StreamStartPosition); - } - } - - [Fact] - public void ThrowsIfHasNoIndexMarker() - { - using (Stream badStream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5 })) - { - BinaryReader br = new BinaryReader(badStream); - var index = new XZIndex(br, false); - Assert.Throws(() => index.Process()); - } - } - - [Fact] - public void ReadsNoRecord() - { - BinaryReader br = new BinaryReader(CompressedEmptyStream); + BinaryReader br = new BinaryReader(badStream); var index = new XZIndex(br, false); - index.Process(); - Assert.Equal((ulong)0, index.NumberOfRecords); + Assert.Equal(0, index.StreamStartPosition); } + } - [Fact] - public void ReadsOneRecord() + [Fact] + public void ThrowsIfHasNoIndexMarker() + { + using (Stream badStream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5 })) { - BinaryReader br = new BinaryReader(CompressedStream); + BinaryReader br = new BinaryReader(badStream); var index = new XZIndex(br, false); - index.Process(); - Assert.Equal((ulong)1, index.NumberOfRecords); + Assert.Throws(() => index.Process()); } + } - [Fact] - public void ReadsMultipleRecords() - { - BinaryReader br = new BinaryReader(CompressedIndexedStream); - var index = new XZIndex(br, false); - index.Process(); - Assert.Equal((ulong)2, index.NumberOfRecords); - } + [Fact] + public void ReadsNoRecord() + { + BinaryReader br = new BinaryReader(CompressedEmptyStream); + var index = new XZIndex(br, false); + index.Process(); + Assert.Equal((ulong)0, index.NumberOfRecords); + } - [Fact] - public void ReadsFirstRecord() - { - BinaryReader br = new BinaryReader(CompressedStream); - var index = new XZIndex(br, false); - index.Process(); - Assert.Equal((ulong)OriginalBytes.Length, index.Records[0].UncompressedSize); - } + [Fact] + public void ReadsOneRecord() + { + BinaryReader br = new BinaryReader(CompressedStream); + var index = new XZIndex(br, false); + index.Process(); + Assert.Equal((ulong)1, index.NumberOfRecords); + } - [Fact] - public void SkipsPadding() - { - // Index with 3-byte padding. - using ( - Stream badStream = new MemoryStream( - new byte[] - { - 0x00, - 0x01, - 0x10, - 0x80, - 0x01, - 0x00, - 0x00, - 0x00, - 0xB1, - 0x01, - 0xD9, - 0xC9, - 0xFF - } - ) + [Fact] + public void ReadsMultipleRecords() + { + BinaryReader br = new BinaryReader(CompressedIndexedStream); + var index = new XZIndex(br, false); + index.Process(); + Assert.Equal((ulong)2, index.NumberOfRecords); + } + + [Fact] + public void ReadsFirstRecord() + { + BinaryReader br = new BinaryReader(CompressedStream); + var index = new XZIndex(br, false); + index.Process(); + Assert.Equal((ulong)OriginalBytes.Length, index.Records[0].UncompressedSize); + } + + [Fact] + public void SkipsPadding() + { + // Index with 3-byte padding. + using ( + Stream badStream = new MemoryStream( + new byte[] + { + 0x00, + 0x01, + 0x10, + 0x80, + 0x01, + 0x00, + 0x00, + 0x00, + 0xB1, + 0x01, + 0xD9, + 0xC9, + 0xFF + } ) - { - BinaryReader br = new BinaryReader(badStream); - var index = new XZIndex(br, false); - index.Process(); - Assert.Equal(0L, badStream.Position % 4L); - } + ) + { + BinaryReader br = new BinaryReader(badStream); + var index = new XZIndex(br, false); + index.Process(); + Assert.Equal(0L, badStream.Position % 4L); } } } diff --git a/tests/SharpCompress.Test/Xz/XZStreamTests.cs b/tests/SharpCompress.Test/Xz/XZStreamTests.cs index fea155de..1f50fb40 100644 --- a/tests/SharpCompress.Test/Xz/XZStreamTests.cs +++ b/tests/SharpCompress.Test/Xz/XZStreamTests.cs @@ -1,42 +1,41 @@ -using SharpCompress.Compressors.Xz; +using SharpCompress.Compressors.Xz; using System.IO; using Xunit; -namespace SharpCompress.Test.Xz +namespace SharpCompress.Test.Xz; + +public class XZStreamTests : XZTestsBase { - public class XZStreamTests : XZTestsBase + [Fact] + public void CanReadEmptyStream() { - [Fact] - public void CanReadEmptyStream() + XZStream xz = new XZStream(CompressedEmptyStream); + using (var sr = new StreamReader(xz)) { - XZStream xz = new XZStream(CompressedEmptyStream); - using (var sr = new StreamReader(xz)) - { - string uncompressed = sr.ReadToEnd(); - Assert.Equal(OriginalEmpty, uncompressed); - } + string uncompressed = sr.ReadToEnd(); + Assert.Equal(OriginalEmpty, uncompressed); } + } - [Fact] - public void CanReadStream() + [Fact] + public void CanReadStream() + { + XZStream xz = new XZStream(CompressedStream); + using (var sr = new StreamReader(xz)) { - XZStream xz = new XZStream(CompressedStream); - using (var sr = new StreamReader(xz)) - { - string uncompressed = sr.ReadToEnd(); - Assert.Equal(Original, uncompressed); - } + string uncompressed = sr.ReadToEnd(); + Assert.Equal(Original, uncompressed); } + } - [Fact] - public void CanReadIndexedStream() + [Fact] + public void CanReadIndexedStream() + { + XZStream xz = new XZStream(CompressedIndexedStream); + using (var sr = new StreamReader(xz)) { - XZStream xz = new XZStream(CompressedIndexedStream); - using (var sr = new StreamReader(xz)) - { - string uncompressed = sr.ReadToEnd(); - Assert.Equal(OriginalIndexed, uncompressed); - } + string uncompressed = sr.ReadToEnd(); + Assert.Equal(OriginalIndexed, uncompressed); } } } diff --git a/tests/SharpCompress.Test/Xz/XZTestsBase.cs b/tests/SharpCompress.Test/Xz/XZTestsBase.cs index 2e931820..5a1b5cbb 100644 --- a/tests/SharpCompress.Test/Xz/XZTestsBase.cs +++ b/tests/SharpCompress.Test/Xz/XZTestsBase.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; using System.Text; @@ -20,20 +20,11 @@ public abstract class XZTestsBase : IDisposable CompressedIndexedStream?.Dispose(); } - protected virtual void RewindEmpty(Stream stream) - { - stream.Position = 0; - } + protected virtual void RewindEmpty(Stream stream) => stream.Position = 0; - protected virtual void Rewind(Stream stream) - { - stream.Position = 0; - } + protected virtual void Rewind(Stream stream) => stream.Position = 0; - protected virtual void RewindIndexed(Stream stream) - { - stream.Position = 0; - } + protected virtual void RewindIndexed(Stream stream) => stream.Position = 0; protected Stream CompressedEmptyStream { get; } = new MemoryStream(CompressedEmpty); diff --git a/tests/SharpCompress.Test/Zip/Zip64Tests.cs b/tests/SharpCompress.Test/Zip/Zip64Tests.cs index 039411a7..7e20c3d4 100644 --- a/tests/SharpCompress.Test/Zip/Zip64Tests.cs +++ b/tests/SharpCompress.Test/Zip/Zip64Tests.cs @@ -20,39 +20,29 @@ public class Zip64Tests : WriterTests private const long FOUR_GB_LIMIT = ((long)uint.MaxValue) + 1; [Trait("format", "zip64")] - public void Zip64_Single_Large_File() - { + public void Zip64_Single_Large_File() => // One single file, requires zip64 RunSingleTest(1, FOUR_GB_LIMIT, set_zip64: true, forward_only: false); - } [Trait("format", "zip64")] - public void Zip64_Two_Large_Files() - { + public void Zip64_Two_Large_Files() => // One single file, requires zip64 RunSingleTest(2, FOUR_GB_LIMIT, set_zip64: true, forward_only: false); - } [Trait("format", "zip64")] - public void Zip64_Two_Small_files() - { + public void Zip64_Two_Small_files() => // Multiple files, does not require zip64 RunSingleTest(2, FOUR_GB_LIMIT / 2, set_zip64: false, forward_only: false); - } [Trait("format", "zip64")] - public void Zip64_Two_Small_files_stream() - { + public void Zip64_Two_Small_files_stream() => // Multiple files, does not require zip64, and works with streams RunSingleTest(2, FOUR_GB_LIMIT / 2, set_zip64: false, forward_only: true); - } [Trait("format", "zip64")] - public void Zip64_Two_Small_Files_Zip64() - { + public void Zip64_Two_Small_Files_Zip64() => // Multiple files, use zip64 even though it is not required RunSingleTest(2, FOUR_GB_LIMIT / 2, set_zip64: true, forward_only: false); - } [Trait("format", "zip64")] public void Zip64_Single_Large_File_Fail() diff --git a/tests/SharpCompress.Test/Zip/ZipArchiveTests.cs b/tests/SharpCompress.Test/Zip/ZipArchiveTests.cs index 738223a7..cdd24675 100644 --- a/tests/SharpCompress.Test/Zip/ZipArchiveTests.cs +++ b/tests/SharpCompress.Test/Zip/ZipArchiveTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; using System.Linq; using System.Text; @@ -10,763 +10,621 @@ using SharpCompress.Writers; using SharpCompress.Writers.Zip; using Xunit; -namespace SharpCompress.Test.Zip +namespace SharpCompress.Test.Zip; + +public class ZipArchiveTests : ArchiveTests { - public class ZipArchiveTests : ArchiveTests - { - public ZipArchiveTests() - { - UseExtensionInsteadOfNameToVerify = true; - } + public ZipArchiveTests() => UseExtensionInsteadOfNameToVerify = true; - [Fact] - public void Zip_ZipX_ArchiveStreamRead() - { - ArchiveStreamRead("Zip.zipx"); - } + [Fact] + public void Zip_ZipX_ArchiveStreamRead() => ArchiveStreamRead("Zip.zipx"); - [Fact] - public void Zip_BZip2_Streamed_ArchiveStreamRead() - { - ArchiveStreamRead("Zip.bzip2.dd.zip"); - } + [Fact] + public void Zip_BZip2_Streamed_ArchiveStreamRead() => ArchiveStreamRead("Zip.bzip2.dd.zip"); - [Fact] - public void Zip_BZip2_ArchiveStreamRead() - { - ArchiveStreamRead("Zip.bzip2.zip"); - } + [Fact] + public void Zip_BZip2_ArchiveStreamRead() => ArchiveStreamRead("Zip.bzip2.zip"); - [Fact] - public void Zip_Deflate_Streamed2_ArchiveStreamRead() - { - ArchiveStreamRead("Zip.deflate.dd-.zip"); - } + [Fact] + public void Zip_Deflate_Streamed2_ArchiveStreamRead() => + ArchiveStreamRead("Zip.deflate.dd-.zip"); - [Fact] - public void Zip_Deflate_Streamed_ArchiveStreamRead() - { - ArchiveStreamRead("Zip.deflate.dd.zip"); - } + [Fact] + public void Zip_Deflate_Streamed_ArchiveStreamRead() => ArchiveStreamRead("Zip.deflate.dd.zip"); - [Fact] - public void Zip_Deflate_ArchiveStreamRead() - { - ArchiveStreamRead("Zip.deflate.zip"); - } + [Fact] + public void Zip_Deflate_ArchiveStreamRead() => ArchiveStreamRead("Zip.deflate.zip"); - [Fact] - public void Zip_Deflate64_ArchiveStreamRead() - { - ArchiveStreamRead("Zip.deflate64.zip"); - } + [Fact] + public void Zip_Deflate64_ArchiveStreamRead() => ArchiveStreamRead("Zip.deflate64.zip"); - [Fact] - public void Zip_LZMA_Streamed_ArchiveStreamRead() - { - ArchiveStreamRead("Zip.lzma.dd.zip"); - } + [Fact] + public void Zip_LZMA_Streamed_ArchiveStreamRead() => ArchiveStreamRead("Zip.lzma.dd.zip"); - [Fact] - public void Zip_LZMA_ArchiveStreamRead() - { - ArchiveStreamRead("Zip.lzma.zip"); - } + [Fact] + public void Zip_LZMA_ArchiveStreamRead() => ArchiveStreamRead("Zip.lzma.zip"); - [Fact] - public void Zip_PPMd_Streamed_ArchiveStreamRead() - { - ArchiveStreamRead("Zip.ppmd.dd.zip"); - } + [Fact] + public void Zip_PPMd_Streamed_ArchiveStreamRead() => ArchiveStreamRead("Zip.ppmd.dd.zip"); - [Fact] - public void Zip_PPMd_ArchiveStreamRead() - { - ArchiveStreamRead("Zip.ppmd.zip"); - } + [Fact] + public void Zip_PPMd_ArchiveStreamRead() => ArchiveStreamRead("Zip.ppmd.zip"); - [Fact] - public void Zip_None_ArchiveStreamRead() - { - ArchiveStreamRead("Zip.none.zip"); - } + [Fact] + public void Zip_None_ArchiveStreamRead() => ArchiveStreamRead("Zip.none.zip"); - [Fact] - public void Zip_BZip2_Streamed_ArchiveFileRead() - { - ArchiveFileRead("Zip.bzip2.dd.zip"); - } + [Fact] + public void Zip_BZip2_Streamed_ArchiveFileRead() => ArchiveFileRead("Zip.bzip2.dd.zip"); - [Fact] - public void Zip_BZip2_ArchiveFileRead() - { - ArchiveFileRead("Zip.bzip2.zip"); - } + [Fact] + public void Zip_BZip2_ArchiveFileRead() => ArchiveFileRead("Zip.bzip2.zip"); - [Fact] - public void WinZip26_ArchiveFileRead() - { - ArchiveFileRead("WinZip26.zip"); - } + [Fact] + public void WinZip26_ArchiveFileRead() => ArchiveFileRead("WinZip26.zip"); - [Fact] - public void WinZip26_Multi_ArchiveFileRead() - { - ArchiveStreamMultiRead(null, "WinZip26.nocomp.multi.zip", "WinZip26.nocomp.multi.z01"); //min split size is 64k so no compression used - } + [Fact] + public void WinZip26_Multi_ArchiveFileRead() => + ArchiveStreamMultiRead(null, "WinZip26.nocomp.multi.zip", "WinZip26.nocomp.multi.z01"); //min split size is 64k so no compression used - [Fact] - public void WinZip26_X_BZip2_ArchiveFileRead() - { - ArchiveFileRead("WinZip26_BZip2.zipx"); - } + [Fact] + public void WinZip26_X_BZip2_ArchiveFileRead() => ArchiveFileRead("WinZip26_BZip2.zipx"); - [Fact] - public void WinZip26_X_Lzma_ArchiveFileRead() - { - ArchiveFileRead("WinZip26_LZMA.zipx"); - } + [Fact] + public void WinZip26_X_Lzma_ArchiveFileRead() => ArchiveFileRead("WinZip26_LZMA.zipx"); - [Fact] - public void WinZip26_X_Multi_ArchiveFileRead() - { - ArchiveStreamMultiRead( - null, - "WinZip26.nocomp.multi.zipx", - "WinZip26.nocomp.multi.zx01" - ); //min split size is 64k so no compression used - } + [Fact] + public void WinZip26_X_Multi_ArchiveFileRead() => + ArchiveStreamMultiRead(null, "WinZip26.nocomp.multi.zipx", "WinZip26.nocomp.multi.zx01"); //min split size is 64k so no compression used - [Fact] - public void Zip_Deflate_Streamed2_ArchiveFileRead() - { - ArchiveFileRead("Zip.deflate.dd-.zip"); - } + [Fact] + public void Zip_Deflate_Streamed2_ArchiveFileRead() => ArchiveFileRead("Zip.deflate.dd-.zip"); - [Fact] - public void Zip_Deflate_Streamed_ArchiveFileRead() - { - ArchiveFileRead("Zip.deflate.dd.zip"); - } + [Fact] + public void Zip_Deflate_Streamed_ArchiveFileRead() => ArchiveFileRead("Zip.deflate.dd.zip"); - [Fact] - public void Zip_Deflate_ArchiveFileRead() - { - ArchiveFileRead("Zip.deflate.zip"); - } + [Fact] + public void Zip_Deflate_ArchiveFileRead() => ArchiveFileRead("Zip.deflate.zip"); - //will detect and load other files - [Fact] - public void Zip_Deflate_Multi_ArchiveFirstFileRead() - { - ArchiveFileRead("WinZip26.nocomp.multi.zip"); - //"WinZip26.nocomp.multi.z01" - } + //will detect and load other files + [Fact] + public void Zip_Deflate_Multi_ArchiveFirstFileRead() => + ArchiveFileRead("WinZip26.nocomp.multi.zip"); - //will detect and load other files - [Fact] - public void ZipX_Deflate_Multi_ArchiveFirstFileRead() - { - ArchiveFileRead("WinZip26.nocomp.multi.zipx"); - //"WinZip26.nocomp.multi.zx01" - } + //"WinZip26.nocomp.multi.z01" + //will detect and load other files + [Fact] + public void ZipX_Deflate_Multi_ArchiveFirstFileRead() => + ArchiveFileRead("WinZip26.nocomp.multi.zipx"); - [Fact] - public void Zip_GetParts() - { - //uses first part to search for all parts and compares against this array - ArchiveGetParts( - new string[] { "Infozip.nocomp.multi.zip", "Infozip.nocomp.multi.z01" } - ); - } + //"WinZip26.nocomp.multi.zx01" + [Fact] + public void Zip_GetParts() => + //uses first part to search for all parts and compares against this array + ArchiveGetParts(new[] { "Infozip.nocomp.multi.zip", "Infozip.nocomp.multi.z01" }); - [Fact] - public void ZipX_GetParts() - { - //uses first part to search for all parts and compares against this array - ArchiveGetParts( - new string[] { "WinZip26.nocomp.multi.zipx", "WinZip26.nocomp.multi.zx01" } - ); - } + [Fact] + public void ZipX_GetParts() => + //uses first part to search for all parts and compares against this array + ArchiveGetParts(new[] { "WinZip26.nocomp.multi.zipx", "WinZip26.nocomp.multi.zx01" }); - [Fact] - public void Zip_GetPartsSplit() - { - //uses first part to search for all parts and compares against this array - ArchiveGetParts( - new string[] - { - "Zip.deflate.split.001", - "Zip.deflate.split.002", - "Zip.deflate.split.003", - "Zip.deflate.split.004", - "Zip.deflate.split.005", - "Zip.deflate.split.006" - } - ); - } - - //will detect and load other files - [Fact] - public void Zip_Deflate_Split_ArchiveFirstFileRead() - { - ArchiveFileRead("Zip.deflate.split.001"); - //"Zip.deflate.split.002", - //"Zip.deflate.split.003", - //"Zip.deflate.split.004", - //"Zip.deflate.split.005", - //"Zip.deflate.split.006" - } - - [Fact] - public void Zip_Deflate_Split_ArchiveFileRead() - { - ArchiveStreamMultiRead( - null, + [Fact] + public void Zip_GetPartsSplit() => + //uses first part to search for all parts and compares against this array + ArchiveGetParts( + new[] + { "Zip.deflate.split.001", "Zip.deflate.split.002", "Zip.deflate.split.003", "Zip.deflate.split.004", "Zip.deflate.split.005", "Zip.deflate.split.006" + } + ); + + //will detect and load other files + [Fact] + public void Zip_Deflate_Split_ArchiveFirstFileRead() => + ArchiveFileRead("Zip.deflate.split.001"); + + //"Zip.deflate.split.002", + //"Zip.deflate.split.003", + //"Zip.deflate.split.004", + //"Zip.deflate.split.005", + //"Zip.deflate.split.006" + [Fact] + public void Zip_Deflate_Split_ArchiveFileRead() => + ArchiveStreamMultiRead( + null, + "Zip.deflate.split.001", + "Zip.deflate.split.002", + "Zip.deflate.split.003", + "Zip.deflate.split.004", + "Zip.deflate.split.005", + "Zip.deflate.split.006" + ); + + [Fact] + public void Zip_InfoZip_Multi_ArchiveFileRead() => + ArchiveStreamMultiRead(null, "Infozip.nocomp.multi.zip", "Infozip.nocomp.multi.z01"); //min split size is 64k so no compression used + + [Fact] + public void Zip_Deflate64_ArchiveFileRead() => ArchiveFileRead("Zip.deflate64.zip"); + + [Fact] + public void Zip_LZMA_Streamed_ArchiveFileRead() => ArchiveFileRead("Zip.lzma.dd.zip"); + + [Fact] + public void Zip_LZMA_ArchiveFileRead() => ArchiveFileRead("Zip.lzma.zip"); + + [Fact] + public void Zip_PPMd_Streamed_ArchiveFileRead() => ArchiveFileRead("Zip.ppmd.dd.zip"); + + [Fact] + public void Zip_PPMd_ArchiveFileRead() => ArchiveFileRead("Zip.ppmd.zip"); + + [Fact] + public void Zip_None_ArchiveFileRead() => ArchiveFileRead("Zip.none.zip"); + + [Fact] + public void Zip_Zip64_ArchiveStreamRead() => ArchiveStreamRead("Zip.zip64.zip"); + + [Fact] + public void Zip_Zip64_ArchiveFileRead() => ArchiveFileRead("Zip.zip64.zip"); + + [Fact] + public void Zip_Random_Write_Remove() + { + string scratchPath = Path.Combine(SCRATCH_FILES_PATH, "Zip.deflate.mod.zip"); + string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.noEmptyDirs.zip"); + string modified = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.mod.zip"); + + using (var archive = ZipArchive.Open(unmodified)) + { + var entry = archive.Entries.Single( + x => x.Key.EndsWith("jpg", StringComparison.OrdinalIgnoreCase) + ); + archive.RemoveEntry(entry); + + WriterOptions writerOptions = new ZipWriterOptions(CompressionType.Deflate); + writerOptions.ArchiveEncoding.Default = Encoding.GetEncoding(866); + + archive.SaveTo(scratchPath, writerOptions); + } + CompareArchivesByPath(modified, scratchPath, Encoding.GetEncoding(866)); + } + + [Fact] + public void Zip_Random_Write_Add() + { + string jpg = Path.Combine(ORIGINAL_FILES_PATH, "jpg", "test.jpg"); + string scratchPath = Path.Combine(SCRATCH_FILES_PATH, "Zip.deflate.mod.zip"); + string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.mod.zip"); + string modified = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.mod2.zip"); + + using (var archive = ZipArchive.Open(unmodified)) + { + archive.AddEntry("jpg\\test.jpg", jpg); + + WriterOptions writerOptions = new ZipWriterOptions(CompressionType.Deflate); + writerOptions.ArchiveEncoding.Default = Encoding.GetEncoding(866); + + archive.SaveTo(scratchPath, writerOptions); + } + CompareArchivesByPath(modified, scratchPath, Encoding.GetEncoding(866)); + } + + [Fact] + public void Zip_Save_Twice() + { + string scratchPath1 = Path.Combine(SCRATCH_FILES_PATH, "a.zip"); + string scratchPath2 = Path.Combine(SCRATCH_FILES_PATH, "b.zip"); + + using (var arc = ZipArchive.Create()) + { + string str = "test.txt"; + var source = new MemoryStream(Encoding.UTF8.GetBytes(str)); + arc.AddEntry("test.txt", source, true, source.Length); + arc.SaveTo(scratchPath1, CompressionType.Deflate); + arc.SaveTo(scratchPath2, CompressionType.Deflate); + } + + Assert.Equal(new FileInfo(scratchPath1).Length, new FileInfo(scratchPath2).Length); + } + + [Fact] + public void Zip_Removal_Poly() + { + string scratchPath = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.noEmptyDirs.zip"); + + using (ZipArchive vfs = (ZipArchive)ArchiveFactory.Open(scratchPath)) + { + var e = vfs.Entries.First( + v => v.Key.EndsWith("jpg", StringComparison.OrdinalIgnoreCase) + ); + vfs.RemoveEntry(e); + Assert.Null( + vfs.Entries.FirstOrDefault( + v => v.Key.EndsWith("jpg", StringComparison.OrdinalIgnoreCase) + ) + ); + Assert.Null( + ((IArchive)vfs).Entries.FirstOrDefault( + v => v.Key.EndsWith("jpg", StringComparison.OrdinalIgnoreCase) + ) ); } + } - [Fact] - public void Zip_InfoZip_Multi_ArchiveFileRead() + [Fact] + public void Zip_Create_NoDups() + { + using (var arc = ZipArchive.Create()) { - ArchiveStreamMultiRead(null, "Infozip.nocomp.multi.zip", "Infozip.nocomp.multi.z01"); //min split size is 64k so no compression used + arc.AddEntry("1.txt", new MemoryStream()); + Assert.Throws(() => arc.AddEntry("\\1.txt", new MemoryStream())); } + } - [Fact] - public void Zip_Deflate64_ArchiveFileRead() + [Fact] + public void Zip_Create_Same_Stream() + { + string scratchPath1 = Path.Combine(SCRATCH_FILES_PATH, "a.zip"); + string scratchPath2 = Path.Combine(SCRATCH_FILES_PATH, "b.zip"); + + using (var arc = ZipArchive.Create()) { - ArchiveFileRead("Zip.deflate64.zip"); - } - - [Fact] - public void Zip_LZMA_Streamed_ArchiveFileRead() - { - ArchiveFileRead("Zip.lzma.dd.zip"); - } - - [Fact] - public void Zip_LZMA_ArchiveFileRead() - { - ArchiveFileRead("Zip.lzma.zip"); - } - - [Fact] - public void Zip_PPMd_Streamed_ArchiveFileRead() - { - ArchiveFileRead("Zip.ppmd.dd.zip"); - } - - [Fact] - public void Zip_PPMd_ArchiveFileRead() - { - ArchiveFileRead("Zip.ppmd.zip"); - } - - [Fact] - public void Zip_None_ArchiveFileRead() - { - ArchiveFileRead("Zip.none.zip"); - } - - [Fact] - public void Zip_Zip64_ArchiveStreamRead() - { - ArchiveStreamRead("Zip.zip64.zip"); - } - - [Fact] - public void Zip_Zip64_ArchiveFileRead() - { - ArchiveFileRead("Zip.zip64.zip"); - } - - [Fact] - public void Zip_Random_Write_Remove() - { - string scratchPath = Path.Combine(SCRATCH_FILES_PATH, "Zip.deflate.mod.zip"); - string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.noEmptyDirs.zip"); - string modified = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.mod.zip"); - - using (var archive = ZipArchive.Open(unmodified)) + using (var stream = new MemoryStream(Encoding.UTF8.GetBytes("qwert"))) { - var entry = archive.Entries.Single( - x => x.Key.EndsWith("jpg", StringComparison.OrdinalIgnoreCase) - ); - archive.RemoveEntry(entry); - - WriterOptions writerOptions = new ZipWriterOptions(CompressionType.Deflate); - writerOptions.ArchiveEncoding.Default = Encoding.GetEncoding(866); - - archive.SaveTo(scratchPath, writerOptions); - } - CompareArchivesByPath(modified, scratchPath, Encoding.GetEncoding(866)); - } - - [Fact] - public void Zip_Random_Write_Add() - { - string jpg = Path.Combine(ORIGINAL_FILES_PATH, "jpg", "test.jpg"); - string scratchPath = Path.Combine(SCRATCH_FILES_PATH, "Zip.deflate.mod.zip"); - string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.mod.zip"); - string modified = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.mod2.zip"); - - using (var archive = ZipArchive.Open(unmodified)) - { - archive.AddEntry("jpg\\test.jpg", jpg); - - WriterOptions writerOptions = new ZipWriterOptions(CompressionType.Deflate); - writerOptions.ArchiveEncoding.Default = Encoding.GetEncoding(866); - - archive.SaveTo(scratchPath, writerOptions); - } - CompareArchivesByPath(modified, scratchPath, Encoding.GetEncoding(866)); - } - - [Fact] - public void Zip_Save_Twice() - { - string scratchPath1 = Path.Combine(SCRATCH_FILES_PATH, "a.zip"); - string scratchPath2 = Path.Combine(SCRATCH_FILES_PATH, "b.zip"); - - using (var arc = ZipArchive.Create()) - { - string str = "test.txt"; - var source = new MemoryStream(Encoding.UTF8.GetBytes(str)); - arc.AddEntry("test.txt", source, true, source.Length); + arc.AddEntry("1.txt", stream, false, stream.Length); + arc.AddEntry("2.txt", stream, false, stream.Length); arc.SaveTo(scratchPath1, CompressionType.Deflate); arc.SaveTo(scratchPath2, CompressionType.Deflate); } - - Assert.Equal(new FileInfo(scratchPath1).Length, new FileInfo(scratchPath2).Length); } - [Fact] - public void Zip_Removal_Poly() - { - string scratchPath = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.noEmptyDirs.zip"); + Assert.Equal(new FileInfo(scratchPath1).Length, new FileInfo(scratchPath2).Length); + } - using (ZipArchive vfs = (ZipArchive)ArchiveFactory.Open(scratchPath)) + [Fact] + public void Zip_Create_New() + { + foreach ( + var file in Directory.EnumerateFiles( + ORIGINAL_FILES_PATH, + "*.*", + SearchOption.AllDirectories + ) + ) + { + var newFileName = file.Substring(ORIGINAL_FILES_PATH.Length); + if ( + newFileName.StartsWith( + Path.DirectorySeparatorChar.ToString(), + StringComparison.OrdinalIgnoreCase + ) + ) { - var e = vfs.Entries.First( - v => v.Key.EndsWith("jpg", StringComparison.OrdinalIgnoreCase) - ); - vfs.RemoveEntry(e); - Assert.Null( - vfs.Entries.FirstOrDefault( - v => v.Key.EndsWith("jpg", StringComparison.OrdinalIgnoreCase) - ) - ); - Assert.Null( - ((IArchive)vfs).Entries.FirstOrDefault( - v => v.Key.EndsWith("jpg", StringComparison.OrdinalIgnoreCase) - ) + newFileName = newFileName.Substring(1); + } + newFileName = Path.Combine(SCRATCH_FILES_PATH, newFileName); + var newDir = Path.GetDirectoryName(newFileName) ?? throw new ArgumentNullException(); + if (!Directory.Exists(newDir)) + { + Directory.CreateDirectory(newDir); + } + File.Copy(file, newFileName); + } + string scratchPath = Path.Combine(SCRATCH2_FILES_PATH, "Zip.deflate.noEmptyDirs.zip"); + string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.noEmptyDirs.zip"); + + using (var archive = ZipArchive.Create()) + { + archive.AddAllFromDirectory(SCRATCH_FILES_PATH); + + WriterOptions writerOptions = new ZipWriterOptions(CompressionType.Deflate); + writerOptions.ArchiveEncoding.Default = Encoding.GetEncoding(866); + + archive.SaveTo(scratchPath, writerOptions); + } + CompareArchivesByPath(unmodified, scratchPath, Encoding.GetEncoding(866)); + Directory.Delete(SCRATCH_FILES_PATH, true); + } + + /// + /// Creates an empty zip file and attempts to read it right afterwards. + /// Ensures that parsing file headers works even in that case + /// + [Fact] + public void Zip_Create_Empty_And_Read() + { + var archive = ZipArchive.Create(); + + var archiveStream = new MemoryStream(); + + archive.SaveTo(archiveStream, CompressionType.LZMA); + + archiveStream.Position = 0; + + var readArchive = ArchiveFactory.Open(archiveStream); + + var count = readArchive.Entries.Count(); + + Assert.Equal(0, count); + } + + [Fact] + public void Zip_Create_New_Add_Remove() + { + foreach ( + var file in Directory.EnumerateFiles( + ORIGINAL_FILES_PATH, + "*.*", + SearchOption.AllDirectories + ) + ) + { + var newFileName = file.Substring(ORIGINAL_FILES_PATH.Length); + if ( + newFileName.StartsWith( + Path.DirectorySeparatorChar.ToString(), + StringComparison.OrdinalIgnoreCase + ) + ) + { + newFileName = newFileName.Substring(1); + } + newFileName = Path.Combine(SCRATCH_FILES_PATH, newFileName); + var newDir = Path.GetDirectoryName(newFileName) ?? throw new ArgumentNullException(); + if (!Directory.Exists(newDir)) + { + Directory.CreateDirectory(newDir); + } + File.Copy(file, newFileName); + } + string scratchPath = Path.Combine(SCRATCH2_FILES_PATH, "Zip.deflate.noEmptyDirs.zip"); + + using (var archive = ZipArchive.Create()) + { + archive.AddAllFromDirectory(SCRATCH_FILES_PATH); + archive.RemoveEntry( + archive.Entries.Single( + x => x.Key.EndsWith("jpg", StringComparison.OrdinalIgnoreCase) + ) + ); + Assert.Null( + archive.Entries.FirstOrDefault( + x => x.Key.EndsWith("jpg", StringComparison.OrdinalIgnoreCase) + ) + ); + } + Directory.Delete(SCRATCH_FILES_PATH, true); + } + + [Fact] + public void Zip_Deflate_WinzipAES_Read() + { + using ( + var reader = ZipArchive.Open( + Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.WinzipAES.zip"), + new ReaderOptions() { Password = "test" } + ) + ) + { + foreach (var entry in reader.Entries.Where(x => !x.IsDirectory)) + { + entry.WriteToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } ); } } + VerifyFiles(); + } - [Fact] - public void Zip_Create_NoDups() - { - using (var arc = ZipArchive.Create()) - { - arc.AddEntry("1.txt", new MemoryStream()); - Assert.Throws(() => arc.AddEntry("\\1.txt", new MemoryStream())); - } - } - - [Fact] - public void Zip_Create_Same_Stream() - { - string scratchPath1 = Path.Combine(SCRATCH_FILES_PATH, "a.zip"); - string scratchPath2 = Path.Combine(SCRATCH_FILES_PATH, "b.zip"); - - using (var arc = ZipArchive.Create()) - { - using (var stream = new MemoryStream(Encoding.UTF8.GetBytes("qwert"))) - { - arc.AddEntry("1.txt", stream, false, stream.Length); - arc.AddEntry("2.txt", stream, false, stream.Length); - arc.SaveTo(scratchPath1, CompressionType.Deflate); - arc.SaveTo(scratchPath2, CompressionType.Deflate); - } - } - - Assert.Equal(new FileInfo(scratchPath1).Length, new FileInfo(scratchPath2).Length); - } - - [Fact] - public void Zip_Create_New() - { - foreach ( - var file in Directory.EnumerateFiles( - ORIGINAL_FILES_PATH, - "*.*", - SearchOption.AllDirectories - ) + [Fact] + public void Zip_Deflate_WinzipAES_MultiOpenEntryStream() + { + using ( + var reader = ZipArchive.Open( + Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.WinzipAES2.zip"), + new ReaderOptions() { Password = "test" } ) - { - var newFileName = file.Substring(ORIGINAL_FILES_PATH.Length); - if ( - newFileName.StartsWith( - Path.DirectorySeparatorChar.ToString(), - StringComparison.OrdinalIgnoreCase - ) - ) - { - newFileName = newFileName.Substring(1); - } - newFileName = Path.Combine(SCRATCH_FILES_PATH, newFileName); - var newDir = - Path.GetDirectoryName(newFileName) ?? throw new ArgumentNullException(); - if (!Directory.Exists(newDir)) - { - Directory.CreateDirectory(newDir); - } - File.Copy(file, newFileName); - } - string scratchPath = Path.Combine(SCRATCH2_FILES_PATH, "Zip.deflate.noEmptyDirs.zip"); - string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.noEmptyDirs.zip"); - - using (var archive = ZipArchive.Create()) - { - archive.AddAllFromDirectory(SCRATCH_FILES_PATH); - - WriterOptions writerOptions = new ZipWriterOptions(CompressionType.Deflate); - writerOptions.ArchiveEncoding.Default = Encoding.GetEncoding(866); - - archive.SaveTo(scratchPath, writerOptions); - } - CompareArchivesByPath(unmodified, scratchPath, Encoding.GetEncoding(866)); - Directory.Delete(SCRATCH_FILES_PATH, true); - } - - /// - /// Creates an empty zip file and attempts to read it right afterwards. - /// Ensures that parsing file headers works even in that case - /// - [Fact] - public void Zip_Create_Empty_And_Read() + ) { - var archive = ZipArchive.Create(); - - var archiveStream = new MemoryStream(); - - archive.SaveTo(archiveStream, CompressionType.LZMA); - - archiveStream.Position = 0; - - var readArchive = ArchiveFactory.Open(archiveStream); - - var count = readArchive.Entries.Count(); - - Assert.Equal(0, count); - } - - [Fact] - public void Zip_Create_New_Add_Remove() - { - foreach ( - var file in Directory.EnumerateFiles( - ORIGINAL_FILES_PATH, - "*.*", - SearchOption.AllDirectories - ) - ) + foreach (var entry in reader.Entries.Where(x => !x.IsDirectory)) { - var newFileName = file.Substring(ORIGINAL_FILES_PATH.Length); - if ( - newFileName.StartsWith( - Path.DirectorySeparatorChar.ToString(), - StringComparison.OrdinalIgnoreCase - ) - ) - { - newFileName = newFileName.Substring(1); - } - newFileName = Path.Combine(SCRATCH_FILES_PATH, newFileName); - var newDir = - Path.GetDirectoryName(newFileName) ?? throw new ArgumentNullException(); - if (!Directory.Exists(newDir)) - { - Directory.CreateDirectory(newDir); - } - File.Copy(file, newFileName); - } - string scratchPath = Path.Combine(SCRATCH2_FILES_PATH, "Zip.deflate.noEmptyDirs.zip"); - - using (var archive = ZipArchive.Create()) - { - archive.AddAllFromDirectory(SCRATCH_FILES_PATH); - archive.RemoveEntry( - archive.Entries.Single( - x => x.Key.EndsWith("jpg", StringComparison.OrdinalIgnoreCase) - ) - ); - Assert.Null( - archive.Entries.FirstOrDefault( - x => x.Key.EndsWith("jpg", StringComparison.OrdinalIgnoreCase) - ) - ); - } - Directory.Delete(SCRATCH_FILES_PATH, true); - } - - [Fact] - public void Zip_Deflate_WinzipAES_Read() - { - using ( - var reader = ZipArchive.Open( - Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.WinzipAES.zip"), - new ReaderOptions() { Password = "test" } - ) - ) - { - foreach (var entry in reader.Entries.Where(x => !x.IsDirectory)) - { - entry.WriteToDirectory( - SCRATCH_FILES_PATH, - new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } - ); - } - } - VerifyFiles(); - } - - [Fact] - public void Zip_Deflate_WinzipAES_MultiOpenEntryStream() - { - using ( - var reader = ZipArchive.Open( - Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.WinzipAES2.zip"), - new ReaderOptions() { Password = "test" } - ) - ) - { - foreach (var entry in reader.Entries.Where(x => !x.IsDirectory)) - { - var stream = entry.OpenEntryStream(); - Assert.NotNull(stream); - var ex = Record.Exception(() => stream = entry.OpenEntryStream()); - Assert.Null(ex); - } - } - } - - [Fact] - public void Zip_Read_Volume_Comment() - { - using ( - var reader = ZipArchive.Open( - Path.Combine(TEST_ARCHIVES_PATH, "Zip.zip64.zip"), - new ReaderOptions() { Password = "test" } - ) - ) - { - var isComplete = reader.IsComplete; - Assert.Equal(1, reader.Volumes.Count); - - string expectedComment = - "Encoding:utf-8 || Compression:Deflate levelDefault || Encrypt:None || ZIP64:Always\r\nCreated at 2017-Jan-23 14:10:43 || DotNetZip Tool v1.9.1.8\r\nTest zip64 archive"; - Assert.Equal(expectedComment, reader.Volumes.First().Comment); - } - } - - [Fact] - public void Zip_BZip2_Pkware_Read() - { - using ( - var reader = ZipArchive.Open( - Path.Combine(TEST_ARCHIVES_PATH, "Zip.bzip2.pkware.zip"), - new ReaderOptions() { Password = "test" } - ) - ) - { - foreach (var entry in reader.Entries.Where(x => !x.IsDirectory)) - { - entry.WriteToDirectory( - SCRATCH_FILES_PATH, - new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } - ); - } - } - VerifyFiles(); - } - - [Fact] - public void Zip_Random_Entry_Access() - { - string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.noEmptyDirs.zip"); - - ZipArchive a = ZipArchive.Open(unmodified); - int count = 0; - foreach (var e in a.Entries) - { - count++; - } - - //Prints 3 - Assert.Equal(3, count); - a.Dispose(); - - a = ZipArchive.Open(unmodified); - int count2 = 0; - - foreach (var e in a.Entries) - { - count2++; - - //Stop at last file - if (count2 == count) - { - var s = e.OpenEntryStream(); - s.ReadByte(); //Actually access stream - s.Dispose(); - break; - } - } - - int count3 = 0; - foreach (var e in a.Entries) - { - count3++; - } - - Assert.Equal(3, count3); - } - - [Fact] - public void Zip_Deflate_PKWear_Multipy_Entry_Access() - { - string zipFile = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.pkware.zip"); - - using (FileStream fileStream = File.Open(zipFile, FileMode.Open)) - { - using ( - IArchive archive = ArchiveFactory.Open( - fileStream, - new ReaderOptions { Password = "12345678" } - ) - ) - { - var entries = archive.Entries.Where(entry => !entry.IsDirectory); - foreach (IArchiveEntry entry in entries) - { - for (var i = 0; i < 100; i++) - { - using (var memoryStream = new MemoryStream()) - using (Stream entryStream = entry.OpenEntryStream()) - { - entryStream.CopyTo(memoryStream); - } - } - } - } - } - } - - [SkippableFact] - public void Zip_Evil_Throws_Exception() - { - //windows only because of the paths - Skip.IfNot(Environment.OSVersion.Platform == PlatformID.Win32NT); - - string zipFile = Path.Combine(TEST_ARCHIVES_PATH, "Zip.Evil.zip"); - - Assert.ThrowsAny(() => - { - using (var archive = ZipArchive.Open(zipFile)) - { - foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) - { - entry.WriteToDirectory( - SCRATCH_FILES_PATH, - new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } - ); - } - } - }); - } - - private class NonSeekableMemoryStream : MemoryStream - { - public override bool CanSeek => false; - } - - [Fact] - public void TestSharpCompressWithEmptyStream() - { - MemoryStream stream = new NonSeekableMemoryStream(); - - using ( - IWriter zipWriter = WriterFactory.Open( - stream, - ArchiveType.Zip, - CompressionType.Deflate - ) - ) - { - zipWriter.Write("foo.txt", new MemoryStream(Array.Empty())); - zipWriter.Write("foo2.txt", new MemoryStream(new byte[10])); - } - - stream = new MemoryStream(stream.ToArray()); - File.WriteAllBytes(Path.Combine(SCRATCH_FILES_PATH, "foo.zip"), stream.ToArray()); - - using (var zipArchive = ZipArchive.Open(stream)) - { - foreach (var entry in zipArchive.Entries) - { - using (var entryStream = entry.OpenEntryStream()) - { - MemoryStream tempStream = new MemoryStream(); - const int bufSize = 0x1000; - byte[] buf = new byte[bufSize]; - int bytesRead = 0; - while ((bytesRead = entryStream.Read(buf, 0, bufSize)) > 0) - { - tempStream.Write(buf, 0, bytesRead); - } - } - } - } - } - - [Fact] - public void Zip_BadLocalExtra_Read() - { - string zipPath = Path.Combine(TEST_ARCHIVES_PATH, "Zip.badlocalextra.zip"); - - using (ZipArchive za = ZipArchive.Open(zipPath)) - { - var ex = Record.Exception(() => - { - var firstEntry = za.Entries.First(x => x.Key == "first.txt"); - var buffer = new byte[4096]; - - using (var memoryStream = new MemoryStream()) - using (var firstStream = firstEntry.OpenEntryStream()) - { - firstStream.CopyTo(memoryStream); - Assert.Equal(199, memoryStream.Length); - } - }); - + var stream = entry.OpenEntryStream(); + Assert.NotNull(stream); + var ex = Record.Exception(() => stream = entry.OpenEntryStream()); Assert.Null(ex); } } + } - [Fact] - public void Zip_NoCompression_DataDescriptors_Read() + [Fact] + public void Zip_Read_Volume_Comment() + { + using ( + var reader = ZipArchive.Open( + Path.Combine(TEST_ARCHIVES_PATH, "Zip.zip64.zip"), + new ReaderOptions() { Password = "test" } + ) + ) { - string zipPath = Path.Combine(TEST_ARCHIVES_PATH, "Zip.none.datadescriptors.zip"); + var isComplete = reader.IsComplete; + Assert.Equal(1, reader.Volumes.Count); - using (ZipArchive za = ZipArchive.Open(zipPath)) + string expectedComment = + "Encoding:utf-8 || Compression:Deflate levelDefault || Encrypt:None || ZIP64:Always\r\nCreated at 2017-Jan-23 14:10:43 || DotNetZip Tool v1.9.1.8\r\nTest zip64 archive"; + Assert.Equal(expectedComment, reader.Volumes.First().Comment); + } + } + + [Fact] + public void Zip_BZip2_Pkware_Read() + { + using ( + var reader = ZipArchive.Open( + Path.Combine(TEST_ARCHIVES_PATH, "Zip.bzip2.pkware.zip"), + new ReaderOptions() { Password = "test" } + ) + ) + { + foreach (var entry in reader.Entries.Where(x => !x.IsDirectory)) + { + entry.WriteToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } + ); + } + } + VerifyFiles(); + } + + [Fact] + public void Zip_Random_Entry_Access() + { + string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.noEmptyDirs.zip"); + + ZipArchive a = ZipArchive.Open(unmodified); + int count = 0; + foreach (var e in a.Entries) + { + count++; + } + + //Prints 3 + Assert.Equal(3, count); + a.Dispose(); + + a = ZipArchive.Open(unmodified); + int count2 = 0; + + foreach (var e in a.Entries) + { + count2++; + + //Stop at last file + if (count2 == count) + { + var s = e.OpenEntryStream(); + s.ReadByte(); //Actually access stream + s.Dispose(); + break; + } + } + + int count3 = 0; + foreach (var e in a.Entries) + { + count3++; + } + + Assert.Equal(3, count3); + } + + [Fact] + public void Zip_Deflate_PKWear_Multipy_Entry_Access() + { + string zipFile = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.pkware.zip"); + + using (FileStream fileStream = File.Open(zipFile, FileMode.Open)) + { + using ( + IArchive archive = ArchiveFactory.Open( + fileStream, + new ReaderOptions { Password = "12345678" } + ) + ) + { + var entries = archive.Entries.Where(entry => !entry.IsDirectory); + foreach (IArchiveEntry entry in entries) + { + for (var i = 0; i < 100; i++) + { + using (var memoryStream = new MemoryStream()) + using (Stream entryStream = entry.OpenEntryStream()) + { + entryStream.CopyTo(memoryStream); + } + } + } + } + } + } + + [SkippableFact] + public void Zip_Evil_Throws_Exception() + { + //windows only because of the paths + Skip.IfNot(Environment.OSVersion.Platform == PlatformID.Win32NT); + + string zipFile = Path.Combine(TEST_ARCHIVES_PATH, "Zip.Evil.zip"); + + Assert.ThrowsAny(() => + { + using (var archive = ZipArchive.Open(zipFile)) + { + foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) + { + entry.WriteToDirectory( + SCRATCH_FILES_PATH, + new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } + ); + } + } + }); + } + + private class NonSeekableMemoryStream : MemoryStream + { + public override bool CanSeek => false; + } + + [Fact] + public void TestSharpCompressWithEmptyStream() + { + MemoryStream stream = new NonSeekableMemoryStream(); + + using ( + IWriter zipWriter = WriterFactory.Open(stream, ArchiveType.Zip, CompressionType.Deflate) + ) + { + zipWriter.Write("foo.txt", new MemoryStream(Array.Empty())); + zipWriter.Write("foo2.txt", new MemoryStream(new byte[10])); + } + + stream = new MemoryStream(stream.ToArray()); + File.WriteAllBytes(Path.Combine(SCRATCH_FILES_PATH, "foo.zip"), stream.ToArray()); + + using (var zipArchive = ZipArchive.Open(stream)) + { + foreach (var entry in zipArchive.Entries) + { + using (var entryStream = entry.OpenEntryStream()) + { + MemoryStream tempStream = new MemoryStream(); + const int bufSize = 0x1000; + byte[] buf = new byte[bufSize]; + int bytesRead = 0; + while ((bytesRead = entryStream.Read(buf, 0, bufSize)) > 0) + { + tempStream.Write(buf, 0, bytesRead); + } + } + } + } + } + + [Fact] + public void Zip_BadLocalExtra_Read() + { + string zipPath = Path.Combine(TEST_ARCHIVES_PATH, "Zip.badlocalextra.zip"); + + using (ZipArchive za = ZipArchive.Open(zipPath)) + { + var ex = Record.Exception(() => { var firstEntry = za.Entries.First(x => x.Key == "first.txt"); var buffer = new byte[4096]; @@ -777,124 +635,145 @@ namespace SharpCompress.Test.Zip firstStream.CopyTo(memoryStream); Assert.Equal(199, memoryStream.Length); } + }); - var len1 = 0; - var buffer1 = new byte[firstEntry.Size + 256]; + Assert.Null(ex); + } + } - using (var firstStream = firstEntry.OpenEntryStream()) - { - len1 = firstStream.Read(buffer1, 0, buffer.Length); - } + [Fact] + public void Zip_NoCompression_DataDescriptors_Read() + { + string zipPath = Path.Combine(TEST_ARCHIVES_PATH, "Zip.none.datadescriptors.zip"); - Assert.Equal(199, len1); + using (ZipArchive za = ZipArchive.Open(zipPath)) + { + var firstEntry = za.Entries.First(x => x.Key == "first.txt"); + var buffer = new byte[4096]; + + using (var memoryStream = new MemoryStream()) + using (var firstStream = firstEntry.OpenEntryStream()) + { + firstStream.CopyTo(memoryStream); + Assert.Equal(199, memoryStream.Length); + } + + var len1 = 0; + var buffer1 = new byte[firstEntry.Size + 256]; + + using (var firstStream = firstEntry.OpenEntryStream()) + { + len1 = firstStream.Read(buffer1, 0, buffer.Length); + } + + Assert.Equal(199, len1); #if !NETFRAMEWORK && !NETSTANDARD2_0 - var len2 = 0; - var buffer2 = new byte[firstEntry.Size + 256]; + var len2 = 0; + var buffer2 = new byte[firstEntry.Size + 256]; - using (var firstStream = firstEntry.OpenEntryStream()) - { - len2 = firstStream.Read(buffer2.AsSpan()); - } - Assert.Equal(len1, len2); - Assert.Equal(buffer1, buffer2); + using (var firstStream = firstEntry.OpenEntryStream()) + { + len2 = firstStream.Read(buffer2.AsSpan()); + } + Assert.Equal(len1, len2); + Assert.Equal(buffer1, buffer2); #endif - } } + } - [Fact] - public void Zip_LongComment_Read() + [Fact] + public void Zip_LongComment_Read() + { + string zipPath = Path.Combine(TEST_ARCHIVES_PATH, "Zip.LongComment.zip"); + + using (ZipArchive za = ZipArchive.Open(zipPath)) { - string zipPath = Path.Combine(TEST_ARCHIVES_PATH, "Zip.LongComment.zip"); - - using (ZipArchive za = ZipArchive.Open(zipPath)) - { - var count = za.Entries.Count; - Assert.Equal(1, count); - } + var count = za.Entries.Count; + Assert.Equal(1, count); } + } - [Fact] - public void Zip_Zip64_CompressedSizeExtraOnly_Read() + [Fact] + public void Zip_Zip64_CompressedSizeExtraOnly_Read() + { + string zipPath = Path.Combine(TEST_ARCHIVES_PATH, "Zip.zip64.compressedonly.zip"); + + using (ZipArchive za = ZipArchive.Open(zipPath)) { - string zipPath = Path.Combine(TEST_ARCHIVES_PATH, "Zip.zip64.compressedonly.zip"); + var firstEntry = za.Entries.First(x => x.Key == "test/test.txt"); - using (ZipArchive za = ZipArchive.Open(zipPath)) + using (var memoryStream = new MemoryStream()) + using (var firstStream = firstEntry.OpenEntryStream()) { - var firstEntry = za.Entries.First(x => x.Key == "test/test.txt"); - - using (var memoryStream = new MemoryStream()) - using (var firstStream = firstEntry.OpenEntryStream()) - { - firstStream.CopyTo(memoryStream); - Assert.Equal(15, memoryStream.Length); - } - } - } - - [Fact] - public void Zip_Uncompressed_Skip_All() - { - var keys = new string[] - { - "Folder/File1.txt", - "Folder/File2.rtf", - "Folder2/File1.txt", - "Folder2/File2.txt", - "DEADBEEF" - }; - var zipPath = Path.Combine(TEST_ARCHIVES_PATH, "Zip.uncompressed.zip"); - using (var stream = File.Open(zipPath, FileMode.Open, FileAccess.Read)) - { - IArchive archive = ArchiveFactory.Open(stream); - IReader reader = archive.ExtractAllEntries(); - int x = 0; - while (reader.MoveToNextEntry()) - { - Assert.Equal(keys[x], reader.Entry.Key); - x++; - } - - Assert.Equal(4, x); - } - } - - [Fact] - public void Zip_Forced_Ignores_UnicodePathExtra() - { - var zipPath = Path.Combine(TEST_ARCHIVES_PATH, "Zip.UnicodePathExtra.zip"); - using (var stream = File.Open(zipPath, FileMode.Open, FileAccess.Read)) - { - IArchive archive = ArchiveFactory.Open( - stream, - new ReaderOptions - { - ArchiveEncoding = new ArchiveEncoding - { - Default = Encoding.GetEncoding("shift_jis"), - } - } - ); - IReader reader = archive.ExtractAllEntries(); - reader.MoveToNextEntry(); - Assert.Equal("궖귛궖귙귪궖귗귪궖귙_wav.frq", reader.Entry.Key); - } - using (var stream = File.Open(zipPath, FileMode.Open, FileAccess.Read)) - { - IArchive archive = ArchiveFactory.Open( - stream, - new ReaderOptions - { - ArchiveEncoding = new ArchiveEncoding - { - Forced = Encoding.GetEncoding("shift_jis"), - } - } - ); - IReader reader = archive.ExtractAllEntries(); - reader.MoveToNextEntry(); - Assert.Equal("きょきゅんきゃんきゅ_wav.frq", reader.Entry.Key); + firstStream.CopyTo(memoryStream); + Assert.Equal(15, memoryStream.Length); } } } + + [Fact] + public void Zip_Uncompressed_Skip_All() + { + var keys = new[] + { + "Folder/File1.txt", + "Folder/File2.rtf", + "Folder2/File1.txt", + "Folder2/File2.txt", + "DEADBEEF" + }; + var zipPath = Path.Combine(TEST_ARCHIVES_PATH, "Zip.uncompressed.zip"); + using (var stream = File.Open(zipPath, FileMode.Open, FileAccess.Read)) + { + IArchive archive = ArchiveFactory.Open(stream); + IReader reader = archive.ExtractAllEntries(); + int x = 0; + while (reader.MoveToNextEntry()) + { + Assert.Equal(keys[x], reader.Entry.Key); + x++; + } + + Assert.Equal(4, x); + } + } + + [Fact] + public void Zip_Forced_Ignores_UnicodePathExtra() + { + var zipPath = Path.Combine(TEST_ARCHIVES_PATH, "Zip.UnicodePathExtra.zip"); + using (var stream = File.Open(zipPath, FileMode.Open, FileAccess.Read)) + { + IArchive archive = ArchiveFactory.Open( + stream, + new ReaderOptions + { + ArchiveEncoding = new ArchiveEncoding + { + Default = Encoding.GetEncoding("shift_jis"), + } + } + ); + IReader reader = archive.ExtractAllEntries(); + reader.MoveToNextEntry(); + Assert.Equal("궖귛궖귙귪궖귗귪궖귙_wav.frq", reader.Entry.Key); + } + using (var stream = File.Open(zipPath, FileMode.Open, FileAccess.Read)) + { + IArchive archive = ArchiveFactory.Open( + stream, + new ReaderOptions + { + ArchiveEncoding = new ArchiveEncoding + { + Forced = Encoding.GetEncoding("shift_jis"), + } + } + ); + IReader reader = archive.ExtractAllEntries(); + reader.MoveToNextEntry(); + Assert.Equal("きょきゅんきゃんきゅ_wav.frq", reader.Entry.Key); + } + } } diff --git a/tests/SharpCompress.Test/Zip/ZipReaderTests.cs b/tests/SharpCompress.Test/Zip/ZipReaderTests.cs index 62f2e751..95d9b93d 100644 --- a/tests/SharpCompress.Test/Zip/ZipReaderTests.cs +++ b/tests/SharpCompress.Test/Zip/ZipReaderTests.cs @@ -12,10 +12,7 @@ namespace SharpCompress.Test.Zip; public class ZipReaderTests : ReaderTests { - public ZipReaderTests() - { - UseExtensionInsteadOfNameToVerify = true; - } + public ZipReaderTests() => UseExtensionInsteadOfNameToVerify = true; [Fact] public void Issue_269_Double_Skip() @@ -38,40 +35,23 @@ public class ZipReaderTests : ReaderTests } [Fact] - public void Zip_Zip64_Streamed_Read() - { - Read("Zip.zip64.zip", CompressionType.Deflate); - } + public void Zip_Zip64_Streamed_Read() => Read("Zip.zip64.zip", CompressionType.Deflate); [Fact] - public void Zip_ZipX_Streamed_Read() - { - Read("Zip.zipx", CompressionType.LZMA); - } + public void Zip_ZipX_Streamed_Read() => Read("Zip.zipx", CompressionType.LZMA); [Fact] - public void Zip_BZip2_Streamed_Read() - { - Read("Zip.bzip2.dd.zip", CompressionType.BZip2); - } + public void Zip_BZip2_Streamed_Read() => Read("Zip.bzip2.dd.zip", CompressionType.BZip2); [Fact] - public void Zip_BZip2_Read() - { - Read("Zip.bzip2.zip", CompressionType.BZip2); - } + public void Zip_BZip2_Read() => Read("Zip.bzip2.zip", CompressionType.BZip2); [Fact] - public void Zip_Deflate_Streamed2_Read() - { + public void Zip_Deflate_Streamed2_Read() => Read("Zip.deflate.dd-.zip", CompressionType.Deflate); - } [Fact] - public void Zip_Deflate_Streamed_Read() - { - Read("Zip.deflate.dd.zip", CompressionType.Deflate); - } + public void Zip_Deflate_Streamed_Read() => Read("Zip.deflate.dd.zip", CompressionType.Deflate); [Fact] public void Zip_Deflate_Streamed_Skip() @@ -98,52 +78,29 @@ public class ZipReaderTests : ReaderTests } [Fact] - public void Zip_Deflate_Read() - { - Read("Zip.deflate.zip", CompressionType.Deflate); - } + public void Zip_Deflate_Read() => Read("Zip.deflate.zip", CompressionType.Deflate); [Fact] - public void Zip_Deflate64_Read() - { - Read("Zip.deflate64.zip", CompressionType.Deflate64); - } + public void Zip_Deflate64_Read() => Read("Zip.deflate64.zip", CompressionType.Deflate64); [Fact] - public void Zip_LZMA_Streamed_Read() - { - Read("Zip.lzma.dd.zip", CompressionType.LZMA); - } + public void Zip_LZMA_Streamed_Read() => Read("Zip.lzma.dd.zip", CompressionType.LZMA); [Fact] - public void Zip_LZMA_Read() - { - Read("Zip.lzma.zip", CompressionType.LZMA); - } + public void Zip_LZMA_Read() => Read("Zip.lzma.zip", CompressionType.LZMA); [Fact] - public void Zip_PPMd_Streamed_Read() - { - Read("Zip.ppmd.dd.zip", CompressionType.PPMd); - } + public void Zip_PPMd_Streamed_Read() => Read("Zip.ppmd.dd.zip", CompressionType.PPMd); [Fact] - public void Zip_PPMd_Read() - { - Read("Zip.ppmd.zip", CompressionType.PPMd); - } + public void Zip_PPMd_Read() => Read("Zip.ppmd.zip", CompressionType.PPMd); [Fact] - public void Zip_None_Read() - { - Read("Zip.none.zip", CompressionType.None); - } + public void Zip_None_Read() => Read("Zip.none.zip", CompressionType.None); [Fact] - public void Zip_Deflate_NoEmptyDirs_Read() - { + public void Zip_Deflate_NoEmptyDirs_Read() => Read("Zip.deflate.noEmptyDirs.zip", CompressionType.Deflate); - } [Fact] public void Zip_BZip2_PkwareEncryption_Read() @@ -211,8 +168,7 @@ public class ZipReaderTests : ReaderTests } [Fact] - public void Zip_LZMA_WinzipAES_Read() - { + public void Zip_LZMA_WinzipAES_Read() => Assert.Throws(() => { using ( @@ -236,7 +192,6 @@ public class ZipReaderTests : ReaderTests } VerifyFiles(); }); - } [Fact] public void Zip_Deflate_WinzipAES_Read() @@ -289,7 +244,7 @@ public class ZipReaderTests : ReaderTests [Fact] public void TestSharpCompressWithEmptyStream() { - var expected = new Tuple[] + var expected = new[] { new Tuple("foo.txt", Array.Empty()), new Tuple("foo2.txt", new byte[10]) @@ -332,16 +287,7 @@ public class ZipReaderTests : ReaderTests [Fact] public void Zip_None_Issue86_Streamed_Read() { - var keys = new string[] - { - "Empty1", - "Empty2", - "Dir1/", - "Dir2/", - "Fake1", - "Fake2", - "Internal.zip" - }; + var keys = new[] { "Empty1", "Empty2", "Dir1/", "Dir2/", "Fake1", "Fake2", "Internal.zip" }; using Stream stream = File.OpenRead( Path.Combine(TEST_ARCHIVES_PATH, "Zip.none.issue86.zip") @@ -365,7 +311,7 @@ public class ZipReaderTests : ReaderTests [Fact] public void Zip_ReaderMoveToNextEntry() { - var keys = new string[] { "version", "sizehint", "data/0/metadata", "data/0/records" }; + var keys = new[] { "version", "sizehint", "data/0/metadata", "data/0/records" }; using var fileStream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "test_477.zip")); using var reader = ZipReader.Open(fileStream); diff --git a/tests/SharpCompress.Test/Zip/ZipWriterTests.cs b/tests/SharpCompress.Test/Zip/ZipWriterTests.cs index b95efb81..d2224000 100644 --- a/tests/SharpCompress.Test/Zip/ZipWriterTests.cs +++ b/tests/SharpCompress.Test/Zip/ZipWriterTests.cs @@ -10,65 +10,53 @@ public class ZipWriterTests : WriterTests public ZipWriterTests() : base(ArchiveType.Zip) { } [Fact] - public void Zip_Deflate_Write() - { + public void Zip_Deflate_Write() => Write( CompressionType.Deflate, "Zip.deflate.noEmptyDirs.zip", "Zip.deflate.noEmptyDirs.zip", Encoding.UTF8 ); - } [Fact] - public void Zip_BZip2_Write() - { + public void Zip_BZip2_Write() => Write( CompressionType.BZip2, "Zip.bzip2.noEmptyDirs.zip", "Zip.bzip2.noEmptyDirs.zip", Encoding.UTF8 ); - } [Fact] - public void Zip_None_Write() - { + public void Zip_None_Write() => Write( CompressionType.None, "Zip.none.noEmptyDirs.zip", "Zip.none.noEmptyDirs.zip", Encoding.UTF8 ); - } [Fact] - public void Zip_LZMA_Write() - { + public void Zip_LZMA_Write() => Write( CompressionType.LZMA, "Zip.lzma.noEmptyDirs.zip", "Zip.lzma.noEmptyDirs.zip", Encoding.UTF8 ); - } [Fact] - public void Zip_PPMd_Write() - { + public void Zip_PPMd_Write() => Write( CompressionType.PPMd, "Zip.ppmd.noEmptyDirs.zip", "Zip.ppmd.noEmptyDirs.zip", Encoding.UTF8 ); - } [Fact] - public void Zip_Rar_Write() - { + public void Zip_Rar_Write() => Assert.Throws( () => Write(CompressionType.Rar, "Zip.ppmd.noEmptyDirs.zip", "Zip.ppmd.noEmptyDirs.zip") ); - } }