Skip to content
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

Fix MemoryStream.CanWrite to allow read-only #67

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 35 additions & 8 deletions System.IO.Streams/MemoryStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ public class MemoryStream : Stream
private readonly bool _expandable;
// Is this stream open or closed?
private bool _isOpen;
// Is the stream writable
private bool _isWritable;

private const int MemStreamMaxLength = 0xFFFF;

Expand All @@ -50,6 +52,7 @@ public MemoryStream()
// Must be 0 for byte[]'s created by MemoryStream
_origin = 0;
_isOpen = true;
_isWritable = true;
}

/// <summary>
Expand All @@ -61,18 +64,24 @@ public MemoryStream()
/// <para>
/// The <see cref="CanRead"/>, <see cref="CanSeek"/>, and <see cref="CanWrite"/> properties are all set to <see langword="true"/>.
/// </para>
/// <para>
/// The capacity of the current stream automatically increases when you use the <see cref="SetLength"/> method to set the length to a value larger than the capacity of the current stream.
/// </para>
/// </remarks>
public MemoryStream(byte[] buffer)
public MemoryStream(byte[] buffer) : this(buffer, true) { }

/// <summary>
/// Initializes a new non-resizable instance of the <see cref="MemoryStream"/> class based on the specified byte array with the <see cref="CanWrite"/> property set as specified.
/// </summary>
/// <param name="buffer">The array of unsigned bytes from which to create the current stream.</param>
/// <param name="isWritable">A bool indicating whether the stream should be writable</param>
/// <exception cref="ArgumentNullException"><paramref name="buffer"/> is <see langword="null"/>.</exception>
public MemoryStream(byte[] buffer, bool isWritable)
{
_buffer = buffer ?? throw new ArgumentNullException();
mizady marked this conversation as resolved.
Show resolved Hide resolved

_length = _capacity = buffer.Length;
_expandable = false;
_origin = 0;
_isOpen = true;
_isWritable = isWritable;
}

/// <summary>
Expand Down Expand Up @@ -115,7 +124,7 @@ public MemoryStream(byte[] buffer)
/// If the stream is closed, this property returns <see langword="false"/>.
/// </para>
/// </remarks>
public override bool CanWrite => _isOpen;
public override bool CanWrite => _isWritable;

/// <inheritdoc/>
protected override void Dispose(bool disposing)
Expand Down Expand Up @@ -329,11 +338,13 @@ public override long Seek(

/// <inheritdoc/>
/// <exception cref="ObjectDisposedException"></exception>
/// <exception cref="NotSupportedException">The stream buffer does not have the capacity to hold the data and is not expandable.</exception>
/// <exception cref="NotSupportedException">The stream buffer does not have the capacity to hold the
/// data and is not expandable, and/or the stream is not writable.</exception>
/// <exception cref="ArgumentOutOfRangeException">The MemoryStream max size was exceeded</exception>
public override void SetLength(long value)
{
EnsureOpen();
EnsureWritable();

if (value > MemStreamMaxLength || value < 0)
{
Expand Down Expand Up @@ -368,14 +379,16 @@ public virtual byte[] ToArray()

/// <inheritdoc/>
/// <exception cref="ObjectDisposedException"></exception>
/// <exception cref="NotSupportedException">The stream buffer does not have the capacity to hold the data and is not expandable.</exception>
/// <exception cref="NotSupportedException">The stream buffer does not have the capacity to hold the
/// data and is not expandable, and/or the stream is not writable.</exception>
/// <exception cref="ArgumentOutOfRangeException">
/// The MemoryStream max size was exceeded or
/// <paramref name="offset"/> or <paramref name="count"/> are less than 0
/// </exception>
public override void Write(byte[] buffer, int offset, int count)
{
EnsureOpen();
EnsureWritable();

if (buffer == null)
{
Expand Down Expand Up @@ -411,11 +424,13 @@ public override void Write(byte[] buffer, int offset, int count)

/// <inheritdoc/>
/// <exception cref="ObjectDisposedException"></exception>
/// <exception cref="NotSupportedException">The stream buffer does not have the capacity to hold the data and is not expandable.</exception>
/// <exception cref="NotSupportedException">The stream buffer does not have the capacity to hold the
/// data and is not expandable, and/or the stream is not writable.</exception>
/// <exception cref="ArgumentOutOfRangeException">The MemoryStream max size was exceeded</exception>
public override void WriteByte(byte value)
{
EnsureOpen();
EnsureWritable();

if (_position >= _capacity)
{
Expand Down Expand Up @@ -459,6 +474,18 @@ private void EnsureOpen()
}
}

/// <summary>
/// Check that stream is writable.
/// </summary>
/// <exception cref="NotSupportedException"></exception>
mizady marked this conversation as resolved.
Show resolved Hide resolved
private void EnsureWritable()
{
if (!CanWrite)
{
throw new NotSupportedException();
}
}

/// <summary>
/// Verifies that there is enough capacity in the stream.
/// </summary>
Expand Down
19 changes: 19 additions & 0 deletions UnitTests/MemoryStreamUnitTests/CanWrite.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,24 @@ public void CanWrite_Byte_Ctor()
OutputHelper.WriteLine($"Unexpected exception {ex}");
}
}

[TestMethod]
[DataRow(true)]
[DataRow(false)]
public void CanWrite_bool_isWritable_Ctor(bool isWritable)
{
// Arrange
byte[] buffer = new byte[1024];

// Act
using MemoryStream fs = new MemoryStream(buffer, isWritable);

// Assert
Assert.AreEqual(isWritable, fs.CanWrite, $"Expected CanWrite == {isWritable}, but got CanWrite == {!isWritable}");
if(!isWritable)
{
Assert.ThrowsException(typeof(NotSupportedException), () => fs.WriteByte(0), "Expected exception when attempt to write to a read only stream.");
}
}
}
}