diff --git a/SharpCompress/Archive/SevenZip/SevenZipArchive.cs b/SharpCompress/Archive/SevenZip/SevenZipArchive.cs index 14792f67..3af441e0 100644 --- a/SharpCompress/Archive/SevenZip/SevenZipArchive.cs +++ b/SharpCompress/Archive/SevenZip/SevenZipArchive.cs @@ -236,7 +236,7 @@ namespace SharpCompress.Archive.SevenZip protected override EntryStream GetEntryStream() { - return new EntryStream(new ReadOnlySubStream(currentStream, currentItem.Size)); + return CreateEntryStream(new ReadOnlySubStream(currentStream, currentItem.Size)); } } } diff --git a/SharpCompress/Common/EntryStream.cs b/SharpCompress/Common/EntryStream.cs index 606bb160..a14bbbbb 100644 --- a/SharpCompress/Common/EntryStream.cs +++ b/SharpCompress/Common/EntryStream.cs @@ -26,12 +26,27 @@ namespace SharpCompress.Common completed = true; } + public bool Cancelled { get; private set; } + + /// + /// Indicates that the remainder of the stream is not required. + /// On dispose, the entry will not be skipped, so it helps with efficiency. + /// The downside is that subsequent entries are not usable, as the compressed stream is not positioned at an entry boundary. + /// + public void Cancel() + { + if (!completed) + { + Cancelled = true; + stream.Close(); + } + } + protected override void Dispose(bool disposing) { - if (!completed) + if (!(completed || Cancelled)) { - throw new InvalidOperationException( - "EntryStream has not been fully consumed. Read the entire stream or use SkipEntry."); + SkipEntry(); } if (isDisposed) { diff --git a/SharpCompress/Reader/AbstractReader.cs b/SharpCompress/Reader/AbstractReader.cs index 0c98e032..bd940ce8 100644 --- a/SharpCompress/Reader/AbstractReader.cs +++ b/SharpCompress/Reader/AbstractReader.cs @@ -77,6 +77,12 @@ namespace SharpCompress.Reader { return LoadStreamForReading(RequestInitialStream()); } + + if (currentEntryStream != null && currentEntryStream.Cancelled) + { + throw new InvalidOperationException("EntryStream has not been fully consumed. Read the entire stream or use SkipEntry."); + } + if (!wroteCurrentEntry) { SkipEntry(); @@ -197,9 +203,19 @@ namespace SharpCompress.Reader return stream; } + private EntryStream currentEntryStream; + + /// + /// Retains a reference to the entry stream, so we can check whether it completed later. + /// + protected EntryStream CreateEntryStream(Stream decompressed) + { + return currentEntryStream = new EntryStream(decompressed); + } + protected virtual EntryStream GetEntryStream() { - return new EntryStream(Entry.Parts.First().GetCompressedStream()); + return CreateEntryStream(Entry.Parts.First().GetCompressedStream()); } #endregion diff --git a/SharpCompress/Reader/Rar/RarReader.cs b/SharpCompress/Reader/Rar/RarReader.cs index 68ee8b2f..58a1be35 100644 --- a/SharpCompress/Reader/Rar/RarReader.cs +++ b/SharpCompress/Reader/Rar/RarReader.cs @@ -73,7 +73,7 @@ namespace SharpCompress.Reader.Rar protected override EntryStream GetEntryStream() { - return new EntryStream(new RarStream(pack, Entry.FileHeader, + return CreateEntryStream(new RarStream(pack, Entry.FileHeader, new MultiVolumeReadOnlyStream( CreateFilePartEnumerableForCurrentEntry().Cast(), this))); }