-
Notifications
You must be signed in to change notification settings - Fork 510
Clean up again #1187
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Clean up again #1187
Changes from all commits
7231b7b
d26db95
d12b539
db54421
778a930
240468f
3fb8387
4e4de62
c21c7eb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,25 +5,25 @@ namespace SharpCompress.IO; | |
|
|
||
| internal sealed partial class SeekableSharpCompressStream : SharpCompressStream | ||
| { | ||
| public override Stream BaseStream() => _underlyingStream; | ||
| public override Stream BaseStream() => _stream; | ||
|
|
||
| private readonly Stream _underlyingStream; | ||
| private readonly Stream _stream; | ||
| private long? _recordedPosition; | ||
| private bool _isDisposed; | ||
|
|
||
| /// <summary> | ||
| /// Gets or sets whether to leave the underlying stream open when disposed. | ||
| /// </summary> | ||
| public new bool LeaveStreamOpen { get; set; } | ||
| public override bool LeaveStreamOpen { get; } | ||
|
|
||
| /// <summary> | ||
| /// Gets or sets whether to throw an exception when Dispose is called. | ||
| /// Useful for testing to ensure streams are not disposed prematurely. | ||
| /// </summary> | ||
| public new bool ThrowOnDispose { get; set; } | ||
| public override bool ThrowOnDispose { get; set; } | ||
|
|
||
| public SeekableSharpCompressStream(Stream stream) | ||
| : base(new NullStream()) | ||
| public SeekableSharpCompressStream(Stream stream, bool leaveStreamOpen = false) | ||
| : base(Null, true, false, null) | ||
adamhathcock marked this conversation as resolved.
Show resolved
Hide resolved
adamhathcock marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| { | ||
| if (stream is null) | ||
| { | ||
|
|
@@ -33,44 +33,45 @@ public SeekableSharpCompressStream(Stream stream) | |
| { | ||
| throw new ArgumentException("Stream must be seekable", nameof(stream)); | ||
| } | ||
| _underlyingStream = stream; | ||
|
|
||
| LeaveStreamOpen = leaveStreamOpen; | ||
|
Comment on lines
25
to
+37
|
||
| _stream = stream; | ||
| } | ||
|
|
||
| public override bool CanRead => _underlyingStream.CanRead; | ||
| public override bool CanRead => _stream.CanRead; | ||
|
|
||
| public override bool CanSeek => _underlyingStream.CanSeek; | ||
| public override bool CanSeek => _stream.CanSeek; | ||
|
|
||
| public override bool CanWrite => _underlyingStream.CanWrite; | ||
| public override bool CanWrite => _stream.CanWrite; | ||
|
|
||
| public override long Length => _underlyingStream.Length; | ||
| public override long Length => _stream.Length; | ||
|
|
||
| public override long Position | ||
| { | ||
| get => _underlyingStream.Position; | ||
| set => _underlyingStream.Position = value; | ||
| get => _stream.Position; | ||
| set => _stream.Position = value; | ||
| } | ||
|
|
||
| internal override bool IsRecording => _recordedPosition.HasValue; | ||
|
|
||
| public override void Flush() => _underlyingStream.Flush(); | ||
| public override void Flush() => _stream.Flush(); | ||
|
|
||
| public override int Read(byte[] buffer, int offset, int count) => | ||
| _underlyingStream.Read(buffer, offset, count); | ||
| _stream.Read(buffer, offset, count); | ||
|
|
||
| #if !LEGACY_DOTNET | ||
| public override int Read(Span<byte> buffer) => _underlyingStream.Read(buffer); | ||
| public override int Read(Span<byte> buffer) => _stream.Read(buffer); | ||
| #endif | ||
|
|
||
| public override long Seek(long offset, SeekOrigin origin) => | ||
| _underlyingStream.Seek(offset, origin); | ||
| public override long Seek(long offset, SeekOrigin origin) => _stream.Seek(offset, origin); | ||
|
|
||
| public override void SetLength(long value) => _underlyingStream.SetLength(value); | ||
| public override void SetLength(long value) => _stream.SetLength(value); | ||
|
|
||
| public override void Write(byte[] buffer, int offset, int count) => | ||
| _underlyingStream.Write(buffer, offset, count); | ||
| _stream.Write(buffer, offset, count); | ||
|
|
||
| #if !LEGACY_DOTNET | ||
| public override void Write(ReadOnlySpan<byte> buffer) => _underlyingStream.Write(buffer); | ||
| public override void Write(ReadOnlySpan<byte> buffer) => _stream.Write(buffer); | ||
| #endif | ||
|
|
||
| public override void Rewind(bool stopRecording = false) | ||
|
|
@@ -80,22 +81,16 @@ public override void Rewind(bool stopRecording = false) | |
| return; | ||
| } | ||
|
|
||
| _underlyingStream.Seek(_recordedPosition.Value, SeekOrigin.Begin); | ||
| _stream.Seek(_recordedPosition.Value, SeekOrigin.Begin); | ||
| if (stopRecording) | ||
| { | ||
| _recordedPosition = null; | ||
| } | ||
| } | ||
|
|
||
| public override void StartRecording() | ||
| { | ||
| _recordedPosition = _underlyingStream.Position; | ||
| } | ||
| public override void StartRecording() => _recordedPosition = _stream.Position; | ||
|
|
||
| public override void StopRecording() | ||
| { | ||
| _recordedPosition = null; | ||
| } | ||
| public override void StopRecording() => _recordedPosition = null; | ||
|
|
||
| protected override void Dispose(bool disposing) | ||
| { | ||
|
|
@@ -112,45 +107,8 @@ protected override void Dispose(bool disposing) | |
| _isDisposed = true; | ||
| if (disposing && !LeaveStreamOpen) | ||
| { | ||
| _underlyingStream.Dispose(); | ||
| _stream.Dispose(); | ||
| } | ||
| base.Dispose(disposing); | ||
| } | ||
|
|
||
| private sealed class NullStream : Stream | ||
| { | ||
| public override bool CanRead => true; | ||
|
|
||
| public override bool CanSeek => false; | ||
|
|
||
| public override bool CanWrite => false; | ||
|
|
||
| public override long Length => throw new NotSupportedException(); | ||
|
|
||
| public override long Position | ||
| { | ||
| get => throw new NotSupportedException(); | ||
| set => throw new NotSupportedException(); | ||
| } | ||
|
|
||
| public override void Flush() { } | ||
|
|
||
| public override int Read(byte[] buffer, int offset, int count) => 0; | ||
|
|
||
| #if !LEGACY_DOTNET | ||
| public override int Read(Span<byte> buffer) => 0; | ||
| #endif | ||
|
|
||
| public override long Seek(long offset, SeekOrigin origin) => | ||
| throw new NotSupportedException(); | ||
|
|
||
| public override void SetLength(long value) => throw new NotSupportedException(); | ||
|
|
||
| public override void Write(byte[] buffer, int offset, int count) => | ||
| throw new NotSupportedException(); | ||
|
|
||
| #if !LEGACY_DOTNET | ||
| public override void Write(ReadOnlySpan<byte> buffer) => throw new NotSupportedException(); | ||
| #endif | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| using System; | ||
| using System.IO; | ||
| using SharpCompress.Common; | ||
|
|
||
| namespace SharpCompress.IO; | ||
|
|
||
| internal partial class SharpCompressStream | ||
| { | ||
| /// <summary> | ||
| /// Creates a SharpCompressStream that acts as a passthrough wrapper. | ||
| /// No buffering is performed; CanSeek delegates to the underlying stream. | ||
| /// The underlying stream will not be disposed when this stream is disposed. | ||
| /// </summary> | ||
| public static SharpCompressStream CreateNonDisposing(Stream stream) => | ||
| new(stream, leaveStreamOpen: true, passthrough: true, bufferSize: null); | ||
|
|
||
| public static SharpCompressStream Create(Stream stream, int? bufferSize = null) | ||
| { | ||
| var rewindableBufferSize = bufferSize ?? Constants.RewindableBufferSize; | ||
|
|
||
| // If it's a passthrough SharpCompressStream, unwrap it and create proper seekable wrapper | ||
| if (stream is SharpCompressStream sharpCompressStream) | ||
| { | ||
| if (sharpCompressStream._isPassthrough) | ||
| { | ||
| // Unwrap the passthrough and create appropriate wrapper | ||
| var underlying = sharpCompressStream.stream; | ||
| if (underlying.CanSeek) | ||
| { | ||
| // Create SeekableSharpCompressStream that preserves LeaveStreamOpen | ||
| return new SeekableSharpCompressStream(underlying, true); | ||
| } | ||
| // Non-seekable underlying stream - wrap with rolling buffer | ||
| return new SharpCompressStream(underlying, true, false, rewindableBufferSize); | ||
| } | ||
| // Not passthrough - return as-is | ||
| return sharpCompressStream; | ||
| } | ||
|
|
||
| // Check if stream is wrapping a SharpCompressStream (e.g., via IStreamStack) | ||
| if (stream is IStreamStack streamStack) | ||
| { | ||
| var underlying = streamStack.GetStream<SharpCompressStream>(); | ||
| if (underlying is not null) | ||
| { | ||
| return underlying; | ||
| } | ||
| } | ||
|
|
||
|
||
| if (stream.CanSeek) | ||
| { | ||
| return new SeekableSharpCompressStream(stream); | ||
| } | ||
|
|
||
| // For non-seekable streams, create a SharpCompressStream with rolling buffer | ||
| // to allow limited backward seeking (required by decompressors that over-read) | ||
| return new SharpCompressStream(stream, false, false, bufferSize); | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Documentation mismatch: The comment says "Gets or sets" but the property is get-only. Since the property cannot be set after construction, the documentation should say "Gets whether to leave the underlying stream open when disposed."