From 71c8f3129f7443b6bb4eaef865bb7e2beb2844ea Mon Sep 17 00:00:00 2001 From: Craig Date: Wed, 27 Apr 2022 13:16:05 +0100 Subject: [PATCH] RarStream Position fix, it was returning the file size. 7Zip CrcCheckStream always failed. Added a Solid Rar entry CRC test. --- .../LZMA/Utilites/CrcCheckStream.cs | 16 ++++---- .../Compressors/Rar/RarStream.cs | 10 +++-- .../SharpCompress.Test/Rar/RarArchiveTests.cs | 40 ++++++++++++++++++- 3 files changed, 55 insertions(+), 11 deletions(-) diff --git a/src/SharpCompress/Compressors/LZMA/Utilites/CrcCheckStream.cs b/src/SharpCompress/Compressors/LZMA/Utilites/CrcCheckStream.cs index 04b00f81..1a4c354c 100644 --- a/src/SharpCompress/Compressors/LZMA/Utilites/CrcCheckStream.cs +++ b/src/SharpCompress/Compressors/LZMA/Utilites/CrcCheckStream.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Diagnostics; using System.IO; @@ -21,16 +21,17 @@ namespace SharpCompress.Compressors.LZMA.Utilites protected override void Dispose(bool disposing) { - if (_mCurrentCrc != _mExpectedCrc) - { - throw new InvalidOperationException(); - } + //Nanook - is not equal here - _mCurrentCrc is yet to be negated + //if (_mCurrentCrc != _mExpectedCrc) + //{ + // throw new InvalidOperationException(); + //} try { if (disposing && !_mClosed) { _mClosed = true; - _mCurrentCrc = Crc.Finish(_mCurrentCrc); + _mCurrentCrc = Crc.Finish(_mCurrentCrc); //now becomes equal #if DEBUG if (_mCurrentCrc == _mExpectedCrc) { @@ -40,6 +41,7 @@ namespace SharpCompress.Compressors.LZMA.Utilites { Debugger.Break(); Debug.WriteLine("bad CRC"); + throw new InvalidOperationException(); //moved exception to here } double lengthInv = 1.0 / _mLength; @@ -102,4 +104,4 @@ namespace SharpCompress.Compressors.LZMA.Utilites _mCurrentCrc = Crc.Update(_mCurrentCrc, buffer, offset, count); } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/Compressors/Rar/RarStream.cs b/src/SharpCompress/Compressors/Rar/RarStream.cs index 5e1cc12a..2ad3c9b8 100644 --- a/src/SharpCompress/Compressors/Rar/RarStream.cs +++ b/src/SharpCompress/Compressors/Rar/RarStream.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable using System; using System.IO; @@ -23,6 +23,7 @@ namespace SharpCompress.Compressors.Rar private int outCount; private int outTotal; private bool isDisposed; + private long _position; public RarStream(IRarUnpack unpack, FileHeader fileHeader, Stream readStream) { @@ -32,6 +33,7 @@ namespace SharpCompress.Compressors.Rar fetch = true; unpack.DoUnpack(fileHeader, readStream, this); fetch = false; + _position = 0; } protected override void Dispose(bool disposing) @@ -56,7 +58,8 @@ namespace SharpCompress.Compressors.Rar public override long Length => fileHeader.UncompressedSize; - public override long Position { get => fileHeader.UncompressedSize - unpack.DestSize; set => throw new NotSupportedException(); } + //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) { @@ -80,6 +83,7 @@ namespace SharpCompress.Compressors.Rar unpack.DoUnpack(); fetch = false; } + _position += (long)outTotal; return outTotal; } @@ -129,4 +133,4 @@ namespace SharpCompress.Compressors.Rar } } } -} \ No newline at end of file +} diff --git a/tests/SharpCompress.Test/Rar/RarArchiveTests.cs b/tests/SharpCompress.Test/Rar/RarArchiveTests.cs index f6bbb7a9..1373f884 100644 --- a/tests/SharpCompress.Test/Rar/RarArchiveTests.cs +++ b/tests/SharpCompress.Test/Rar/RarArchiveTests.cs @@ -1,8 +1,9 @@ -using System.IO; +using System.IO; using System.Linq; using SharpCompress.Archives; using SharpCompress.Archives.Rar; using SharpCompress.Common; +using SharpCompress.Compressors.LZMA.Utilites; using SharpCompress.Readers; using Xunit; @@ -203,6 +204,43 @@ namespace SharpCompress.Test.Rar 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); + if (entry == testEntry) + break; + } //throws if not valid + } + } + } + } + + [Fact] public void Rar_Solid_ArchiveStreamRead() {