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..86e50978 100644 --- a/SharpCompress/Common/EntryStream.cs +++ b/SharpCompress/Common/EntryStream.cs @@ -1,16 +1,19 @@ using System; using System.IO; +using SharpCompress.Reader; namespace SharpCompress.Common { public class EntryStream : Stream { + public IReader Reader { get; private set; } private Stream stream; private bool completed; private bool isDisposed; - internal EntryStream(Stream stream) + internal EntryStream(IReader reader, Stream stream) { + this.Reader = reader; this.stream = stream; } @@ -28,10 +31,9 @@ namespace SharpCompress.Common protected override void Dispose(bool disposing) { - if (!completed) + if (!(completed || Reader.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..699770a3 100644 --- a/SharpCompress/Reader/AbstractReader.cs +++ b/SharpCompress/Reader/AbstractReader.cs @@ -67,12 +67,32 @@ namespace SharpCompress.Reader #endregion + + public bool Cancelled { get; private set; } + + /// + /// Indicates that the remaining entries are not required. + /// On dispose of an EntryStream, the stream will not skip to the end of the entry. + /// An attempt to move to the next entry will throw an exception, as the compressed stream is not positioned at an entry boundary. + /// + public void Cancel() + { + if (!completed) + { + Cancelled = true; + } + } + public bool MoveToNextEntry() { if (completed) { return false; } + if (Cancelled) + { + throw new InvalidOperationException("Reader has been cancelled."); + } if (entriesForCurrentReadStream == null) { return LoadStreamForReading(RequestInitialStream()); @@ -197,9 +217,17 @@ namespace SharpCompress.Reader return stream; } + /// + /// Retains a reference to the entry stream, so we can check whether it completed later. + /// + protected EntryStream CreateEntryStream(Stream decompressed) + { + return new EntryStream(this, decompressed); + } + protected virtual EntryStream GetEntryStream() { - return new EntryStream(Entry.Parts.First().GetCompressedStream()); + return CreateEntryStream(Entry.Parts.First().GetCompressedStream()); } #endregion diff --git a/SharpCompress/Reader/IReader.cs b/SharpCompress/Reader/IReader.cs index 769c1741..cf26ea16 100644 --- a/SharpCompress/Reader/IReader.cs +++ b/SharpCompress/Reader/IReader.cs @@ -22,6 +22,9 @@ namespace SharpCompress.Reader /// void WriteEntryTo(Stream writableStream); + bool Cancelled { get; } + void Cancel(); + /// /// Moves to the next entry by reading more data from the underlying stream. This skips if data has not been read. /// 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))); }