Update Reference Sources to .NET Framework 4.6.1
[mono.git] / mcs / class / referencesource / mscorlib / system / io / memorystream.cs
1 // ==++==
2 // 
3 //   Copyright (c) Microsoft Corporation.  All rights reserved.
4 // 
5 // ==--==
6 /*============================================================
7 **
8 ** Class:  MemoryStream
9 ** 
10 ** <OWNER>[....]</OWNER>
11 **
12 **
13 ** Purpose: A Stream whose backing store is memory.  Great
14 ** for temporary storage without creating a temp file.  Also
15 ** lets users expose a byte[] as a stream.
16 **
17 **
18 ===========================================================*/
19
20 using System;
21 using System.Runtime;
22 using System.Runtime.CompilerServices;
23 using System.Runtime.InteropServices;
24 using System.Diagnostics.Contracts;
25 #if FEATURE_ASYNC_IO
26 using System.Threading;
27 using System.Threading.Tasks;
28 using System.Security.Permissions;
29 #endif
30
31 namespace System.IO {
32     // A MemoryStream represents a Stream in memory (ie, it has no backing store).
33     // This stream may reduce the need for temporary buffers and files in 
34     // an application.  
35     // 
36     // There are two ways to create a MemoryStream.  You can initialize one
37     // from an unsigned byte array, or you can create an empty one.  Empty 
38     // memory streams are resizable, while ones created with a byte array provide
39     // a stream "view" of the data.
40     [Serializable]
41     [ComVisible(true)]
42     public class MemoryStream : Stream
43     {
44         private byte[] _buffer;    // Either allocated internally or externally.
45         private int _origin;       // For user-provided arrays, start at this origin
46         private int _position;     // read/write head.
47         [ContractPublicPropertyName("Length")]
48         private int _length;       // Number of bytes within the memory stream
49         private int _capacity;     // length of usable portion of buffer for stream
50         // Note that _capacity == _buffer.Length for non-user-provided byte[]'s
51
52         private bool _expandable;  // User-provided buffers aren't expandable.
53         private bool _writable;    // Can user write to this stream?
54         private bool _exposable;   // Whether the array can be returned to the user.
55         private bool _isOpen;      // Is this stream open or closed?
56
57 #if FEATURE_ASYNC_IO
58         [NonSerialized]
59         private Task<int> _lastReadTask; // The last successful task returned from ReadAsync
60 #endif
61
62         // <
63
64         private const int MemStreamMaxLength = Int32.MaxValue;
65
66         public MemoryStream() 
67             : this(0) {
68         }
69         
70         public MemoryStream(int capacity) {
71             if (capacity < 0) {
72                 throw new ArgumentOutOfRangeException("capacity", Environment.GetResourceString("ArgumentOutOfRange_NegativeCapacity"));
73             }
74             Contract.EndContractBlock();
75
76             _buffer = new byte[capacity];
77             _capacity = capacity;
78             _expandable = true;
79             _writable = true;
80             _exposable = true;
81             _origin = 0;      // Must be 0 for byte[]'s created by MemoryStream
82             _isOpen = true;
83         }
84         
85         public MemoryStream(byte[] buffer) 
86             : this(buffer, true) {
87         }
88         
89         public MemoryStream(byte[] buffer, bool writable) {
90             if (buffer == null) throw new ArgumentNullException("buffer", Environment.GetResourceString("ArgumentNull_Buffer"));
91             Contract.EndContractBlock();
92             _buffer = buffer;
93             _length = _capacity = buffer.Length;
94             _writable = writable;
95             _exposable = false;
96             _origin = 0;
97             _isOpen = true;
98         }
99         
100         public MemoryStream(byte[] buffer, int index, int count) 
101             : this(buffer, index, count, true, false) {
102         }
103         
104         public MemoryStream(byte[] buffer, int index, int count, bool writable) 
105             : this(buffer, index, count, writable, false) {
106         }
107     
108         public MemoryStream(byte[] buffer, int index, int count, bool writable, bool publiclyVisible) {
109             if (buffer==null)
110                 throw new ArgumentNullException("buffer", Environment.GetResourceString("ArgumentNull_Buffer"));
111             if (index < 0)
112                 throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
113             if (count < 0)
114                 throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
115             if (buffer.Length - index < count)
116                 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
117             Contract.EndContractBlock();
118     
119             _buffer = buffer;
120             _origin = _position = index;
121             _length = _capacity = index + count;
122             _writable = writable;
123             _exposable = publiclyVisible;  // Can TryGetBuffer/GetBuffer return the array?
124             _expandable = false;
125             _isOpen = true;
126         }
127     
128         public override bool CanRead {
129             [Pure]
130             get { return _isOpen; }
131         }
132         
133         public override bool CanSeek {
134             [Pure]
135             get { return _isOpen; }
136         }
137         
138         public override bool CanWrite {
139             [Pure]
140             get { return _writable; }
141         }
142
143         private void EnsureWriteable() {
144             if (!CanWrite) __Error.WriteNotSupported();
145         }
146
147         protected override void Dispose(bool disposing)
148         {
149             try {
150                 if (disposing) {
151                     _isOpen = false;
152                     _writable = false;
153                     _expandable = false;
154                     // Don't set buffer to null - allow TryGetBuffer, GetBuffer & ToArray to work.
155 #if FEATURE_ASYNC_IO
156                     _lastReadTask = null;
157 #endif
158                 }
159             }
160             finally {
161                 // Call base.Close() to cleanup async IO resources
162                 base.Dispose(disposing);
163             }
164         }
165         
166         // returns a bool saying whether we allocated a new array.
167         private bool EnsureCapacity(int value) {
168             // Check for overflow
169             if (value < 0)
170                 throw new IOException(Environment.GetResourceString("IO.IO_StreamTooLong"));
171             if (value > _capacity) {
172                 int newCapacity = value;
173                 if (newCapacity < 256)
174                     newCapacity = 256;
175                 // We are ok with this overflowing since the next statement will deal
176                 // with the cases where _capacity*2 overflows.
177                 if (newCapacity < _capacity * 2)
178                     newCapacity = _capacity * 2;
179                 // We want to expand the array up to Array.MaxArrayLengthOneDimensional
180                 // And we want to give the user the value that they asked for
181                 if ((uint)(_capacity * 2) > Array.MaxByteArrayLength)
182                     newCapacity = value > Array.MaxByteArrayLength ? value : Array.MaxByteArrayLength;
183                 
184                 Capacity = newCapacity;
185                 return true;
186             }
187             return false;
188         }
189     
190         public override void Flush() {
191         }
192
193 #if FEATURE_ASYNC_IO
194         [HostProtection(ExternalThreading=true)]
195         [ComVisible(false)]
196         public override Task FlushAsync(CancellationToken cancellationToken) {
197
198             if (cancellationToken.IsCancellationRequested)
199                 return Task.FromCancellation(cancellationToken);
200
201             try {
202
203                 Flush();
204                 return Task.CompletedTask;
205         
206             } catch(Exception ex) {
207
208                 return Task.FromException(ex);
209             }
210         }
211 #endif // FEATURE_ASYNC_IO
212
213
214         public virtual byte[] GetBuffer() {
215             if (!_exposable)
216                 throw new UnauthorizedAccessException(Environment.GetResourceString("UnauthorizedAccess_MemStreamBuffer"));
217             return _buffer;
218         }
219
220         public virtual bool TryGetBuffer(out ArraySegment<byte> buffer) {
221             if (!_exposable) {
222                 buffer = default(ArraySegment<byte>);
223                 return false;
224             }
225
226             buffer = new ArraySegment<byte>(_buffer, offset:_origin, count:(_length - _origin));
227             return true;
228         }
229
230         // -------------- PERF: Internal functions for fast direct access of MemoryStream buffer (cf. BinaryReader for usage) ---------------
231
232         // PERF: Internal sibling of GetBuffer, always returns a buffer (cf. GetBuffer())
233         internal byte[] InternalGetBuffer() {
234             return _buffer;
235         }
236
237         // PERF: Get origin and length - used in ResourceWriter.
238         [FriendAccessAllowed]
239         internal void InternalGetOriginAndLength(out int origin, out int length)
240         {
241             if (!_isOpen) __Error.StreamIsClosed();
242             origin = _origin;
243             length = _length;
244         }
245
246         // PERF: True cursor position, we don't need _origin for direct access
247         internal int InternalGetPosition() {
248             if (!_isOpen) __Error.StreamIsClosed();
249             return _position;
250         }
251
252         // PERF: Takes out Int32 as fast as possible
253         internal int InternalReadInt32() {
254            if (!_isOpen)
255                __Error.StreamIsClosed();
256
257            int pos = (_position += 4); // use temp to avoid ----
258            if (pos > _length)
259            {
260                _position = _length;
261                __Error.EndOfFile();
262            }
263            return (int)(_buffer[pos-4] | _buffer[pos-3] << 8 | _buffer[pos-2] << 16 | _buffer[pos-1] << 24);
264         }
265
266         // PERF: Get actual length of bytes available for read; do sanity checks; shift position - i.e. everything except actual copying bytes
267         internal int InternalEmulateRead(int count) {
268             if (!_isOpen) __Error.StreamIsClosed();
269
270             int n = _length - _position;
271             if (n > count) n = count;
272             if (n < 0) n = 0;
273
274             Contract.Assert(_position + n >= 0, "_position + n >= 0");  // len is less than 2^31 -1.
275             _position += n;
276             return n;
277         }
278        
279         // Gets & sets the capacity (number of bytes allocated) for this stream.
280         // The capacity cannot be set to a value less than the current length
281         // of the stream.
282         // 
283         public virtual int Capacity {
284             get { 
285                 if (!_isOpen) __Error.StreamIsClosed();
286                 return _capacity - _origin;
287             }
288             set {
289                 // Only update the capacity if the MS is expandable and the value is different than the current capacity.
290                 // Special behavior if the MS isn't expandable: we don't throw if value is the same as the current capacity
291                 if (value < Length) throw new ArgumentOutOfRangeException("value", Environment.GetResourceString("ArgumentOutOfRange_SmallCapacity"));
292                 Contract.Ensures(_capacity - _origin == value);
293                 Contract.EndContractBlock();
294
295                 if (!_isOpen) __Error.StreamIsClosed();
296                 if (!_expandable && (value != Capacity)) __Error.MemoryStreamNotExpandable();
297
298                 // MemoryStream has this invariant: _origin > 0 => !expandable (see ctors)
299                 if (_expandable && value != _capacity) {
300                     if (value > 0) {
301                         byte[] newBuffer = new byte[value];
302                         if (_length > 0) Buffer.InternalBlockCopy(_buffer, 0, newBuffer, 0, _length);
303                         _buffer = newBuffer;
304                     }
305                     else {
306                         _buffer = null;
307                     }
308                     _capacity = value;
309                 }
310             }
311         }        
312
313         public override long Length {
314             get {
315                 if (!_isOpen) __Error.StreamIsClosed();
316                 return _length - _origin;
317             }
318         }
319
320         public override long Position {
321             get { 
322                 if (!_isOpen) __Error.StreamIsClosed();
323                 return _position - _origin;
324             }
325             set {
326                 if (value < 0)
327                     throw new ArgumentOutOfRangeException("value", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
328                 Contract.Ensures(Position == value);
329                 Contract.EndContractBlock();
330
331                 if (!_isOpen) __Error.StreamIsClosed();
332
333                 if (value > MemStreamMaxLength)
334                     throw new ArgumentOutOfRangeException("value", Environment.GetResourceString("ArgumentOutOfRange_StreamLength"));
335                 _position = _origin + (int)value;
336             }
337         }
338
339         public override int Read([In, Out] byte[] buffer, int offset, int count) {
340             if (buffer==null)
341                 throw new ArgumentNullException("buffer", Environment.GetResourceString("ArgumentNull_Buffer"));
342             if (offset < 0)
343                 throw new ArgumentOutOfRangeException("offset", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
344             if (count < 0)
345                 throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
346             if (buffer.Length - offset < count)
347                 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
348             Contract.EndContractBlock();
349
350             if (!_isOpen) __Error.StreamIsClosed();
351
352             int n = _length - _position;
353             if (n > count) n = count;
354             if (n <= 0)
355                 return 0;
356
357             Contract.Assert(_position + n >= 0, "_position + n >= 0");  // len is less than 2^31 -1.
358
359             if (n <= 8)
360             {
361                 int byteCount = n;
362                 while (--byteCount >= 0)
363                     buffer[offset + byteCount] = _buffer[_position + byteCount];
364             }
365             else
366                 Buffer.InternalBlockCopy(_buffer, _position, buffer, offset, n);
367             _position += n;
368
369             return n;
370         }
371
372 #if FEATURE_ASYNC_IO
373         [HostProtection(ExternalThreading = true)]
374         [ComVisible(false)]
375         public override Task<int> ReadAsync(Byte[] buffer, int offset, int count, CancellationToken cancellationToken)
376         {
377             if (buffer==null)
378                 throw new ArgumentNullException("buffer", Environment.GetResourceString("ArgumentNull_Buffer"));
379             if (offset < 0)
380                 throw new ArgumentOutOfRangeException("offset", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
381             if (count < 0)
382                 throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
383             if (buffer.Length - offset < count)
384                 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
385             Contract.EndContractBlock(); // contract validation copied from Read(...)
386
387             // If cancellation was requested, bail early
388             if (cancellationToken.IsCancellationRequested) 
389                 return Task.FromCancellation<int>(cancellationToken);
390
391             try
392             {
393                 int n = Read(buffer, offset, count);
394                 var t = _lastReadTask;
395                 Contract.Assert(t == null || t.Status == TaskStatus.RanToCompletion, 
396                     "Expected that a stored last task completed successfully");
397                 return (t != null && t.Result == n) ? t : (_lastReadTask = Task.FromResult<int>(n));
398             }
399             catch (OperationCanceledException oce)
400             {
401                 return Task.FromCancellation<int>(oce);
402             }
403             catch (Exception exception)
404             {
405                 return Task.FromException<int>(exception);
406             }
407         }
408 #endif //FEATURE_ASYNC_IO
409
410
411         public override int ReadByte() {
412             if (!_isOpen) __Error.StreamIsClosed();
413             
414             if (_position >= _length) return -1;
415
416             return _buffer[_position++];
417         }
418
419
420 #if FEATURE_ASYNC_IO
421         public override Task CopyToAsync(Stream destination, Int32 bufferSize, CancellationToken cancellationToken) {
422
423             // This implementation offers beter performance compared to the base class version.
424
425             // The parameter checks must be in [....] with the base version:
426             if (destination == null)
427                 throw new ArgumentNullException("destination");
428             
429             if (bufferSize <= 0)
430                 throw new ArgumentOutOfRangeException("bufferSize", Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum"));
431
432             if (!CanRead && !CanWrite)
433                 throw new ObjectDisposedException(null, Environment.GetResourceString("ObjectDisposed_StreamClosed"));
434
435             if (!destination.CanRead && !destination.CanWrite)
436                 throw new ObjectDisposedException("destination", Environment.GetResourceString("ObjectDisposed_StreamClosed"));
437
438             if (!CanRead)
439                 throw new NotSupportedException(Environment.GetResourceString("NotSupported_UnreadableStream"));
440
441             if (!destination.CanWrite)
442                 throw new NotSupportedException(Environment.GetResourceString("NotSupported_UnwritableStream"));
443
444             Contract.EndContractBlock();
445
446             // If we have been inherited into a subclass, the following implementation could be incorrect
447             // since it does not call through to Read() or Write() which a subclass might have overriden.  
448             // To be safe we will only use this implementation in cases where we know it is safe to do so,
449             // and delegate to our base class (which will call into Read/Write) when we are not sure.
450             if (this.GetType() != typeof(MemoryStream))
451                 return base.CopyToAsync(destination, bufferSize, cancellationToken);
452
453             // If cancelled - return fast:
454             if (cancellationToken.IsCancellationRequested)
455                 return Task.FromCancellation(cancellationToken);
456            
457             // Avoid copying data from this buffer into a temp buffer:
458             //   (require that InternalEmulateRead does not throw,
459             //    otherwise it needs to be wrapped into try-catch-Task.FromException like memStrDest.Write below)
460
461             Int32 pos = _position;
462             Int32 n = InternalEmulateRead(_length - _position);
463
464             // If destination is not a memory stream, write there asynchronously:
465             MemoryStream memStrDest = destination as MemoryStream;
466             if (memStrDest == null)                 
467                 return destination.WriteAsync(_buffer, pos, n, cancellationToken);
468            
469             try {
470
471                 // If destination is a MemoryStream, CopyTo synchronously:
472                 memStrDest.Write(_buffer, pos, n);
473                 return Task.CompletedTask;
474
475             } catch(Exception ex) {
476                 return Task.FromException(ex);
477             }
478         }
479 #endif //FEATURE_ASYNC_IO
480
481
482         public override long Seek(long offset, SeekOrigin loc) {
483             if (!_isOpen) __Error.StreamIsClosed();
484
485             if (offset > MemStreamMaxLength)
486                 throw new ArgumentOutOfRangeException("offset", Environment.GetResourceString("ArgumentOutOfRange_StreamLength"));
487             switch(loc) {
488             case SeekOrigin.Begin: {
489                 int tempPosition = unchecked(_origin + (int)offset);
490                 if (offset < 0 || tempPosition < _origin)
491                     throw new IOException(Environment.GetResourceString("IO.IO_SeekBeforeBegin"));
492                 _position = tempPosition;
493                 break;
494             }  
495             case SeekOrigin.Current: {
496                 int tempPosition = unchecked(_position + (int)offset);
497                 if (unchecked(_position + offset) < _origin || tempPosition < _origin)
498                     throw new IOException(Environment.GetResourceString("IO.IO_SeekBeforeBegin"));
499                 _position = tempPosition;
500                 break;
501             }    
502             case SeekOrigin.End: {
503                 int tempPosition = unchecked(_length + (int)offset);
504                 if ( unchecked(_length + offset) < _origin || tempPosition < _origin )
505                     throw new IOException(Environment.GetResourceString("IO.IO_SeekBeforeBegin"));
506                 _position = tempPosition;
507                 break;
508             }
509             default:
510                 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidSeekOrigin"));
511             }
512
513             Contract.Assert(_position >= 0, "_position >= 0");
514             return _position;
515         }
516         
517         // Sets the length of the stream to a given value.  The new
518         // value must be nonnegative and less than the space remaining in
519         // the array, Int32.MaxValue - origin
520         // Origin is 0 in all cases other than a MemoryStream created on
521         // top of an existing array and a specific starting offset was passed 
522         // into the MemoryStream constructor.  The upper bounds prevents any 
523         // situations where a stream may be created on top of an array then 
524         // the stream is made longer than the maximum possible length of the 
525         // array (Int32.MaxValue).
526         // 
527         public override void SetLength(long value) {
528             if (value < 0 || value > Int32.MaxValue) {
529                 throw new ArgumentOutOfRangeException("value", Environment.GetResourceString("ArgumentOutOfRange_StreamLength"));
530             }
531             Contract.Ensures(_length - _origin == value);
532             Contract.EndContractBlock();
533             EnsureWriteable();
534
535             // Origin wasn't publicly exposed above.
536             Contract.Assert(MemStreamMaxLength == Int32.MaxValue);  // Check parameter validation logic in this method if this fails.
537             if (value > (Int32.MaxValue - _origin)) {
538                 throw new ArgumentOutOfRangeException("value", Environment.GetResourceString("ArgumentOutOfRange_StreamLength"));
539             }
540
541             int newLength = _origin + (int)value;
542             bool allocatedNewArray = EnsureCapacity(newLength);
543             if (!allocatedNewArray && newLength > _length)
544                 Array.Clear(_buffer, _length, newLength - _length);
545             _length = newLength;
546             if (_position > newLength) _position = newLength;
547
548         }
549         
550         public virtual byte[] ToArray() {
551 #if MONO
552             // Bug fix for BCL bug when _buffer is null
553             if (_length - _origin == 0)
554                 return EmptyArray<byte>.Value;
555 #endif
556             BCLDebug.Perf(_exposable, "MemoryStream::GetBuffer will let you avoid a copy.");
557             byte[] copy = new byte[_length - _origin];
558             Buffer.InternalBlockCopy(_buffer, _origin, copy, 0, _length - _origin);
559             return copy;
560         }
561     
562         public override void Write(byte[] buffer, int offset, int count) {
563             if (buffer==null)
564                 throw new ArgumentNullException("buffer", Environment.GetResourceString("ArgumentNull_Buffer"));
565             if (offset < 0)
566                 throw new ArgumentOutOfRangeException("offset", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
567             if (count < 0)
568                 throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
569             if (buffer.Length - offset < count)
570                 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
571             Contract.EndContractBlock();
572
573             if (!_isOpen) __Error.StreamIsClosed();
574             EnsureWriteable();
575
576             int i = _position + count;
577             // Check for overflow
578             if (i < 0)
579                 throw new IOException(Environment.GetResourceString("IO.IO_StreamTooLong"));
580
581             if (i > _length) {
582                 bool mustZero = _position > _length;
583                 if (i > _capacity) {
584                     bool allocatedNewArray = EnsureCapacity(i);
585                     if (allocatedNewArray)
586                         mustZero = false;
587                 }
588                 if (mustZero)
589                     Array.Clear(_buffer, _length, i - _length);
590                 _length = i;
591             }
592             if ((count <= 8) && (buffer != _buffer))
593             {
594                 int byteCount = count;
595                 while (--byteCount >= 0)
596                     _buffer[_position + byteCount] = buffer[offset + byteCount];
597             }
598             else
599                 Buffer.InternalBlockCopy(buffer, offset, _buffer, _position, count);
600             _position = i;
601
602         }
603
604 #if FEATURE_ASYNC_IO
605         [HostProtection(ExternalThreading = true)]
606         [ComVisible(false)]
607         public override Task WriteAsync(Byte[] buffer, int offset, int count, CancellationToken cancellationToken)
608         {
609             if (buffer == null)
610                 throw new ArgumentNullException("buffer", Environment.GetResourceString("ArgumentNull_Buffer"));
611             if (offset < 0)
612                 throw new ArgumentOutOfRangeException("offset", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
613             if (count < 0)
614                 throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
615             if (buffer.Length - offset < count)
616                 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
617             Contract.EndContractBlock(); // contract validation copied from Write(...)
618
619             // If cancellation is already requested, bail early
620             if (cancellationToken.IsCancellationRequested) 
621                 return Task.FromCancellation(cancellationToken);
622
623             try
624             {
625                 Write(buffer, offset, count);
626                 return Task.CompletedTask;
627             }
628             catch (OperationCanceledException oce)
629             {
630                 return Task.FromCancellation<VoidTaskResult>(oce);
631             }
632             catch (Exception exception)
633             {
634                 return Task.FromException(exception);
635             }
636         }
637 #endif // FEATURE_ASYNC_IO
638
639         public override void WriteByte(byte value) {
640             if (!_isOpen) __Error.StreamIsClosed();
641             EnsureWriteable();
642             
643             if (_position >= _length) {
644                 int newLength = _position + 1;
645                 bool mustZero = _position > _length;
646                 if (newLength >= _capacity) {
647                     bool allocatedNewArray = EnsureCapacity(newLength);
648                     if (allocatedNewArray)
649                         mustZero = false;
650                 }
651                 if (mustZero)
652                     Array.Clear(_buffer, _length, _position - _length);
653                 _length = newLength;
654             }
655             _buffer[_position++] = value;
656
657         }
658     
659         // Writes this MemoryStream to another stream.
660         public virtual void WriteTo(Stream stream) {
661             if (stream==null)
662                 throw new ArgumentNullException("stream", Environment.GetResourceString("ArgumentNull_Stream"));
663             Contract.EndContractBlock();
664
665             if (!_isOpen) __Error.StreamIsClosed();
666             stream.Write(_buffer, _origin, _length - _origin);
667         }
668
669 #if CONTRACTS_FULL
670         [ContractInvariantMethod]
671         private void ObjectInvariantMS() {
672             Contract.Invariant(_origin >= 0);
673             Contract.Invariant(_origin <= _position);
674             Contract.Invariant(_length <= _capacity);
675             // equivalent to _origin > 0 => !expandable, and using fact that _origin is non-negative.
676             Contract.Invariant(_origin == 0 || !_expandable);
677         }
678 #endif
679     }
680 }