diff --git a/src/SharpCompress/IO/PooledMemoryStream.cs b/src/SharpCompress/IO/PooledMemoryStream.cs index 58bc748f..3bbdb330 100644 --- a/src/SharpCompress/IO/PooledMemoryStream.cs +++ b/src/SharpCompress/IO/PooledMemoryStream.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.IO; using System.Threading; using System.Threading.Tasks; +using SharpCompress.Common; namespace SharpCompress.IO; @@ -12,8 +13,6 @@ namespace SharpCompress.IO; /// public sealed class PooledMemoryStream : MemoryStream { - public const int DefaultBlockSize = 81920; - private const int MaxStreamLength = int.MaxValue; private enum StorageMode @@ -33,11 +32,6 @@ public sealed class PooledMemoryStream : MemoryStream private bool _contiguousBufferExposed; private bool _isOpen; - private bool _writable; - private bool _expandable; - private bool _exposable; - - private int _origin; private int _position; private int _length; private int _capacity; @@ -47,7 +41,7 @@ public sealed class PooledMemoryStream : MemoryStream : this(0) { } public PooledMemoryStream(int capacity) - : this(capacity, DefaultBlockSize, ArrayPool.Shared) { } + : this(capacity, Constants.BufferSize, ArrayPool.Shared) { } public PooledMemoryStream(int capacity, int blockSize) : this(capacity, blockSize, ArrayPool.Shared) { } @@ -64,10 +58,6 @@ public sealed class PooledMemoryStream : MemoryStream _mode = StorageMode.Segmented; _blocks = new List(); _isOpen = true; - _writable = true; - _expandable = true; - _exposable = true; - _origin = 0; _position = 0; _length = 0; _capacity = capacity; @@ -75,67 +65,18 @@ public sealed class PooledMemoryStream : MemoryStream EnsureSegmentedAllocated(capacity); } - public PooledMemoryStream(byte[] buffer) - : this(buffer, writable: true) { } - - public PooledMemoryStream(byte[] buffer, bool writable) - : this(buffer, 0, buffer?.Length ?? 0, writable, publiclyVisible: false) { } - - public PooledMemoryStream(byte[] buffer, int index, int count) - : this(buffer, index, count, writable: true, publiclyVisible: false) { } - - public PooledMemoryStream(byte[] buffer, int index, int count, bool writable) - : this(buffer, index, count, writable, publiclyVisible: false) { } - - public PooledMemoryStream( - byte[] buffer, - int index, - int count, - bool writable, - bool publiclyVisible - ) - { - ThrowHelper.ThrowIfNull(buffer, nameof(buffer)); - ThrowHelper.ThrowIfNegative(index, nameof(index)); - ThrowHelper.ThrowIfNegative(count, nameof(count)); - if (buffer.Length - index < count) - { - throw new ArgumentException("Offset and length are out of bounds."); - } - - _arrayPool = ArrayPool.Shared; - _blockSize = DefaultBlockSize; - - _mode = StorageMode.Segmented; - _blocks = new List(); - _origin = 0; - _position = 0; - _length = count; - _capacity = count; - _writable = writable; - _expandable = false; - _exposable = publiclyVisible; - _isOpen = true; - - EnsureSegmentedAllocated(_capacity); - if (count > 0) - { - CopyToSegmented(0, buffer, index, count); - } - } - public override bool CanRead => _isOpen; public override bool CanSeek => _isOpen; - public override bool CanWrite => _writable; + public override bool CanWrite => _isOpen; public override long Length { get { EnsureNotClosed(); - return _length - _origin; + return _length; } } @@ -144,15 +85,15 @@ public sealed class PooledMemoryStream : MemoryStream get { EnsureNotClosed(); - return _position - _origin; + return _position; } set { ThrowHelper.ThrowIfNegative(value, nameof(value)); EnsureNotClosed(); - ThrowHelper.ThrowIfGreaterThan(value, MaxStreamLength - _origin, nameof(value)); + ThrowHelper.ThrowIfGreaterThan(value, MaxStreamLength, nameof(value)); - _position = _origin + (int)value; + _position = (int)value; } } @@ -161,23 +102,15 @@ public sealed class PooledMemoryStream : MemoryStream get { EnsureNotClosed(); - return _capacity - _origin; + return _capacity; } set { - if (value < Length) - { - throw new ArgumentOutOfRangeException(nameof(value)); - } + ThrowHelper.ThrowIfLessThan(value, _length, nameof(value)); EnsureNotClosed(); - if (!_expandable && value != Capacity) - { - throw new NotSupportedException("Memory stream is not expandable."); - } - - var target = _origin + value; + var target = value; if (target == _capacity) { return; @@ -205,14 +138,14 @@ public sealed class PooledMemoryStream : MemoryStream var anchor = loc switch { - SeekOrigin.Begin => _origin, + SeekOrigin.Begin => 0, SeekOrigin.Current => _position, SeekOrigin.End => _length, _ => throw new ArgumentException("Invalid seek origin.", nameof(loc)), }; var target = anchor + offset; - if (target < _origin) + if (target < 0) { throw new IOException("Attempted to seek before the beginning of the stream."); } @@ -223,7 +156,7 @@ public sealed class PooledMemoryStream : MemoryStream } _position = (int)target; - return _position - _origin; + return _position; } public override void SetLength(long value) @@ -233,7 +166,7 @@ public sealed class PooledMemoryStream : MemoryStream EnsureWritable(); - var newLength = _origin + (int)value; + var newLength = (int)value; if (newLength > _capacity) { EnsureCapacityForAppend(newLength); @@ -395,11 +328,6 @@ public sealed class PooledMemoryStream : MemoryStream public override byte[] GetBuffer() { EnsureNotClosed(); - if (!_exposable) - { - throw new UnauthorizedAccessException("Memory stream buffer is not publicly visible."); - } - EnsureContiguous(); _contiguousBufferExposed = true; return _contiguousBuffer!; @@ -407,12 +335,6 @@ public sealed class PooledMemoryStream : MemoryStream public override bool TryGetBuffer(out ArraySegment buffer) { - if (!_exposable) - { - buffer = default; - return false; - } - EnsureNotClosed(); EnsureContiguous(); @@ -425,7 +347,7 @@ public sealed class PooledMemoryStream : MemoryStream { EnsureNotClosed(); - var count = _length - _origin; + var count = _length; if (count == 0) { return Array.Empty(); @@ -435,10 +357,10 @@ public sealed class PooledMemoryStream : MemoryStream switch (_mode) { case StorageMode.Contiguous: - Buffer.BlockCopy(_contiguousBuffer!, _origin, copy, 0, count); + Buffer.BlockCopy(_contiguousBuffer!, 0, copy, 0, count); break; case StorageMode.Segmented: - CopyFromSegmented(_origin, copy, 0, count); + CopyFromSegmented(0, copy, 0, count); break; } @@ -450,7 +372,7 @@ public sealed class PooledMemoryStream : MemoryStream ThrowHelper.ThrowIfNull(stream, nameof(stream)); EnsureNotClosed(); - var count = _length - _origin; + var count = _length; if (count == 0) { return; @@ -459,11 +381,11 @@ public sealed class PooledMemoryStream : MemoryStream switch (_mode) { case StorageMode.Contiguous: - stream.Write(_contiguousBuffer!, _origin, count); + stream.Write(_contiguousBuffer!, 0, count); break; case StorageMode.Segmented: { - var position = _origin; + var position = 0; var remaining = count; while (remaining > 0) { @@ -526,7 +448,7 @@ public sealed class PooledMemoryStream : MemoryStream } #if !LEGACY_DOTNET - public override int Read(Span buffer) + public override int Read(Span destination) { EnsureNotClosed(); @@ -536,11 +458,11 @@ public sealed class PooledMemoryStream : MemoryStream return 0; } - var count = Math.Min(available, buffer.Length); + var count = Math.Min(available, destination.Length); switch (_mode) { case StorageMode.Contiguous: - _contiguousBuffer.AsSpan(_position, count).CopyTo(buffer); + _contiguousBuffer.AsSpan(_position, count).CopyTo(destination); break; case StorageMode.Segmented: { @@ -556,7 +478,7 @@ public sealed class PooledMemoryStream : MemoryStream _blocks! [blockIndex] .AsSpan(blockOffset, toCopy) - .CopyTo(buffer.Slice(destinationOffset, toCopy)); + .CopyTo(destination.Slice(destinationOffset, toCopy)); sourcePosition += toCopy; destinationOffset += toCopy; @@ -571,15 +493,15 @@ public sealed class PooledMemoryStream : MemoryStream return count; } - public override void Write(ReadOnlySpan buffer) + public override void Write(ReadOnlySpan source) { EnsureWritable(); - if (buffer.Length == 0) + if (source.Length == 0) { return; } - var endPosition = _position + buffer.Length; + var endPosition = _position + source.Length; if (endPosition < 0) { throw new IOException("Stream is too long."); @@ -598,13 +520,13 @@ public sealed class PooledMemoryStream : MemoryStream switch (_mode) { case StorageMode.Contiguous: - buffer.CopyTo(_contiguousBuffer.AsSpan(_position, buffer.Length)); + source.CopyTo(_contiguousBuffer.AsSpan(_position, source.Length)); break; case StorageMode.Segmented: { var sourceOffset = 0; var destinationPosition = _position; - var remaining = buffer.Length; + var remaining = source.Length; while (remaining > 0) { @@ -612,7 +534,7 @@ public sealed class PooledMemoryStream : MemoryStream var blockOffset = destinationPosition % _blockSize; var toCopy = Math.Min(remaining, _blockSize - blockOffset); - buffer + source .Slice(sourceOffset, toCopy) .CopyTo(_blocks![blockIndex].AsSpan(blockOffset, toCopy)); @@ -633,7 +555,7 @@ public sealed class PooledMemoryStream : MemoryStream } public override ValueTask ReadAsync( - Memory buffer, + Memory destination, CancellationToken cancellationToken = default ) { @@ -644,7 +566,7 @@ public sealed class PooledMemoryStream : MemoryStream try { - return ValueTask.FromResult(Read(buffer.Span)); + return ValueTask.FromResult(Read(destination.Span)); } catch (Exception ex) { @@ -653,7 +575,7 @@ public sealed class PooledMemoryStream : MemoryStream } public override ValueTask WriteAsync( - ReadOnlyMemory buffer, + ReadOnlyMemory source, CancellationToken cancellationToken = default ) { @@ -664,7 +586,7 @@ public sealed class PooledMemoryStream : MemoryStream try { - Write(buffer.Span); + Write(source.Span); return ValueTask.CompletedTask; } catch (Exception ex) @@ -679,8 +601,6 @@ public sealed class PooledMemoryStream : MemoryStream if (_isOpen) { _isOpen = false; - _writable = false; - _expandable = false; if (disposing) { @@ -702,10 +622,6 @@ public sealed class PooledMemoryStream : MemoryStream private void EnsureWritable() { EnsureNotClosed(); - if (!_writable) - { - throw new NotSupportedException("Stream does not support writing."); - } } private void EnsureCapacityForAppend(int requiredLength) @@ -720,11 +636,6 @@ public sealed class PooledMemoryStream : MemoryStream return; } - if (!_expandable) - { - throw new NotSupportedException("Memory stream is not expandable."); - } - var nextCapacity = RoundUpToBlockBoundary(requiredLength); SetCapacityAbsolute(nextCapacity); } diff --git a/tests/SharpCompress.Test/Streams/PooledMemoryStreamTests.cs b/tests/SharpCompress.Test/Streams/PooledMemoryStreamTests.cs index 28af7f1c..c628821d 100644 --- a/tests/SharpCompress.Test/Streams/PooledMemoryStreamTests.cs +++ b/tests/SharpCompress.Test/Streams/PooledMemoryStreamTests.cs @@ -54,49 +54,28 @@ public class PooledMemoryStreamTests } [Fact] - public void BufferConstructorCopiesDataAndIsNonExpandable() + public void TryGetBufferReturnsSegmentWhenOpen() { - var backing = Enumerable.Range(0, 10).Select(i => (byte)i).ToArray(); - using var stream = new PooledMemoryStream( - backing, - 2, - 4, - writable: true, - publiclyVisible: true - ); + using var stream = new PooledMemoryStream(capacity: 0, blockSize: 8); + stream.Write(new byte[] { 1, 2, 3, 4 }, 0, 4); - Assert.Equal(4, stream.Length); - Assert.Equal(4, stream.Capacity); - - backing[2] = 255; - Assert.Equal(new byte[] { 2, 3, 4, 5 }, stream.ToArray()); - - Assert.Throws(() => stream.Capacity = 5); + Assert.True(stream.TryGetBuffer(out var segment)); + Assert.Equal(0, segment.Offset); + Assert.Equal(4, segment.Count); + Assert.Equal(1, segment.Array![0]); } [Fact] - public void BufferConstructorTryGetBufferRespectsVisibilityFlag() + public void CapacitySetterCanGrowAndShrinkWithinLength() { - var backing = new byte[10]; - using var hidden = new PooledMemoryStream( - backing, - 1, - 5, - writable: true, - publiclyVisible: false - ); - Assert.False(hidden.TryGetBuffer(out _)); + using var stream = new PooledMemoryStream(capacity: 16, blockSize: 8); + stream.Write(new byte[6], 0, 6); - using var visible = new PooledMemoryStream( - backing, - 1, - 5, - writable: true, - publiclyVisible: true - ); - Assert.True(visible.TryGetBuffer(out var segment)); - Assert.Equal(0, segment.Offset); - Assert.Equal(5, segment.Count); + stream.Capacity = 24; + Assert.Equal(24, stream.Capacity); + + stream.Capacity = 8; + Assert.Equal(8, stream.Capacity); } [Fact]