From 44a5433af34737e93e78f1322e88d4d64d5384cf Mon Sep 17 00:00:00 2001 From: Lars Vahlenberg Date: Thu, 4 Aug 2022 21:22:31 +0200 Subject: [PATCH] 64bit DataDescriptor --- .../Common/Zip/StreamingZipFilePart.cs | 23 ++++++++++-- .../Common/Zip/StreamingZipHeaderFactory.cs | 33 +++++++++++++++--- src/SharpCompress/IO/SourceStream.cs | 4 ++- .../SharpCompress.Test/Zip/ZipReaderTests.cs | 23 ++++++++++-- .../TestArchives/Archives/64bitstream.zip.7z | Bin 0 -> 643195 bytes 5 files changed, 72 insertions(+), 11 deletions(-) create mode 100644 tests/TestArchives/Archives/64bitstream.zip.7z diff --git a/src/SharpCompress/Common/Zip/StreamingZipFilePart.cs b/src/SharpCompress/Common/Zip/StreamingZipFilePart.cs index 9b333038..ee0c6be9 100644 --- a/src/SharpCompress/Common/Zip/StreamingZipFilePart.cs +++ b/src/SharpCompress/Common/Zip/StreamingZipFilePart.cs @@ -47,6 +47,9 @@ namespace SharpCompress.Common.Zip { _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); @@ -66,12 +69,26 @@ namespace SharpCompress.Common.Zip br.ReadUInt32(); // CRC32 var compressed_size = br.ReadUInt32(); var uncompressed_size = br.ReadUInt32(); - if (compressed_size == size && compressed_size == uncompressed_size ) + var uncompressed_64bit = br.ReadInt64(); + + long test_64bit = (long)uncompressed_size << 32 | (long)compressed_size; + + if( test_64bit == size && test_64bit == uncompressed_64bit ) { - rewindableStream.Position -= 16; + Header.CompressedSize = test_64bit; + Header.UncompressedSize = uncompressed_64bit; + rewindableStream.Position -= 24; break; } - rewindableStream.Position -= 12; + + if (compressed_size == size && compressed_size == uncompressed_size ) + { + Header.CompressedSize = compressed_size; + Header.UncompressedSize = uncompressed_size; + rewindableStream.Position -= 24; + break; + } + rewindableStream.Position -= 20; } } diff --git a/src/SharpCompress/Common/Zip/StreamingZipHeaderFactory.cs b/src/SharpCompress/Common/Zip/StreamingZipHeaderFactory.cs index 3c273e32..836fb039 100644 --- a/src/SharpCompress/Common/Zip/StreamingZipHeaderFactory.cs +++ b/src/SharpCompress/Common/Zip/StreamingZipHeaderFactory.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.IO; using SharpCompress.Common.Zip.Headers; using SharpCompress.IO; @@ -28,6 +28,7 @@ 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)) { @@ -39,15 +40,37 @@ namespace SharpCompress.Common.Zip crc = reader.ReadUInt32(); } _lastEntryHeader.Crc = crc; - _lastEntryHeader.CompressedSize = reader.ReadUInt32(); - _lastEntryHeader.UncompressedSize = 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 + 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 = null; - uint headerBytes = reader.ReadUInt32(); header = ReadHeader(headerBytes, reader); if (header is null) { @@ -86,4 +109,4 @@ namespace SharpCompress.Common.Zip } } } -} \ No newline at end of file +} diff --git a/src/SharpCompress/IO/SourceStream.cs b/src/SharpCompress/IO/SourceStream.cs index 71918c81..22e44b22 100644 --- a/src/SharpCompress/IO/SourceStream.cs +++ b/src/SharpCompress/IO/SourceStream.cs @@ -143,9 +143,11 @@ namespace SharpCompress.IO if (!IsVolumes && count != 0 && Current.Position == Current.Length) { - _prevSize += Current.Length; + var length = Current.Length; + if (!SetStream(_stream + 1)) //will load next file if present break; + _prevSize += length; Current.Seek(0, SeekOrigin.Begin); } } diff --git a/tests/SharpCompress.Test/Zip/ZipReaderTests.cs b/tests/SharpCompress.Test/Zip/ZipReaderTests.cs index 89cc4c13..65ae9326 100644 --- a/tests/SharpCompress.Test/Zip/ZipReaderTests.cs +++ b/tests/SharpCompress.Test/Zip/ZipReaderTests.cs @@ -401,8 +401,6 @@ namespace SharpCompress.Test.Zip } } - - [Fact] public void Zip_Uncompressed_Skip_All() { @@ -415,5 +413,26 @@ namespace SharpCompress.Test.Zip } } } + + [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/TestArchives/Archives/64bitstream.zip.7z b/tests/TestArchives/Archives/64bitstream.zip.7z new file mode 100644 index 0000000000000000000000000000000000000000..18b942c11cfcb8d7e07d1209fad5156e743baae1 GIT binary patch literal 643195 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 literal 0 HcmV?d00001