diff --git a/src/SharpCompress/Archives/SevenZip/SevenZipArchive.cs b/src/SharpCompress/Archives/SevenZip/SevenZipArchive.cs index de0adc98b..cc95f673d 100644 --- a/src/SharpCompress/Archives/SevenZip/SevenZipArchive.cs +++ b/src/SharpCompress/Archives/SevenZip/SevenZipArchive.cs @@ -162,6 +162,15 @@ protected override EntryStream GetEntryStream() return CreateEntryStream(Stream.Null); } + // 7z may contain valid "empty stream" file entries (HasStream == false). + // These entries represent zero-byte files and do not have folder mapping. + // Returning Stream.Null keeps extraction behavior correct and avoids + // null-folder dereference when requesting a folder stream. + if (!entry.FilePart.Header.HasStream) + { + return CreateEntryStream(Stream.Null); + } + var folder = entry.FilePart.Folder; // Check if we're starting a new folder - dispose old folder stream if needed diff --git a/tests/SharpCompress.Test/SevenZip/SevenZipArchiveTests.cs b/tests/SharpCompress.Test/SevenZip/SevenZipArchiveTests.cs index ea9316e57..dfbf7881e 100644 --- a/tests/SharpCompress.Test/SevenZip/SevenZipArchiveTests.cs +++ b/tests/SharpCompress.Test/SevenZip/SevenZipArchiveTests.cs @@ -132,6 +132,33 @@ public void SevenZipArchive_BZip2_Split_FirstFileRead() => [Fact] public void SevenZipArchive_Copy_PathRead() => ArchiveFileRead("7Zip.Copy.7z"); + [Fact] + public void SevenZipArchive_EmptyStream_WriteToDirectory_DoesNotThrow() + { + var archivePath = Path.Combine(TEST_ARCHIVES_PATH, "7Zip.EmptyStream.7z"); + var outputPath = Path.Combine( + SCRATCH_FILES_PATH, + nameof(SevenZipArchive_EmptyStream_WriteToDirectory_DoesNotThrow)); + + if (Directory.Exists(outputPath)) + { + Directory.Delete(outputPath, true); + } + + Directory.CreateDirectory(outputPath); + + using var archive = SevenZipArchive.OpenArchive(archivePath); + var progress = new Progress(_ => { }); + + var ex = Record.Exception(() => archive.WriteToDirectory(outputPath, progress)); + + Assert.Null(ex); + + var files = Directory.GetFiles(outputPath, "*", SearchOption.AllDirectories); + Assert.NotEmpty(files); + Assert.Contains(files, p => new FileInfo(p).Length == 0); + } + [Fact] public void SevenZipArchive_Copy_CompressionType() { diff --git a/tests/TestArchives/Archives/7Zip.EmptyStream.7z b/tests/TestArchives/Archives/7Zip.EmptyStream.7z new file mode 100644 index 000000000..c2d9bfa43 Binary files /dev/null and b/tests/TestArchives/Archives/7Zip.EmptyStream.7z differ