diff options
Diffstat (limited to 'src/mscorlib/src/System/IO/MemoryStream.cs')
-rw-r--r-- | src/mscorlib/src/System/IO/MemoryStream.cs | 393 |
1 files changed, 223 insertions, 170 deletions
diff --git a/src/mscorlib/src/System/IO/MemoryStream.cs b/src/mscorlib/src/System/IO/MemoryStream.cs index 05aac909b5..3d5668d774 100644 --- a/src/mscorlib/src/System/IO/MemoryStream.cs +++ b/src/mscorlib/src/System/IO/MemoryStream.cs @@ -24,7 +24,8 @@ using System.Diagnostics.Contracts; using System.Threading; using System.Threading.Tasks; -namespace System.IO { +namespace System.IO +{ // A MemoryStream represents a Stream in memory (ie, it has no backing store). // This stream may reduce the need for temporary buffers and files in // an application. @@ -54,17 +55,20 @@ namespace System.IO { private const int MemStreamMaxLength = Int32.MaxValue; - public MemoryStream() - : this(0) { + public MemoryStream() + : this(0) + { } - - public MemoryStream(int capacity) { - if (capacity < 0) { - throw new ArgumentOutOfRangeException(nameof(capacity), Environment.GetResourceString("ArgumentOutOfRange_NegativeCapacity")); + + public MemoryStream(int capacity) + { + if (capacity < 0) + { + throw new ArgumentOutOfRangeException(nameof(capacity), SR.ArgumentOutOfRange_NegativeCapacity); } Contract.EndContractBlock(); - _buffer = capacity != 0 ? new byte[capacity] : EmptyArray<byte>.Value; + _buffer = capacity != 0 ? new byte[capacity] : Array.Empty<byte>(); _capacity = capacity; _expandable = true; _writable = true; @@ -72,13 +76,15 @@ namespace System.IO { _origin = 0; // Must be 0 for byte[]'s created by MemoryStream _isOpen = true; } - - public MemoryStream(byte[] buffer) - : this(buffer, true) { + + public MemoryStream(byte[] buffer) + : this(buffer, true) + { } - - public MemoryStream(byte[] buffer, bool writable) { - if (buffer == null) throw new ArgumentNullException(nameof(buffer), Environment.GetResourceString("ArgumentNull_Buffer")); + + public MemoryStream(byte[] buffer, bool writable) + { + if (buffer == null) throw new ArgumentNullException(nameof(buffer), SR.ArgumentNull_Buffer); Contract.EndContractBlock(); _buffer = buffer; _length = _capacity = buffer.Length; @@ -87,26 +93,29 @@ namespace System.IO { _origin = 0; _isOpen = true; } - - public MemoryStream(byte[] buffer, int index, int count) - : this(buffer, index, count, true, false) { + + public MemoryStream(byte[] buffer, int index, int count) + : this(buffer, index, count, true, false) + { } - - public MemoryStream(byte[] buffer, int index, int count, bool writable) - : this(buffer, index, count, writable, false) { + + public MemoryStream(byte[] buffer, int index, int count, bool writable) + : this(buffer, index, count, writable, false) + { } - - public MemoryStream(byte[] buffer, int index, int count, bool writable, bool publiclyVisible) { - if (buffer==null) - throw new ArgumentNullException(nameof(buffer), Environment.GetResourceString("ArgumentNull_Buffer")); + + public MemoryStream(byte[] buffer, int index, int count, bool writable, bool publiclyVisible) + { + if (buffer == null) + throw new ArgumentNullException(nameof(buffer), SR.ArgumentNull_Buffer); if (index < 0) - throw new ArgumentOutOfRangeException(nameof(index), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_NeedNonNegNum); if (count < 0) - throw new ArgumentOutOfRangeException(nameof(count), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum); if (buffer.Length - index < count) - throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen")); + throw new ArgumentException(SR.Argument_InvalidOffLen); Contract.EndContractBlock(); - + _buffer = buffer; _origin = _position = index; _length = _capacity = index + count; @@ -115,30 +124,36 @@ namespace System.IO { _expandable = false; _isOpen = true; } - - public override bool CanRead { + + public override bool CanRead + { [Pure] get { return _isOpen; } } - - public override bool CanSeek { + + public override bool CanSeek + { [Pure] get { return _isOpen; } } - - public override bool CanWrite { + + public override bool CanWrite + { [Pure] get { return _writable; } } - private void EnsureWriteable() { + private void EnsureWriteable() + { if (!CanWrite) __Error.WriteNotSupported(); } protected override void Dispose(bool disposing) { - try { - if (disposing) { + try + { + if (disposing) + { _isOpen = false; _writable = false; _expandable = false; @@ -146,18 +161,21 @@ namespace System.IO { _lastReadTask = null; } } - finally { + finally + { // Call base.Close() to cleanup async IO resources base.Dispose(disposing); } } - + // returns a bool saying whether we allocated a new array. - private bool EnsureCapacity(int value) { + private bool EnsureCapacity(int value) + { // Check for overflow if (value < 0) - throw new IOException(Environment.GetResourceString("IO.IO_StreamTooLong")); - if (value > _capacity) { + throw new IOException(SR.IO_StreamTooLong); + if (value > _capacity) + { int newCapacity = value; if (newCapacity < 256) newCapacity = 256; @@ -169,53 +187,58 @@ namespace System.IO { // And we want to give the user the value that they asked for if ((uint)(_capacity * 2) > Array.MaxByteArrayLength) newCapacity = value > Array.MaxByteArrayLength ? value : Array.MaxByteArrayLength; - + Capacity = newCapacity; return true; } return false; } - - public override void Flush() { - } - public override Task FlushAsync(CancellationToken cancellationToken) { + public override void Flush() + { + } + public override Task FlushAsync(CancellationToken cancellationToken) + { if (cancellationToken.IsCancellationRequested) return Task.FromCanceled(cancellationToken); - try { - + try + { Flush(); return Task.CompletedTask; - - } catch(Exception ex) { - + } + catch (Exception ex) + { return Task.FromException(ex); } } - public virtual byte[] GetBuffer() { + public virtual byte[] GetBuffer() + { if (!_exposable) - throw new UnauthorizedAccessException(Environment.GetResourceString("UnauthorizedAccess_MemStreamBuffer")); + throw new UnauthorizedAccessException(SR.UnauthorizedAccess_MemStreamBuffer); return _buffer; } - public virtual bool TryGetBuffer(out ArraySegment<byte> buffer) { - if (!_exposable) { + public virtual bool TryGetBuffer(out ArraySegment<byte> buffer) + { + if (!_exposable) + { buffer = default(ArraySegment<byte>); return false; } - buffer = new ArraySegment<byte>(_buffer, offset:_origin, count:(_length - _origin)); + buffer = new ArraySegment<byte>(_buffer, offset: _origin, count: (_length - _origin)); return true; } // -------------- PERF: Internal functions for fast direct access of MemoryStream buffer (cf. BinaryReader for usage) --------------- // PERF: Internal sibling of GetBuffer, always returns a buffer (cf. GetBuffer()) - internal byte[] InternalGetBuffer() { + internal byte[] InternalGetBuffer() + { return _buffer; } @@ -229,27 +252,30 @@ namespace System.IO { } // PERF: True cursor position, we don't need _origin for direct access - internal int InternalGetPosition() { + internal int InternalGetPosition() + { if (!_isOpen) __Error.StreamIsClosed(); return _position; } // PERF: Takes out Int32 as fast as possible - internal int InternalReadInt32() { - if (!_isOpen) - __Error.StreamIsClosed(); + internal int InternalReadInt32() + { + if (!_isOpen) + __Error.StreamIsClosed(); - int pos = (_position += 4); // use temp to avoid a race condition - if (pos > _length) - { - _position = _length; - __Error.EndOfFile(); - } - return (int)(_buffer[pos-4] | _buffer[pos-3] << 8 | _buffer[pos-2] << 16 | _buffer[pos-1] << 24); + int pos = (_position += 4); // use temp to avoid a race condition + if (pos > _length) + { + _position = _length; + __Error.EndOfFile(); + } + return (int)(_buffer[pos - 4] | _buffer[pos - 3] << 8 | _buffer[pos - 2] << 16 | _buffer[pos - 1] << 24); } // PERF: Get actual length of bytes available for read; do sanity checks; shift position - i.e. everything except actual copying bytes - internal int InternalEmulateRead(int count) { + internal int InternalEmulateRead(int count) + { if (!_isOpen) __Error.StreamIsClosed(); int n = _length - _position; @@ -260,20 +286,23 @@ namespace System.IO { _position += n; return n; } - + // Gets & sets the capacity (number of bytes allocated) for this stream. // The capacity cannot be set to a value less than the current length // of the stream. // - public virtual int Capacity { - get { + public virtual int Capacity + { + get + { if (!_isOpen) __Error.StreamIsClosed(); return _capacity - _origin; } - set { + set + { // Only update the capacity if the MS is expandable and the value is different than the current capacity. // Special behavior if the MS isn't expandable: we don't throw if value is the same as the current capacity - if (value < Length) throw new ArgumentOutOfRangeException(nameof(value), Environment.GetResourceString("ArgumentOutOfRange_SmallCapacity")); + if (value < Length) throw new ArgumentOutOfRangeException(nameof(value), SR.ArgumentOutOfRange_SmallCapacity); Contract.Ensures(_capacity - _origin == value); Contract.EndContractBlock(); @@ -281,55 +310,64 @@ namespace System.IO { if (!_expandable && (value != Capacity)) __Error.MemoryStreamNotExpandable(); // MemoryStream has this invariant: _origin > 0 => !expandable (see ctors) - if (_expandable && value != _capacity) { - if (value > 0) { + if (_expandable && value != _capacity) + { + if (value > 0) + { byte[] newBuffer = new byte[value]; if (_length > 0) Buffer.InternalBlockCopy(_buffer, 0, newBuffer, 0, _length); _buffer = newBuffer; } - else { + else + { _buffer = null; } _capacity = value; } } - } + } - public override long Length { - get { + public override long Length + { + get + { if (!_isOpen) __Error.StreamIsClosed(); return _length - _origin; } } - public override long Position { - get { + public override long Position + { + get + { if (!_isOpen) __Error.StreamIsClosed(); return _position - _origin; } - set { + set + { if (value < 0) - throw new ArgumentOutOfRangeException(nameof(value), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + throw new ArgumentOutOfRangeException(nameof(value), SR.ArgumentOutOfRange_NeedNonNegNum); Contract.Ensures(Position == value); Contract.EndContractBlock(); if (!_isOpen) __Error.StreamIsClosed(); if (value > MemStreamMaxLength) - throw new ArgumentOutOfRangeException(nameof(value), Environment.GetResourceString("ArgumentOutOfRange_StreamLength")); + throw new ArgumentOutOfRangeException(nameof(value), SR.ArgumentOutOfRange_StreamLength); _position = _origin + (int)value; } } - public override int Read([In, Out] byte[] buffer, int offset, int count) { - if (buffer==null) - throw new ArgumentNullException(nameof(buffer), Environment.GetResourceString("ArgumentNull_Buffer")); + public override int Read([In, Out] byte[] buffer, int offset, int count) + { + if (buffer == null) + throw new ArgumentNullException(nameof(buffer), SR.ArgumentNull_Buffer); if (offset < 0) - throw new ArgumentOutOfRangeException(nameof(offset), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + throw new ArgumentOutOfRangeException(nameof(offset), SR.ArgumentOutOfRange_NeedNonNegNum); if (count < 0) - throw new ArgumentOutOfRangeException(nameof(count), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum); if (buffer.Length - offset < count) - throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen")); + throw new ArgumentException(SR.Argument_InvalidOffLen); Contract.EndContractBlock(); if (!_isOpen) __Error.StreamIsClosed(); @@ -356,25 +394,25 @@ namespace System.IO { public override Task<int> ReadAsync(Byte[] buffer, int offset, int count, CancellationToken cancellationToken) { - if (buffer==null) - throw new ArgumentNullException(nameof(buffer), Environment.GetResourceString("ArgumentNull_Buffer")); + if (buffer == null) + throw new ArgumentNullException(nameof(buffer), SR.ArgumentNull_Buffer); if (offset < 0) - throw new ArgumentOutOfRangeException(nameof(offset), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + throw new ArgumentOutOfRangeException(nameof(offset), SR.ArgumentOutOfRange_NeedNonNegNum); if (count < 0) - throw new ArgumentOutOfRangeException(nameof(count), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum); if (buffer.Length - offset < count) - throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen")); + throw new ArgumentException(SR.Argument_InvalidOffLen); Contract.EndContractBlock(); // contract validation copied from Read(...) // If cancellation was requested, bail early - if (cancellationToken.IsCancellationRequested) + if (cancellationToken.IsCancellationRequested) return Task.FromCanceled<int>(cancellationToken); try { int n = Read(buffer, offset, count); var t = _lastReadTask; - Debug.Assert(t == null || t.Status == TaskStatus.RanToCompletion, + Debug.Assert(t == null || t.Status == TaskStatus.RanToCompletion, "Expected that a stored last task completed successfully"); return (t != null && t.Result == n) ? t : (_lastReadTask = Task.FromResult<int>(n)); } @@ -389,9 +427,10 @@ namespace System.IO { } - public override int ReadByte() { + public override int ReadByte() + { if (!_isOpen) __Error.StreamIsClosed(); - + if (_position >= _length) return -1; return _buffer[_position++]; @@ -412,7 +451,7 @@ namespace System.IO { base.CopyTo(destination, bufferSize); return; } - + int originalPosition = _position; // Seek to the end of the MemoryStream. @@ -427,8 +466,8 @@ namespace System.IO { } } - public override Task CopyToAsync(Stream destination, Int32 bufferSize, CancellationToken cancellationToken) { - + public override Task CopyToAsync(Stream destination, Int32 bufferSize, CancellationToken cancellationToken) + { // This implementation offers beter performance compared to the base class version. StreamHelpers.ValidateCopyToArgs(this, destination, bufferSize); @@ -443,7 +482,7 @@ namespace System.IO { // If cancelled - return fast: if (cancellationToken.IsCancellationRequested) return Task.FromCanceled(cancellationToken); - + // Avoid copying data from this buffer into a temp buffer: // (require that InternalEmulateRead does not throw, // otherwise it needs to be wrapped into try-catch-Task.FromException like memStrDest.Write below) @@ -453,56 +492,62 @@ namespace System.IO { // If destination is not a memory stream, write there asynchronously: MemoryStream memStrDest = destination as MemoryStream; - if (memStrDest == null) + if (memStrDest == null) return destination.WriteAsync(_buffer, pos, n, cancellationToken); - - try { + try + { // If destination is a MemoryStream, CopyTo synchronously: memStrDest.Write(_buffer, pos, n); return Task.CompletedTask; - - } catch(Exception ex) { + } + catch (Exception ex) + { return Task.FromException(ex); } } - public override long Seek(long offset, SeekOrigin loc) { + public override long Seek(long offset, SeekOrigin loc) + { if (!_isOpen) __Error.StreamIsClosed(); if (offset > MemStreamMaxLength) - throw new ArgumentOutOfRangeException(nameof(offset), Environment.GetResourceString("ArgumentOutOfRange_StreamLength")); - switch(loc) { - case SeekOrigin.Begin: { - int tempPosition = unchecked(_origin + (int)offset); - if (offset < 0 || tempPosition < _origin) - throw new IOException(Environment.GetResourceString("IO.IO_SeekBeforeBegin")); - _position = tempPosition; - break; - } - case SeekOrigin.Current: { - int tempPosition = unchecked(_position + (int)offset); - if (unchecked(_position + offset) < _origin || tempPosition < _origin) - throw new IOException(Environment.GetResourceString("IO.IO_SeekBeforeBegin")); - _position = tempPosition; - break; - } - case SeekOrigin.End: { - int tempPosition = unchecked(_length + (int)offset); - if ( unchecked(_length + offset) < _origin || tempPosition < _origin ) - throw new IOException(Environment.GetResourceString("IO.IO_SeekBeforeBegin")); - _position = tempPosition; - break; - } - default: - throw new ArgumentException(Environment.GetResourceString("Argument_InvalidSeekOrigin")); + throw new ArgumentOutOfRangeException(nameof(offset), SR.ArgumentOutOfRange_StreamLength); + switch (loc) + { + case SeekOrigin.Begin: + { + int tempPosition = unchecked(_origin + (int)offset); + if (offset < 0 || tempPosition < _origin) + throw new IOException(SR.IO_SeekBeforeBegin); + _position = tempPosition; + break; + } + case SeekOrigin.Current: + { + int tempPosition = unchecked(_position + (int)offset); + if (unchecked(_position + offset) < _origin || tempPosition < _origin) + throw new IOException(SR.IO_SeekBeforeBegin); + _position = tempPosition; + break; + } + case SeekOrigin.End: + { + int tempPosition = unchecked(_length + (int)offset); + if (unchecked(_length + offset) < _origin || tempPosition < _origin) + throw new IOException(SR.IO_SeekBeforeBegin); + _position = tempPosition; + break; + } + default: + throw new ArgumentException(SR.Argument_InvalidSeekOrigin); } Debug.Assert(_position >= 0, "_position >= 0"); return _position; } - + // Sets the length of the stream to a given value. The new // value must be nonnegative and less than the space remaining in // the array, Int32.MaxValue - origin @@ -513,9 +558,11 @@ namespace System.IO { // the stream is made longer than the maximum possible length of the // array (Int32.MaxValue). // - public override void SetLength(long value) { - if (value < 0 || value > Int32.MaxValue) { - throw new ArgumentOutOfRangeException(nameof(value), Environment.GetResourceString("ArgumentOutOfRange_StreamLength")); + public override void SetLength(long value) + { + if (value < 0 || value > Int32.MaxValue) + { + throw new ArgumentOutOfRangeException(nameof(value), SR.ArgumentOutOfRange_StreamLength); } Contract.Ensures(_length - _origin == value); Contract.EndContractBlock(); @@ -523,8 +570,9 @@ namespace System.IO { // Origin wasn't publicly exposed above. Debug.Assert(MemStreamMaxLength == Int32.MaxValue); // Check parameter validation logic in this method if this fails. - if (value > (Int32.MaxValue - _origin)) { - throw new ArgumentOutOfRangeException(nameof(value), Environment.GetResourceString("ArgumentOutOfRange_StreamLength")); + if (value > (Int32.MaxValue - _origin)) + { + throw new ArgumentOutOfRangeException(nameof(value), SR.ArgumentOutOfRange_StreamLength); } int newLength = _origin + (int)value; @@ -533,25 +581,26 @@ namespace System.IO { Array.Clear(_buffer, _length, newLength - _length); _length = newLength; if (_position > newLength) _position = newLength; - } - - public virtual byte[] ToArray() { + + public virtual byte[] ToArray() + { BCLDebug.Perf(_exposable, "MemoryStream::GetBuffer will let you avoid a copy."); byte[] copy = new byte[_length - _origin]; Buffer.InternalBlockCopy(_buffer, _origin, copy, 0, _length - _origin); return copy; } - - public override void Write(byte[] buffer, int offset, int count) { - if (buffer==null) - throw new ArgumentNullException(nameof(buffer), Environment.GetResourceString("ArgumentNull_Buffer")); + + public override void Write(byte[] buffer, int offset, int count) + { + if (buffer == null) + throw new ArgumentNullException(nameof(buffer), SR.ArgumentNull_Buffer); if (offset < 0) - throw new ArgumentOutOfRangeException(nameof(offset), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + throw new ArgumentOutOfRangeException(nameof(offset), SR.ArgumentOutOfRange_NeedNonNegNum); if (count < 0) - throw new ArgumentOutOfRangeException(nameof(count), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum); if (buffer.Length - offset < count) - throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen")); + throw new ArgumentException(SR.Argument_InvalidOffLen); Contract.EndContractBlock(); if (!_isOpen) __Error.StreamIsClosed(); @@ -560,11 +609,13 @@ namespace System.IO { int i = _position + count; // Check for overflow if (i < 0) - throw new IOException(Environment.GetResourceString("IO.IO_StreamTooLong")); + throw new IOException(SR.IO_StreamTooLong); - if (i > _length) { + if (i > _length) + { bool mustZero = _position > _length; - if (i > _capacity) { + if (i > _capacity) + { bool allocatedNewArray = EnsureCapacity(i); if (allocatedNewArray) mustZero = false; @@ -582,23 +633,22 @@ namespace System.IO { else Buffer.InternalBlockCopy(buffer, offset, _buffer, _position, count); _position = i; - } public override Task WriteAsync(Byte[] buffer, int offset, int count, CancellationToken cancellationToken) { if (buffer == null) - throw new ArgumentNullException(nameof(buffer), Environment.GetResourceString("ArgumentNull_Buffer")); + throw new ArgumentNullException(nameof(buffer), SR.ArgumentNull_Buffer); if (offset < 0) - throw new ArgumentOutOfRangeException(nameof(offset), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + throw new ArgumentOutOfRangeException(nameof(offset), SR.ArgumentOutOfRange_NeedNonNegNum); if (count < 0) - throw new ArgumentOutOfRangeException(nameof(count), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum); if (buffer.Length - offset < count) - throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen")); + throw new ArgumentException(SR.Argument_InvalidOffLen); Contract.EndContractBlock(); // contract validation copied from Write(...) // If cancellation is already requested, bail early - if (cancellationToken.IsCancellationRequested) + if (cancellationToken.IsCancellationRequested) return Task.FromCanceled(cancellationToken); try @@ -616,14 +666,17 @@ namespace System.IO { } } - public override void WriteByte(byte value) { + public override void WriteByte(byte value) + { if (!_isOpen) __Error.StreamIsClosed(); EnsureWriteable(); - - if (_position >= _length) { + + if (_position >= _length) + { int newLength = _position + 1; bool mustZero = _position > _length; - if (newLength >= _capacity) { + if (newLength >= _capacity) + { bool allocatedNewArray = EnsureCapacity(newLength); if (allocatedNewArray) mustZero = false; @@ -633,13 +686,13 @@ namespace System.IO { _length = newLength; } _buffer[_position++] = value; - } - + // Writes this MemoryStream to another stream. - public virtual void WriteTo(Stream stream) { - if (stream==null) - throw new ArgumentNullException(nameof(stream), Environment.GetResourceString("ArgumentNull_Stream")); + public virtual void WriteTo(Stream stream) + { + if (stream == null) + throw new ArgumentNullException(nameof(stream), SR.ArgumentNull_Stream); Contract.EndContractBlock(); if (!_isOpen) __Error.StreamIsClosed(); |