From 5706732c55fff25f4f57b8b082c1fb89359ffd6c Mon Sep 17 00:00:00 2001 From: Lars Vahlenberg Date: Thu, 28 Jul 2022 23:03:06 +0200 Subject: [PATCH] Naive implementation of searching of DataDescriptor, not compatible with big archives (>32bit), but handles test cases. --- .../Common/Zip/StreamingZipFilePart.cs | 18 ++++++++++ src/SharpCompress/Utility.cs | 35 +++++++++++++++++++ .../SharpCompress.Test/Zip/ZipArchiveTests.cs | 4 +-- 3 files changed, 54 insertions(+), 3 deletions(-) diff --git a/src/SharpCompress/Common/Zip/StreamingZipFilePart.cs b/src/SharpCompress/Common/Zip/StreamingZipFilePart.cs index f287ab73..9b333038 100644 --- a/src/SharpCompress/Common/Zip/StreamingZipFilePart.cs +++ b/src/SharpCompress/Common/Zip/StreamingZipFilePart.cs @@ -55,6 +55,24 @@ internal BinaryReader FixStreamedFileLocation(ref RewindableStream rewindableStr 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(); + if (compressed_size == size && compressed_size == uncompressed_size ) + { + rewindableStream.Position -= 16; + break; + } + rewindableStream.Position -= 12; + } } Skipped = true; diff --git a/src/SharpCompress/Utility.cs b/src/SharpCompress/Utility.cs index ee732e8d..28979d9d 100644 --- a/src/SharpCompress/Utility.cs +++ b/src/SharpCompress/Utility.cs @@ -165,6 +165,41 @@ public static void Skip(this Stream source) } } + public static bool Find(this Stream source, byte[] array) + { + byte[] buffer = GetTransferByteArray(); + try + { + var pos = source.Position; + int count = 0; + var len = source.Read(buffer, 0, buffer.Length); + source.Position = pos + len; + + 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; diff --git a/tests/SharpCompress.Test/Zip/ZipArchiveTests.cs b/tests/SharpCompress.Test/Zip/ZipArchiveTests.cs index 67653e77..eb85da5e 100644 --- a/tests/SharpCompress.Test/Zip/ZipArchiveTests.cs +++ b/tests/SharpCompress.Test/Zip/ZipArchiveTests.cs @@ -751,9 +751,7 @@ public void Zip_Uncompressed_Skip_All() x++; } - // if we implement searching for DataDescriptor on none compressed streams - // this would work, see StreamingZipFilePart function FixStreamedFileLocation - // Assert.Equal(4, x); + Assert.Equal(4, x); } } }