diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/MemoryStream.cs b/src/libraries/System.Private.CoreLib/src/System/IO/MemoryStream.cs
index 7f6001364fcc85..c32406553e1088 100644
--- a/src/libraries/System.Private.CoreLib/src/System/IO/MemoryStream.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/IO/MemoryStream.cs
@@ -22,17 +22,17 @@ public class MemoryStream : Stream
{
private byte[] _buffer; // Either allocated internally or externally.
private readonly int _origin; // For user-provided arrays, start at this origin
- private protected int _position; // read/write head.
- private protected int _length; // Number of bytes within the memory stream
+ private int _position; // read/write head.
+ private int _length; // Number of bytes within the memory stream
private int _capacity; // length of usable portion of buffer for stream
// Note that _capacity == _buffer.Length for non-user-provided byte[]'s
private bool _expandable; // User-provided buffers aren't expandable.
- private protected bool _writable; // Can user write to this stream?
+ private bool _writable; // Can user write to this stream?
private readonly bool _exposable; // Whether the array can be returned to the user.
- private protected bool _isOpen; // Is this stream open or closed?
+ private bool _isOpen; // Is this stream open or closed?
- private protected CachedCompletedInt32Task _lastReadTask; // The last successful task returned from ReadAsync
+ private CachedCompletedInt32Task _lastReadTask; // The last successful task returned from ReadAsync
public MemoryStream()
: this(0)
diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/ReadOnlyMemoryStream.cs b/src/libraries/System.Private.CoreLib/src/System/IO/ReadOnlyMemoryStream.cs
index a3dd29fc9438a3..bfa15300cb994c 100644
--- a/src/libraries/System.Private.CoreLib/src/System/IO/ReadOnlyMemoryStream.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/IO/ReadOnlyMemoryStream.cs
@@ -7,49 +7,140 @@
namespace System.IO
{
///
- /// Provides a seekable, read-only over a .
+ /// Provides a seekable, read-only over a .
///
///
- /// The stream cannot be written to. always returns .
- /// throws and returns .
+ /// The stream cannot be written to. always returns .
+ /// throws and returns .
///
- public sealed class ReadOnlyMemoryStream : MemoryStream
+ public sealed class ReadOnlyMemoryStream : Stream
{
private ReadOnlyMemory _memory;
+ private int _position;
+ private bool _isOpen;
+ private CachedCompletedInt32Task _lastReadTask;
///
/// Initializes a new instance of the class over the specified .
///
/// The to wrap.
- public ReadOnlyMemoryStream(ReadOnlyMemory source) : base()
+ public ReadOnlyMemoryStream(ReadOnlyMemory source)
{
- _writable = false;
_memory = source;
- _length = source.Length;
+ _isOpen = true;
}
///
- public override int Capacity
+ public override bool CanRead => _isOpen;
+
+ ///
+ public override bool CanSeek => _isOpen;
+
+ ///
+ public override bool CanWrite => false;
+
+ ///
+ public override long Length
{
get
{
EnsureNotClosed();
return _memory.Length;
}
- set => throw new NotSupportedException(SR.NotSupported_MemStreamNotExpandable);
}
///
- public override byte[] GetBuffer() =>
- throw new UnauthorizedAccessException(SR.UnauthorizedAccess_MemStreamBuffer);
+ public override long Position
+ {
+ get
+ {
+ EnsureNotClosed();
+ return _position;
+ }
+ set
+ {
+ ArgumentOutOfRangeException.ThrowIfNegative(value);
+ ArgumentOutOfRangeException.ThrowIfGreaterThan(value, int.MaxValue);
+ EnsureNotClosed();
+ _position = (int)value;
+ }
+ }
+
+ ///
+ public override long Seek(long offset, SeekOrigin loc)
+ {
+ EnsureNotClosed();
+
+ ArgumentOutOfRangeException.ThrowIfGreaterThan(offset, int.MaxValue);
+
+ long target = loc switch
+ {
+ SeekOrigin.Begin => offset,
+ SeekOrigin.Current => _position + offset,
+ SeekOrigin.End => _memory.Length + offset,
+ _ => throw new ArgumentException(SR.Argument_InvalidSeekOrigin, nameof(loc)),
+ };
+
+ if (target < 0)
+ throw new IOException(SR.IO_SeekBeforeBegin);
+ ArgumentOutOfRangeException.ThrowIfGreaterThan(target, int.MaxValue, nameof(offset));
+
+ _position = (int)target;
+ return _position;
+ }
+
+ ///
+ public override void Flush() { }
+
+ ///
+ public override Task FlushAsync(CancellationToken cancellationToken) =>
+ cancellationToken.IsCancellationRequested
+ ? Task.FromCanceled(cancellationToken)
+ : Task.CompletedTask;
///
- public override bool TryGetBuffer(out ArraySegment buffer)
+ public override void SetLength(long value) =>
+ throw new NotSupportedException(SR.NotSupported_UnwritableStream);
+
+ /// Gets the size of the underlying buffer.
+ public int Capacity
+ {
+ get
+ {
+ EnsureNotClosed();
+ return _memory.Length;
+ }
+ }
+
+ /// Always throws; the underlying buffer is not exposed.
+ /// Always thrown.
+ public byte[] GetBuffer() =>
+ throw new UnauthorizedAccessException(SR.UnauthorizedAccess_MemStreamBuffer);
+
+ /// Always returns ; the underlying buffer is not exposed.
+ /// When this method returns, contains the default value of .
+ /// .
+ public bool TryGetBuffer(out ArraySegment buffer)
{
buffer = default;
return false;
}
+ ///
+ public override void Write(byte[] buffer, int offset, int count)
+ {
+ ValidateBufferArguments(buffer, offset, count);
+ throw new NotSupportedException(SR.NotSupported_UnwritableStream);
+ }
+
+ ///
+ public override void Write(ReadOnlySpan buffer) =>
+ throw new NotSupportedException(SR.NotSupported_UnwritableStream);
+
+ ///
+ public override void WriteByte(byte value) =>
+ throw new NotSupportedException(SR.NotSupported_UnwritableStream);
+
///
public override int ReadByte()
{
@@ -156,8 +247,9 @@ public override Task CopyToAsync(Stream destination, int bufferSize, Cancellatio
return Task.CompletedTask;
}
- ///
- public override byte[] ToArray()
+ /// Writes the stream contents to a byte array, regardless of the .
+ /// A new byte array containing a copy of the stream's contents.
+ public byte[] ToArray()
{
EnsureNotClosed();
if (_memory.Length == 0)
@@ -170,8 +262,9 @@ public override byte[] ToArray()
return copy;
}
- ///
- public override void WriteTo(Stream stream)
+ /// Writes the entire contents of this stream to another stream.
+ /// The destination stream.
+ public void WriteTo(Stream stream)
{
ArgumentNullException.ThrowIfNull(stream);
EnsureNotClosed();
@@ -183,6 +276,7 @@ public override void WriteTo(Stream stream)
protected override void Dispose(bool disposing)
{
_memory = default;
+ _isOpen = false;
base.Dispose(disposing);
}
diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/WritableMemoryStream.cs b/src/libraries/System.Private.CoreLib/src/System/IO/WritableMemoryStream.cs
index 2b6284f7746f20..786c4756242589 100644
--- a/src/libraries/System.Private.CoreLib/src/System/IO/WritableMemoryStream.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/IO/WritableMemoryStream.cs
@@ -7,42 +7,117 @@
namespace System.IO
{
///
- /// Provides a seekable, writable over a with fixed capacity.
+ /// Provides a seekable, writable over a with fixed capacity.
///
///
/// The stream cannot expand beyond the initial memory capacity.
- /// throws and returns .
+ /// throws and returns .
///
- public sealed class WritableMemoryStream : MemoryStream
+ public sealed class WritableMemoryStream : Stream
{
private Memory _memory;
+ private int _position;
+ private int _length;
+ private bool _isOpen;
+ private CachedCompletedInt32Task _lastReadTask;
///
/// Initializes a new instance of the class over the specified .
///
/// The to wrap.
- public WritableMemoryStream(Memory buffer) : base()
+ public WritableMemoryStream(Memory buffer)
{
_memory = buffer;
+ _isOpen = true;
}
///
- public override int Capacity
+ public override bool CanRead => _isOpen;
+
+ ///
+ public override bool CanSeek => _isOpen;
+
+ ///
+ public override bool CanWrite => _isOpen;
+
+ ///
+ public override long Length
{
get
{
EnsureNotClosed();
- return _memory.Length;
+ return _length;
}
- set => throw new NotSupportedException(SR.NotSupported_MemStreamNotExpandable);
}
///
- public override byte[] GetBuffer() =>
- throw new UnauthorizedAccessException(SR.UnauthorizedAccess_MemStreamBuffer);
+ public override long Position
+ {
+ get
+ {
+ EnsureNotClosed();
+ return _position;
+ }
+ set
+ {
+ ArgumentOutOfRangeException.ThrowIfNegative(value);
+ ArgumentOutOfRangeException.ThrowIfGreaterThan(value, int.MaxValue);
+ EnsureNotClosed();
+ _position = (int)value;
+ }
+ }
+
+ ///
+ public override long Seek(long offset, SeekOrigin loc)
+ {
+ EnsureNotClosed();
+
+ ArgumentOutOfRangeException.ThrowIfGreaterThan(offset, int.MaxValue);
+
+ long target = loc switch
+ {
+ SeekOrigin.Begin => offset,
+ SeekOrigin.Current => _position + offset,
+ SeekOrigin.End => _length + offset,
+ _ => throw new ArgumentException(SR.Argument_InvalidSeekOrigin, nameof(loc)),
+ };
+
+ if (target < 0)
+ throw new IOException(SR.IO_SeekBeforeBegin);
+ ArgumentOutOfRangeException.ThrowIfGreaterThan(target, int.MaxValue, nameof(offset));
+
+ _position = (int)target;
+ return _position;
+ }
///
- public override bool TryGetBuffer(out ArraySegment buffer)
+ public override void Flush() { }
+
+ ///
+ public override Task FlushAsync(CancellationToken cancellationToken) =>
+ cancellationToken.IsCancellationRequested
+ ? Task.FromCanceled(cancellationToken)
+ : Task.CompletedTask;
+
+ /// Gets the size of the underlying buffer.
+ public int Capacity
+ {
+ get
+ {
+ EnsureNotClosed();
+ return _memory.Length;
+ }
+ }
+
+ /// Always throws; the underlying buffer is not exposed.
+ /// Always thrown.
+ public byte[] GetBuffer() =>
+ throw new UnauthorizedAccessException(SR.UnauthorizedAccess_MemStreamBuffer);
+
+ /// Always returns ; the underlying buffer is not exposed.
+ /// When this method returns, contains the default value of .
+ /// .
+ public bool TryGetBuffer(out ArraySegment buffer)
{
buffer = default;
return false;
@@ -238,8 +313,9 @@ public override ValueTask WriteAsync(ReadOnlyMemory buffer, CancellationTo
///
public override void SetLength(long value) => throw new NotSupportedException(SR.NotSupported_MemStreamNotExpandable);
- ///
- public override byte[] ToArray()
+ /// Writes the stream contents to a byte array, regardless of the .
+ /// A new byte array containing a copy of the written contents.
+ public byte[] ToArray()
{
EnsureNotClosed();
if (_length == 0)
@@ -252,8 +328,9 @@ public override byte[] ToArray()
return copy;
}
- ///
- public override void WriteTo(Stream stream)
+ /// Writes the stream contents to another stream.
+ /// The destination stream.
+ public void WriteTo(Stream stream)
{
ArgumentNullException.ThrowIfNull(stream);
EnsureNotClosed();
@@ -265,6 +342,7 @@ public override void WriteTo(Stream stream)
protected override void Dispose(bool disposing)
{
_memory = default;
+ _isOpen = false;
base.Dispose(disposing);
}
diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs
index 7e7ae5dbe9f49b..812fcc56d65c08 100644
--- a/src/libraries/System.Runtime/ref/System.Runtime.cs
+++ b/src/libraries/System.Runtime/ref/System.Runtime.cs
@@ -11053,45 +11053,65 @@ public override void Write(System.ReadOnlySpan buffer) { }
public override System.Threading.Tasks.Task WriteAsync(byte[] buffer, int offset, int count, System.Threading.CancellationToken cancellationToken) { throw null; }
public override System.Threading.Tasks.ValueTask WriteAsync(System.ReadOnlyMemory buffer, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
}
- public sealed partial class ReadOnlyMemoryStream : System.IO.MemoryStream
+ public sealed partial class ReadOnlyMemoryStream : System.IO.Stream
{
public ReadOnlyMemoryStream(System.ReadOnlyMemory source) { }
- public override int Capacity { get { throw null; } set { } }
+ public int Capacity { get { throw null; } }
+ public override bool CanRead { get { throw null; } }
+ public override bool CanSeek { get { throw null; } }
+ public override bool CanWrite { get { throw null; } }
+ public override long Length { get { throw null; } }
+ public override long Position { get { throw null; } set { } }
+ public override long Seek(long offset, System.IO.SeekOrigin loc) { throw null; }
+ public override void SetLength(long value) { }
+ public override void Flush() { }
+ public override System.Threading.Tasks.Task FlushAsync(System.Threading.CancellationToken cancellationToken) { throw null; }
public override void CopyTo(System.IO.Stream destination, int bufferSize) { }
public override System.Threading.Tasks.Task CopyToAsync(System.IO.Stream destination, int bufferSize, System.Threading.CancellationToken cancellationToken) { throw null; }
protected override void Dispose(bool disposing) { }
- public override byte[] GetBuffer() { throw null; }
+ public byte[] GetBuffer() { throw null; }
public override int Read(byte[] buffer, int offset, int count) { throw null; }
public override int Read(System.Span buffer) { throw null; }
public override System.Threading.Tasks.Task ReadAsync(byte[] buffer, int offset, int count, System.Threading.CancellationToken cancellationToken) { throw null; }
public override System.Threading.Tasks.ValueTask ReadAsync(System.Memory buffer, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
public override int ReadByte() { throw null; }
- public override byte[] ToArray() { throw null; }
- public override bool TryGetBuffer(out System.ArraySegment buffer) { throw null; }
- public override void WriteTo(System.IO.Stream stream) { }
+ public override void Write(byte[] buffer, int offset, int count) { }
+ public override void Write(System.ReadOnlySpan buffer) { }
+ public override void WriteByte(byte value) { }
+ public byte[] ToArray() { throw null; }
+ public bool TryGetBuffer(out System.ArraySegment buffer) { throw null; }
+ public void WriteTo(System.IO.Stream stream) { }
}
- public sealed partial class WritableMemoryStream : System.IO.MemoryStream
+ public sealed partial class WritableMemoryStream : System.IO.Stream
{
public WritableMemoryStream(System.Memory buffer) { }
- public override int Capacity { get { throw null; } set { } }
+ public int Capacity { get { throw null; } }
+ public override bool CanRead { get { throw null; } }
+ public override bool CanSeek { get { throw null; } }
+ public override bool CanWrite { get { throw null; } }
+ public override long Length { get { throw null; } }
+ public override long Position { get { throw null; } set { } }
+ public override long Seek(long offset, System.IO.SeekOrigin loc) { throw null; }
+ public override void Flush() { }
+ public override System.Threading.Tasks.Task FlushAsync(System.Threading.CancellationToken cancellationToken) { throw null; }
public override void CopyTo(System.IO.Stream destination, int bufferSize) { }
public override System.Threading.Tasks.Task CopyToAsync(System.IO.Stream destination, int bufferSize, System.Threading.CancellationToken cancellationToken) { throw null; }
protected override void Dispose(bool disposing) { }
- public override byte[] GetBuffer() { throw null; }
+ public byte[] GetBuffer() { throw null; }
public override int Read(byte[] buffer, int offset, int count) { throw null; }
public override int Read(System.Span buffer) { throw null; }
public override System.Threading.Tasks.Task ReadAsync(byte[] buffer, int offset, int count, System.Threading.CancellationToken cancellationToken) { throw null; }
public override System.Threading.Tasks.ValueTask ReadAsync(System.Memory buffer, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
public override int ReadByte() { throw null; }
public override void SetLength(long value) { }
- public override byte[] ToArray() { throw null; }
- public override bool TryGetBuffer(out System.ArraySegment buffer) { throw null; }
+ public byte[] ToArray() { throw null; }
+ public bool TryGetBuffer(out System.ArraySegment buffer) { throw null; }
public override void Write(byte[] buffer, int offset, int count) { }
public override void Write(System.ReadOnlySpan buffer) { }
public override System.Threading.Tasks.Task WriteAsync(byte[] buffer, int offset, int count, System.Threading.CancellationToken cancellationToken) { throw null; }
public override System.Threading.Tasks.ValueTask WriteAsync(System.ReadOnlyMemory buffer, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
public override void WriteByte(byte value) { }
- public override void WriteTo(System.IO.Stream stream) { }
+ public void WriteTo(System.IO.Stream stream) { }
}
public partial class StringWriter : System.IO.TextWriter
{