diff --git a/src/SharpCompress/Archives/SevenZip/SevenZipArchive.cs b/src/SharpCompress/Archives/SevenZip/SevenZipArchive.cs index d9b5ba1a..43618dbc 100644 --- a/src/SharpCompress/Archives/SevenZip/SevenZipArchive.cs +++ b/src/SharpCompress/Archives/SevenZip/SevenZipArchive.cs @@ -212,10 +212,31 @@ public class SevenZipArchive : AbstractArchive _database?._packSizes.Aggregate(0L, (total, packSize) => total + packSize) ?? 0; - private sealed class SevenZipReader : AbstractReader + internal sealed class SevenZipReader : AbstractReader { private readonly SevenZipArchive _archive; private SevenZipEntry? _currentEntry; + private Stream? _currentFolderStream; + private CFolder? _currentFolder; + + /// + /// Enables internal diagnostics for tests. + /// When disabled (default), diagnostics properties return null to avoid exposing internal state. + /// + internal bool DiagnosticsEnabled { get; set; } + + /// + /// Current folder instance used to decide whether the solid folder stream should be reused. + /// Only available when is true. + /// + internal object? DiagnosticsCurrentFolder => DiagnosticsEnabled ? _currentFolder : null; + + /// + /// Current shared folder stream instance. + /// Only available when is true. + /// + internal Stream? DiagnosticsCurrentFolderStream => + DiagnosticsEnabled ? _currentFolderStream : null; internal SevenZipReader(ReaderOptions readerOptions, SevenZipArchive archive) : base(readerOptions, ArchiveType.SevenZip) => this._archive = archive; @@ -231,9 +252,10 @@ public class SevenZipArchive : AbstractArchive !x.IsDirectory)) { _currentEntry = entry; @@ -243,19 +265,53 @@ public class SevenZipArchive : AbstractArchive(reader); + sevenZipReader.DiagnosticsEnabled = true; + + Stream? currentFolderStreamInstance = null; + object? currentFolder = null; + var entryCount = 0; + var entriesInCurrentFolder = 0; + var streamRecreationsWithinFolder = 0; + + while (reader.MoveToNextEntry()) + { + if (!reader.Entry.IsDirectory) + { + // Extract the entry to trigger GetEntryStream + using var entryStream = reader.OpenEntryStream(); + var buffer = new byte[4096]; + while (entryStream.Read(buffer, 0, buffer.Length) > 0) + { + // Read the stream to completion + } + + entryCount++; + + var folderStream = sevenZipReader.DiagnosticsCurrentFolderStream; + var folder = sevenZipReader.DiagnosticsCurrentFolder; + + Assert.NotNull(folderStream); // Folder stream should exist + + // Check if we're in a new folder + if (currentFolder == null || !ReferenceEquals(currentFolder, folder)) + { + // Starting a new folder + currentFolder = folder; + currentFolderStreamInstance = folderStream; + entriesInCurrentFolder = 1; + } + else + { + // Same folder - verify stream wasn't recreated + entriesInCurrentFolder++; + + if (!ReferenceEquals(currentFolderStreamInstance, folderStream)) + { + // Stream was recreated within the same folder - this is the bug we're testing for! + streamRecreationsWithinFolder++; + } + + currentFolderStreamInstance = folderStream; + } + } + } + + // Verify we actually tested multiple entries + Assert.True(entryCount > 1, "Test should have multiple entries to verify stream reuse"); + + // The critical check: within a single folder, the stream should NEVER be recreated + Assert.Equal(0, streamRecreationsWithinFolder); // Folder stream should remain the same for all entries in the same folder + } }