From b91289d82c732e50c8554d051726027c889cd476 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Sat, 1 Aug 2026 13:25:08 +0100 Subject: [PATCH] add large file tests and GZip/Lzw factory fixes --- src/SharpCompress/Factories/GZipFactory.cs | 12 +- src/SharpCompress/Factories/LzwFactory.cs | 12 +- tests/SharpCompress.Test/LargeArchiveTests.cs | 187 ++++++++++++++++++ tests/TestArchives/Archives/Large/Large.7z | Bin 0 -> 10012 bytes tests/TestArchives/Archives/Large/Large.gz | Bin 0 -> 162850 bytes tests/TestArchives/Archives/Large/Large.rar | Bin 0 -> 3147 bytes .../TestArchives/Archives/Large/Large.tar.gz | Bin 0 -> 163062 bytes tests/TestArchives/Archives/Large/Large.zip | Bin 0 -> 162830 bytes tests/TestArchives/Archives/Large/README.md | 38 ++++ 9 files changed, 241 insertions(+), 8 deletions(-) create mode 100644 tests/SharpCompress.Test/LargeArchiveTests.cs create mode 100644 tests/TestArchives/Archives/Large/Large.7z create mode 100644 tests/TestArchives/Archives/Large/Large.gz create mode 100644 tests/TestArchives/Archives/Large/Large.rar create mode 100644 tests/TestArchives/Archives/Large/Large.tar.gz create mode 100644 tests/TestArchives/Archives/Large/Large.zip create mode 100644 tests/TestArchives/Archives/Large/README.md diff --git a/src/SharpCompress/Factories/GZipFactory.cs b/src/SharpCompress/Factories/GZipFactory.cs index bda6ef1f..4649f0fc 100644 --- a/src/SharpCompress/Factories/GZipFactory.cs +++ b/src/SharpCompress/Factories/GZipFactory.cs @@ -151,13 +151,16 @@ public class GZipFactory CompressionContext.FromStream(sharpCompressStream).WithReaderOptions(options) ) ); - if (TarArchive.IsTarFile(testStream)) + var isTarArchive = TarArchive.IsTarFile(testStream); + + // The TAR probe can consume arbitrary compressed input before it rejects a stream. + sharpCompressStream.Rewind(); + sharpCompressStream.StopRecording(); + if (isTarArchive) { - sharpCompressStream.StopRecording(); reader = new TarReader(sharpCompressStream, options, CompressionType.GZip); return true; } - sharpCompressStream.StopRecording(); reader = OpenReader(sharpCompressStream, options); return true; } @@ -185,12 +188,13 @@ public class GZipFactory var tarReader = await new TarFactory() .TryOpenReaderAsync(sharpCompressStream, options, cancellationToken) .ConfigureAwait(false); + sharpCompressStream.Rewind(); + sharpCompressStream.StopRecording(); if (tarReader is not null) { return tarReader; } - sharpCompressStream.StopRecording(); return await OpenAsyncReader(sharpCompressStream, options, cancellationToken) .ConfigureAwait(false); } diff --git a/src/SharpCompress/Factories/LzwFactory.cs b/src/SharpCompress/Factories/LzwFactory.cs index bd5569d1..da475d8a 100644 --- a/src/SharpCompress/Factories/LzwFactory.cs +++ b/src/SharpCompress/Factories/LzwFactory.cs @@ -65,14 +65,17 @@ public class LzwFactory : Factory, IReaderFactory ) ) { - if (TarArchive.IsTarFile(testStream)) + var isTarArchive = TarArchive.IsTarFile(testStream); + + // The TAR probe can consume arbitrary compressed input before it rejects a stream. + sharpCompressStream.Rewind(); + sharpCompressStream.StopRecording(); + if (isTarArchive) { - sharpCompressStream.StopRecording(); reader = new TarReader(sharpCompressStream, options, CompressionType.Lzw); return true; } } - sharpCompressStream.StopRecording(); reader = OpenReader(sharpCompressStream, options); return true; } @@ -100,12 +103,13 @@ public class LzwFactory : Factory, IReaderFactory var tarReader = await new TarFactory() .TryOpenReaderAsync(sharpCompressStream, options, cancellationToken) .ConfigureAwait(false); + sharpCompressStream.Rewind(); + sharpCompressStream.StopRecording(); if (tarReader is not null) { return tarReader; } - sharpCompressStream.StopRecording(); return await OpenAsyncReader(sharpCompressStream, options, cancellationToken) .ConfigureAwait(false); } diff --git a/tests/SharpCompress.Test/LargeArchiveTests.cs b/tests/SharpCompress.Test/LargeArchiveTests.cs new file mode 100644 index 00000000..fc94c935 --- /dev/null +++ b/tests/SharpCompress.Test/LargeArchiveTests.cs @@ -0,0 +1,187 @@ +using System; +using System.IO; +using System.IO.Compression; +using System.Linq; +using System.Threading.Tasks; +using SharpCompress.Archives; +using SharpCompress.Crypto; +using SharpCompress.Readers; +using SharpCompress.Test.Mocks; +using Xunit; + +namespace SharpCompress.Test; + +[Collection(LargeArchiveCollection.Name)] +public class LargeArchiveTests : TestBase +{ + private const long LargeFileSize = 64L * 1024 * 1024; + private const uint LargeFileCrc = 0xF9081EB0; + private const int BufferSize = 64 * 1024; + + [Theory] + [InlineData("Large/Large.zip")] + [InlineData("Large/Large.tar")] + [InlineData("Large/Large.gz")] + [InlineData("Large/Large.rar")] + [InlineData("Large/Large.7z")] + public void OpenArchive_ShouldStreamLargeEntry(string fixtureName) + { + using var stream = File.OpenRead(GetArchiveFixturePath(fixtureName)); + using var archive = ArchiveFactory.OpenArchive(stream); + + VerifyArchive(archive); + } + + [Theory] + [InlineData("Large/Large.zip")] + [InlineData("Large/Large.tar")] + [InlineData("Large/Large.gz")] + [InlineData("Large/Large.rar")] + [InlineData("Large/Large.7z")] + public async Task OpenAsyncArchive_ShouldStreamLargeEntry(string fixtureName) + { + await using var stream = new AsyncOnlyStream( + File.OpenRead(await GetArchiveFixturePathAsync(fixtureName)) + ); + await using var archive = await ArchiveFactory.OpenAsyncArchive(stream); + + var entry = await GetSingleEntryAsync(archive); + await using var entryStream = await entry.OpenEntryStreamAsync(); + await VerifyContentAsync(entry.Key, entryStream); + } + + [Theory] + [InlineData("Large/Large.zip")] + [InlineData("Large/Large.tar")] + [InlineData("Large/Large.gz")] + [InlineData("Large/Large.rar")] + [InlineData("Large/Large.tar.gz")] + public void OpenReader_ShouldStreamLargeEntry(string fixtureName) + { + using var stream = File.OpenRead(GetFixturePath(fixtureName)); + using var reader = ReaderFactory.OpenReader(stream); + + VerifyReader(reader); + } + + [Theory] + [InlineData("Large/Large.zip")] + [InlineData("Large/Large.tar")] + [InlineData("Large/Large.gz")] + [InlineData("Large/Large.rar")] + [InlineData("Large/Large.tar.gz")] + public async Task OpenAsyncReader_ShouldStreamLargeEntry(string fixtureName) + { + await using var stream = new AsyncOnlyStream(File.OpenRead(GetFixturePath(fixtureName))); + await using var reader = await ReaderFactory.OpenAsyncReader(stream); + + Assert.True(await reader.MoveToNextEntryAsync()); + Assert.False(reader.Entry.IsDirectory); + await using var entryStream = await reader.OpenEntryStreamAsync(); + await VerifyContentAsync(reader.Entry.Key, entryStream); + Assert.False(await reader.MoveToNextEntryAsync()); + } + + private static string GetFixturePath(string fixtureName) => + Path.Combine(TEST_ARCHIVES_PATH, fixtureName); + + private string GetArchiveFixturePath(string fixtureName) => + fixtureName == "Large/Large.tar" ? MaterializeTarFixture() : GetFixturePath(fixtureName); + + private async Task GetArchiveFixturePathAsync(string fixtureName) => + fixtureName == "Large/Large.tar" + ? await MaterializeTarFixtureAsync() + : GetFixturePath(fixtureName); + + private string MaterializeTarFixture() + { + var tarPath = Path.Combine(SCRATCH_FILES_PATH, "Large.tar"); + using var compressedStream = File.OpenRead(GetFixturePath("Large/Large.tar.gz")); + using var gzipStream = new GZipStream(compressedStream, CompressionMode.Decompress); + using var tarStream = File.Create(tarPath); + gzipStream.CopyTo(tarStream); + return tarPath; + } + + private async Task MaterializeTarFixtureAsync() + { + var tarPath = Path.Combine(SCRATCH_FILES_PATH, "Large.tar"); + using var compressedStream = File.OpenRead(GetFixturePath("Large/Large.tar.gz")); + using var gzipStream = new GZipStream(compressedStream, CompressionMode.Decompress); + using var tarStream = File.Create(tarPath); + await gzipStream.CopyToAsync(tarStream); + return tarPath; + } + + private static void VerifyArchive(IArchive archive) + { + var entry = Assert.Single(archive.Entries); + + Assert.False(entry.IsDirectory); + using var entryStream = entry.OpenEntryStream(); + VerifyContent(entry.Key, entryStream); + } + + private static async Task GetSingleEntryAsync(IAsyncArchive archive) + { + IArchiveEntry? entry = null; + await foreach (var candidate in archive.EntriesAsync) + { + Assert.Null(entry); + entry = candidate; + } + + return entry ?? throw new InvalidOperationException("The archive contains no entries."); + } + + private static void VerifyReader(IReader reader) + { + Assert.True(reader.MoveToNextEntry()); + Assert.False(reader.Entry.IsDirectory); + using var entryStream = reader.OpenEntryStream(); + VerifyContent(reader.Entry.Key, entryStream); + Assert.False(reader.MoveToNextEntry()); + } + + private static void VerifyContent(string? key, Stream entryStream) + { + Assert.Equal("large.bin", key); + + using var crcStream = new Crc32Stream(Stream.Null); + var buffer = new byte[BufferSize]; + long length = 0; + int bytesRead; + while ((bytesRead = entryStream.Read(buffer, 0, buffer.Length)) > 0) + { + crcStream.Write(buffer, 0, bytesRead); + length += bytesRead; + } + + Assert.Equal(LargeFileSize, length); + Assert.Equal(LargeFileCrc, crcStream.Crc); + } + + private static async Task VerifyContentAsync(string? key, Stream entryStream) + { + Assert.Equal("large.bin", key); + + using var crcStream = new Crc32Stream(Stream.Null); + var buffer = new byte[BufferSize]; + long length = 0; + int bytesRead; + while ((bytesRead = await entryStream.ReadAsync(buffer, 0, buffer.Length)) > 0) + { + await crcStream.WriteAsync(buffer, 0, bytesRead); + length += bytesRead; + } + + Assert.Equal(LargeFileSize, length); + Assert.Equal(LargeFileCrc, crcStream.Crc); + } +} + +[CollectionDefinition(LargeArchiveCollection.Name, DisableParallelization = true)] +public sealed class LargeArchiveCollection +{ + public const string Name = "Large archive fixtures"; +} diff --git a/tests/TestArchives/Archives/Large/Large.7z b/tests/TestArchives/Archives/Large/Large.7z new file mode 100644 index 0000000000000000000000000000000000000000..719ea18df023e2174e0eab883ff7aaf94708504b GIT binary patch literal 10012 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 F1ps&6m3ROE literal 0 HcmV?d00001 diff --git a/tests/TestArchives/Archives/Large/Large.rar b/tests/TestArchives/Archives/Large/Large.rar new file mode 100644 index 0000000000000000000000000000000000000000..6f0a65d484263ea26b0589e8bb2b542e390d6d8b GIT binary patch literal 3147 zcmWGaEK-zWXJlYm*eb}&$jZsU!N}ME0t}%urxvO+G5ww1(9poZ*3i(fpn+jYGZVu@ z?zjzd96uXe898$ji_%l|k}~r;S?_WiyM9#u8eqIH(M{jLv(bz5!;~%#g^7DRe>F>M zyjwr{daT~OfAx8B`|t1B`SIoD_UHTU=h@iV{jUG|@!!1raaR8&7#J9&kJk4vFfg$G zGhkp~5dU$2fq^0ZF#`hwMua<%=x literal 0 HcmV?d00001 diff --git a/tests/TestArchives/Archives/Large/Large.tar.gz b/tests/TestArchives/Archives/Large/Large.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..007fef083fe9e4d65cac12d5c3639a5659ff8303 GIT binary patch literal 163062 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 bj+TU@B_UNx!tIred7_sW+AA_}F|YstBaSne literal 0 HcmV?d00001 diff --git a/tests/TestArchives/Archives/Large/Large.zip b/tests/TestArchives/Archives/Large/Large.zip new file mode 100644 index 0000000000000000000000000000000000000000..5b07336fde030aff7517df489d4596cddafca01f GIT binary patch literal 162830 zcmWIWW@Zs#U}E54U|>)T*dWL8b5=DI0|NsC3nv2uLr!8*da7PhX5O2Vr+FI`L>M;g z4&KnMY{AI>M@8x+v+(xgjydaPnHhe}wz?nQdnwAQI7fBu@!Rt?E^m5XaL)4ioZ?Yp zGz>=5!Du!ZEeb|U!qJj&v?LrY2}eu9(UNeqBpfXXM@z!dl5n&n94!e)OTy8TaI_>G zEeS_U!qJj&v?LrY2}eu9(UNeqBpfXXM@z!dl5n&n94!e)OTy8TaI_>GEeS_U!qJj& zv?LrY2}eu9(UNeqBpfXXM@z!dl5n&n94!e)OTy8TaI_>GEeS_U!qJj&v?LrY2}eu9 z(UNeqBpfXXM@z!dl5n&n94!e)OTy8TaI_>GEeS_U!qJj&v?LrY2}eu9(UNeqBpfXX zM@z!dl8_oDp?r0b2k5{+hA02C-B;YJe!utoC@~raqv>EY8;lkOqb1>JNjO>(j+TU@ zCE;jEI9d{pmV~1v;b=)XS`vJNjO>(j+TU@CE;jEI9d{p zmV~1v;b=)XS`vJNjO>(j+TU@CE;jEI9d{pmV~1v;b=)X zS`vJNjO>(j+TU@CE;jEI9d{pmV~1v;b=)XS`vJNjO>(j+TU@CE;jEI9d{pmV~1v;b=)n%aX9&)=~w07~rS>Ta`m- zY13#tj)v}NjW$}Njn-(RCE;jEI9d{pmV~1v;b=)XS`vJ zNjO>(j+TU@CE;jEI9d{pmV~1v;b=)XS`vJNjO>(j+TU@ zCE;jEI9d{pmV~1v;b=)XS`vJNjO>(j+TU@CE;jEI9d{p zmV~1v;b=)XS`vJNjO>(j+TU@CE;jEI9d{pmV~1v;b=)X zS`vGEeS_U!qJj&v?LrY2}iTRXh}F)5{{OHqb1>JNjO>(j+TU@CE;jE zI9d{pmV~1v;b=)XS`vJNjO>(j+TU@CE;jEI9d{pmV~1v z;b=)XS`vJNjO>(j+TU@CE;jEI9d{pmV~1v;b=)XS`vJNjO>(j+TU@CE;jEI9d{pmV~1vAuUV7M1MX`&|!cLf9l_I zT&1N=qwzQzx}!DPXpJ^nqm7n?qb1>JNjO>(j+TU@CE;jEI9d{pmV~1v;b=)XS`vJNjO>(j+TU@CE;jEI9d{pmV~1v;b=)XS`vJNjO>(j+TU@CE;jEI9d{pmV~1v;b=)XS`vJ zNjO>(j+TU@CE;jEI9d{pmV~1v;b=)XS`vJNjO>(j+TU@CE;jEI9d{pmV~1v z;b=)XS`vJNjO>(j+TU@CE;jEI9d{pmV~1v;b=)XS`vJNjO>(j+TU@CE;jEI9d{pmV~1v;b=)XS`vJNjO>(j+TU@CE;jEI9d{pmV~1v;b=)XS`vGEeS_U!qJj&v?LrY2}eu9(UNeq zBpfXXM@z!dl5n&n94!e)OTy8TaI_>GEeS_U!qJj&v?LrY2}eu9(UNeqBpl5Kqb1>J zNjO>(j+TU@CE;jEI9d{pmV~1v;b=)XS`vJNjO>(j+TU@ zCE;jEI9d{pmV~1v;b=)XS`vJNjO>(j+TU@CE;jEI9d{p zmV~1v;b=)XS`vGEeS_U!qJj&v?LrY2}eu9(UNeq zBpfXXM@z!dl5n&n94!e)OTy8TaI_>GEeS_U!qJj&v?LrY2}eu9(UNeqBpfXXM@z!d zl5n&n94!e)OTy8TaI_>GEeS_U!qJj&v?LrY2}eu9(UNeqBpfXXM@z!dl5n&n94!e) zOTy8TaI_>GEeS_U!qJj&v?LrY2}eu9(UNeqBpfXXM@zy%QWDM+5AbGWl4BNOU}E54 zU|>)T*dWL8b5=DI0|NsC3nz$VU|?WmU|?9%2;$@<7Nw`^C1vIXc(byB1Q;0@8O#|N J7!HE9002S{jOhRX literal 0 HcmV?d00001 diff --git a/tests/TestArchives/Archives/Large/README.md b/tests/TestArchives/Archives/Large/README.md new file mode 100644 index 00000000..4992f31b --- /dev/null +++ b/tests/TestArchives/Archives/Large/README.md @@ -0,0 +1,38 @@ +# Large Test Archives + +Each fixture contains one `large.bin` entry with a 67,108,864-byte (64 MiB) +deterministic, repeated text pattern with a 2 KiB `0xFF` prefix. The entry CRC-32 is +`f9081eb0`. + +| Fixture | Archive API | Reader API | +| --- | --- | --- | +| `Large.zip` | Yes | Yes | +| Generated `Large.tar` | Yes | N/A | +| `Large.gz` | Yes | Yes | +| `Large.rar` | Yes | Yes | +| `Large.7z` | Yes | No | +| `Large.tar.gz` | No | Yes | + +The compressible payload keeps the compressed fixtures small while requiring a full +64 MiB decompression to validate each API. The Archive API test expands `Large.tar.gz` +to a scratch `Large.tar` before exercising raw TAR support, so the 64 MiB TAR file is +not committed. + +## Regenerating + +The fixtures were created with `zip`, `tar`, `gzip`, RAR 7.22, and 7-Zip. Run these +commands from a temporary directory after replacing `` with the repository root: + +```sh +yes "SharpCompress large fixture" | head -c 67108864 > large.bin +printf '\377%.0s' {1..2048} > prefix.bin +dd if=prefix.bin of=large.bin bs=2048 count=1 conv=notrunc +touch -t 202001010000 large.bin +mkdir -p /tests/TestArchives/Archives/Large +zip -X -9 -j /tests/TestArchives/Archives/Large/Large.zip large.bin +COPYFILE_DISABLE=1 tar -cf large.tar large.bin +gzip -9 -c large.bin > /tests/TestArchives/Archives/Large/Large.gz +gzip -n -9 -c large.tar > /tests/TestArchives/Archives/Large/Large.tar.gz +rar a -ma5 -m5 -ep /tests/TestArchives/Archives/Large/Large.rar large.bin +7z a -t7z -mx=9 /tests/TestArchives/Archives/Large/Large.7z large.bin +```