The Labs \ Source Viewer \ SSCLI \ System.IO \ MemoryStream

  1. // ==++==
  2. //
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. //
  14. // ==--==
  15. /*============================================================
  16. **
  17. ** Class:  MemoryStream
  18. **
  19. **
  20. ** Purpose: A Stream whose backing store is memory.  Great
  21. ** for temporary storage without creating a temp file.  Also
  22. ** lets users expose a byte[] as a stream.
  23. **
  24. **
  25. ===========================================================*/
  26. using System;
  27. using System.Runtime.InteropServices;
  28. namespace System.IO
  29. {
  30.     // A MemoryStream represents a Stream in memory (ie, it has no backing store).
  31.     // This stream may reduce the need for temporary buffers and files in
  32.     // an application.
  33.     //
  34.     // There are two ways to create a MemoryStream. You can initialize one
  35.     // from an unsigned byte array, or you can create an empty one. Empty
  36.     // memory streams are resizable, while ones created with a byte array provide
  37.     // a stream "view" of the data.
  38.     [Serializable()]
  39.     [ComVisible(true)]
  40.     public class MemoryStream : Stream
  41.     {
  42.         private byte[] _buffer;
  43.         // Either allocated internally or externally.
  44.         private int _origin;
  45.         // For user-provided arrays, start at this origin
  46.         private int _position;
  47.         // read/write head.
  48.         private int _length;
  49.         // Number of bytes within the memory stream
  50.         private int _capacity;
  51.         // length of usable portion of buffer for stream
  52.         // Note that _capacity == _buffer.Length for non-user-provided byte[]'s
  53.         private bool _expandable;
  54.         // User-provided buffers aren't expandable.
  55.         private bool _writable;
  56.         // Can user write to this stream?
  57.         private bool _exposable;
  58.         // Whether the array can be returned to the user.
  59.         private bool _isOpen;
  60.         // Is this stream open or closed?
  61.         private const int MemStreamMaxLength = Int32.MaxValue;
  62.        
  63.         public MemoryStream() : this(0)
  64.         {
  65.         }
  66.        
  67.         public MemoryStream(int capacity)
  68.         {
  69.             if (capacity < 0) {
  70.                 throw new ArgumentOutOfRangeException("capacity", Environment.GetResourceString("ArgumentOutOfRange_NegativeCapacity"));
  71.             }
  72.            
  73.             _buffer = new byte[capacity];
  74.             _capacity = capacity;
  75.             _expandable = true;
  76.             _writable = true;
  77.             _exposable = true;
  78.             _origin = 0;
  79.             // Must be 0 for byte[]'s created by MemoryStream
  80.             _isOpen = true;
  81.         }
  82.        
  83.         public MemoryStream(byte[] buffer) : this(buffer, true)
  84.         {
  85.         }
  86.        
  87.         public MemoryStream(byte[] buffer, bool writable)
  88.         {
  89.             if (buffer == null)
  90.                 throw new ArgumentNullException("buffer", Environment.GetResourceString("ArgumentNull_Buffer"));
  91.             _buffer = buffer;
  92.             _length = _capacity = buffer.Length;
  93.             _writable = writable;
  94.             _exposable = false;
  95.             _origin = 0;
  96.             _isOpen = true;
  97.         }
  98.        
  99.         public MemoryStream(byte[] buffer, int index, int count) : this(buffer, index, count, true, false)
  100.         {
  101.         }
  102.        
  103.         public MemoryStream(byte[] buffer, int index, int count, bool writable) : this(buffer, index, count, writable, false)
  104.         {
  105.         }
  106.        
  107.         public MemoryStream(byte[] buffer, int index, int count, bool writable, bool publiclyVisible)
  108.         {
  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.            
  118.             _buffer = buffer;
  119.             _origin = _position = index;
  120.             _length = _capacity = index + count;
  121.             _writable = writable;
  122.             _exposable = publiclyVisible;
  123.             // Can GetBuffer return the array?
  124.             _expandable = false;
  125.             _isOpen = true;
  126.         }
  127.        
  128.         public override bool CanRead {
  129.             get { return _isOpen; }
  130.         }
  131.        
  132.         public override bool CanSeek {
  133.             get { return _isOpen; }
  134.         }
  135.        
  136.         public override bool CanWrite {
  137.             get { return _writable; }
  138.         }
  139.        
  140.         protected override void Dispose(bool disposing)
  141.         {
  142.             try {
  143.                 if (disposing) {
  144.                     _isOpen = false;
  145.                     _writable = false;
  146.                     _expandable = false;
  147.                     // Don't set buffer to null - allow GetBuffer & ToArray to work.
  148.                 }
  149.             }
  150.             finally {
  151.                 // Call base.Close() to cleanup async IO resources
  152.                 base.Dispose(disposing);
  153.             }
  154.         }
  155.        
  156.         // returns a bool saying whether we allocated a new array.
  157.         private bool EnsureCapacity(int value)
  158.         {
  159.             // Check for overflow
  160.             if (value < 0)
  161.                 throw new IOException(Environment.GetResourceString("IO.IO_StreamTooLong"));
  162.             if (value > _capacity) {
  163.                 int newCapacity = value;
  164.                 if (newCapacity < 256)
  165.                     newCapacity = 256;
  166.                 if (newCapacity < _capacity * 2)
  167.                     newCapacity = _capacity * 2;
  168.                 Capacity = newCapacity;
  169.                 return true;
  170.             }
  171.             return false;
  172.         }
  173.        
  174.         public override void Flush()
  175.         {
  176.         }
  177.        
  178.         public virtual byte[] GetBuffer()
  179.         {
  180.             if (!_exposable)
  181.                 throw new UnauthorizedAccessException(Environment.GetResourceString("UnauthorizedAccess_MemStreamBuffer"));
  182.             return _buffer;
  183.         }
  184.        
  185.         // -------------- PERF: Internal functions for fast direct access of MemoryStream buffer (cf. BinaryReader for usage) ---------------
  186.        
  187.         // PERF: Internal sibling of GetBuffer, always returns a buffer (cf. GetBuffer())
  188.         internal byte[] InternalGetBuffer()
  189.         {
  190.             return _buffer;
  191.         }
  192.        
  193.         // PERF: Get origin and length - used in ResourceWriter.
  194.         internal void InternalGetOriginAndLength(out int origin, out int length)
  195.         {
  196.             if (!_isOpen)
  197.                 __Error.StreamIsClosed();
  198.             origin = _origin;
  199.             length = _length;
  200.         }
  201.        
  202.         // PERF: True cursor position, we don't need _origin for direct access
  203.         internal int InternalGetPosition()
  204.         {
  205.             if (!_isOpen)
  206.                 __Error.StreamIsClosed();
  207.             return _position;
  208.         }
  209.        
  210.         // PERF: Takes out Int32 as fast as possible
  211.         internal int InternalReadInt32()
  212.         {
  213.             if (!_isOpen)
  214.                 __Error.StreamIsClosed();
  215.            
  216.             int pos = (_position += 4);
  217.             // use temp to avoid race
  218.             if (pos > _length) {
  219.                 _position = _length;
  220.                 __Error.EndOfFile();
  221.             }
  222.             return (int)(_buffer[pos - 4] | _buffer[pos - 3] << 8 | _buffer[pos - 2] << 16 | _buffer[pos - 1] << 24);
  223.         }
  224.        
  225.         // PERF: Get actual length of bytes available for read; do sanity checks; shift position - i.e. everything except actual copying bytes
  226.         internal int InternalEmulateRead(int count)
  227.         {
  228.             if (!_isOpen)
  229.                 __Error.StreamIsClosed();
  230.            
  231.             int n = _length - _position;
  232.             if (n > count)
  233.                 n = count;
  234.             if (n < 0)
  235.                 n = 0;
  236.            
  237.             BCLDebug.Assert(_position + n >= 0, "_position + n >= 0");
  238.             // len is less than 2^31 -1.
  239.             _position += n;
  240.             return n;
  241.         }
  242.        
  243.         // Gets &; sets the capacity (number of bytes allocated) for this stream.
  244.         // The capacity cannot be set to a value less than the current length
  245.         // of the stream.
  246.         //
  247.         public virtual int Capacity {
  248.             get {
  249.                 if (!_isOpen)
  250.                     __Error.StreamIsClosed();
  251.                 return _capacity - _origin;
  252.             }
  253.             set {
  254.                 if (!_isOpen)
  255.                     __Error.StreamIsClosed();
  256.                 if (value != _capacity) {
  257.                     if (!_expandable)
  258.                         __Error.MemoryStreamNotExpandable();
  259.                     if (value < _length)
  260.                         throw new ArgumentOutOfRangeException("value", Environment.GetResourceString("ArgumentOutOfRange_SmallCapacity"));
  261.                     if (value > 0) {
  262.                         byte[] newBuffer = new byte[value];
  263.                         if (_length > 0)
  264.                             Buffer.InternalBlockCopy(_buffer, 0, newBuffer, 0, _length);
  265.                         _buffer = newBuffer;
  266.                     }
  267.                     else {
  268.                         _buffer = null;
  269.                     }
  270.                     _capacity = value;
  271.                 }
  272.             }
  273.         }
  274.        
  275.         public override long Length {
  276.             get {
  277.                 if (!_isOpen)
  278.                     __Error.StreamIsClosed();
  279.                 return _length - _origin;
  280.             }
  281.         }
  282.        
  283.         public override long Position {
  284.             get {
  285.                 if (!_isOpen)
  286.                     __Error.StreamIsClosed();
  287.                 return _position - _origin;
  288.             }
  289.             set {
  290.                 if (!_isOpen)
  291.                     __Error.StreamIsClosed();
  292.                 if (value < 0)
  293.                     throw new ArgumentOutOfRangeException("value", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
  294.                 if (value > MemStreamMaxLength)
  295.                     throw new ArgumentOutOfRangeException("value", Environment.GetResourceString("ArgumentOutOfRange_MemStreamLength"));
  296.                 _position = _origin + (int)value;
  297.             }
  298.         }
  299.        
  300.         public override int Read(        [In(), Out()]
  301. byte[] buffer, int offset, int count)
  302.         {
  303.             if (!_isOpen)
  304.                 __Error.StreamIsClosed();
  305.             if (buffer == null)
  306.                 throw new ArgumentNullException("buffer", Environment.GetResourceString("ArgumentNull_Buffer"));
  307.             if (offset < 0)
  308.                 throw new ArgumentOutOfRangeException("offset", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
  309.             if (count < 0)
  310.                 throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
  311.             if (buffer.Length - offset < count)
  312.                 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
  313.            
  314.             int n = _length - _position;
  315.             if (n > count)
  316.                 n = count;
  317.             if (n <= 0)
  318.                 return 0;
  319.            
  320.             BCLDebug.Assert(_position + n >= 0, "_position + n >= 0");
  321.             // len is less than 2^31 -1.
  322.             if (n <= 8) {
  323.                 int byteCount = n;
  324.                 while (--byteCount >= 0)
  325.                     buffer[offset + byteCount] = _buffer[_position + byteCount];
  326.             }
  327.             else
  328.                 Buffer.InternalBlockCopy(_buffer, _position, buffer, offset, n);
  329.             _position += n;
  330.             return n;
  331.         }
  332.        
  333.         public override int ReadByte()
  334.         {
  335.             if (!_isOpen)
  336.                 __Error.StreamIsClosed();
  337.             if (_position >= _length)
  338.                 return -1;
  339.             return _buffer[_position++];
  340.         }
  341.        
  342.        
  343.         public override long Seek(long offset, SeekOrigin loc)
  344.         {
  345.             if (!_isOpen)
  346.                 __Error.StreamIsClosed();
  347.             if (offset > MemStreamMaxLength)
  348.                 throw new ArgumentOutOfRangeException("offset", Environment.GetResourceString("ArgumentOutOfRange_MemStreamLength"));
  349.             switch (loc) {
  350.                 case SeekOrigin.Begin:
  351.                     if (offset < 0)
  352.                         throw new IOException(Environment.GetResourceString("IO.IO_SeekBeforeBegin"));
  353.                     _position = _origin + (int)offset;
  354.                     break;
  355.                 case SeekOrigin.Current:
  356.                    
  357.                     if (offset + _position < _origin)
  358.                         throw new IOException(Environment.GetResourceString("IO.IO_SeekBeforeBegin"));
  359.                     _position += (int)offset;
  360.                     break;
  361.                 case SeekOrigin.End:
  362.                    
  363.                     if (_length + offset < _origin)
  364.                         throw new IOException(Environment.GetResourceString("IO.IO_SeekBeforeBegin"));
  365.                     _position = _length + (int)offset;
  366.                     break;
  367.                 default:
  368.                    
  369.                     throw new ArgumentException(Environment.GetResourceString("Argument_InvalidSeekOrigin"));
  370.                     break;
  371.             }
  372.            
  373.             BCLDebug.Assert(_position >= 0, "_position >= 0");
  374.             return _position;
  375.         }
  376.        
  377.         // Sets the length of the stream to a given value. The new
  378.         // value must be nonnegative and less than the space remaining in
  379.         // the array, Int32.MaxValue - origin
  380.         // Origin is 0 in all cases other than a MemoryStream created on
  381.         // top of an existing array and a specific starting offset was passed
  382.         // into the MemoryStream constructor. The upper bounds prevents any
  383.         // situations where a stream may be created on top of an array then
  384.         // the stream is made longer than the maximum possible length of the
  385.         // array (Int32.MaxValue).
  386.         //
  387.         public override void SetLength(long value)
  388.         {
  389.             if (!_writable)
  390.                 __Error.WriteNotSupported();
  391.             if (value > MemStreamMaxLength)
  392.                 throw new ArgumentOutOfRangeException("value", Environment.GetResourceString("ArgumentOutOfRange_MemStreamLength"));
  393.             if (value < 0 || value > (Int32.MaxValue - _origin)) {
  394.                 throw new ArgumentOutOfRangeException("value", Environment.GetResourceString("ArgumentOutOfRange_MemStreamLength"));
  395.             }
  396.             int newLength = _origin + (int)value;
  397.             bool allocatedNewArray = EnsureCapacity(newLength);
  398.             if (!allocatedNewArray && newLength > _length)
  399.                 Array.Clear(_buffer, _length, newLength - _length);
  400.             _length = newLength;
  401.             if (_position > newLength)
  402.                 _position = newLength;
  403.         }
  404.        
  405.         public virtual byte[] ToArray()
  406.         {
  407.             BCLDebug.Perf(_exposable, "MemoryStream::GetBuffer will let you avoid a copy.");
  408.             byte[] copy = new byte[_length - _origin];
  409.             Buffer.InternalBlockCopy(_buffer, _origin, copy, 0, _length - _origin);
  410.             return copy;
  411.         }
  412.        
  413.         public override void Write(byte[] buffer, int offset, int count)
  414.         {
  415.             if (!_isOpen)
  416.                 __Error.StreamIsClosed();
  417.             if (!_writable)
  418.                 __Error.WriteNotSupported();
  419.             if (buffer == null)
  420.                 throw new ArgumentNullException("buffer", Environment.GetResourceString("ArgumentNull_Buffer"));
  421.             if (offset < 0)
  422.                 throw new ArgumentOutOfRangeException("offset", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
  423.             if (count < 0)
  424.                 throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
  425.             if (buffer.Length - offset < count)
  426.                 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
  427.            
  428.             int i = _position + count;
  429.             // Check for overflow
  430.             if (i < 0)
  431.                 throw new IOException(Environment.GetResourceString("IO.IO_StreamTooLong"));
  432.            
  433.             if (i > _length) {
  434.                 bool mustZero = _position > _length;
  435.                 if (i > _capacity) {
  436.                     bool allocatedNewArray = EnsureCapacity(i);
  437.                     if (allocatedNewArray)
  438.                         mustZero = false;
  439.                 }
  440.                 if (mustZero)
  441.                     Array.Clear(_buffer, _length, i - _length);
  442.                 _length = i;
  443.             }
  444.             if (count <= 8) {
  445.                 int byteCount = count;
  446.                 while (--byteCount >= 0)
  447.                     _buffer[_position + byteCount] = buffer[offset + byteCount];
  448.             }
  449.             else
  450.                 Buffer.InternalBlockCopy(buffer, offset, _buffer, _position, count);
  451.             _position = i;
  452.             return;
  453.         }
  454.        
  455.         public override void WriteByte(byte value)
  456.         {
  457.             if (!_isOpen)
  458.                 __Error.StreamIsClosed();
  459.             if (!_writable)
  460.                 __Error.WriteNotSupported();
  461.             if (_position >= _length) {
  462.                 int newLength = _position + 1;
  463.                 bool mustZero = _position > _length;
  464.                 if (newLength >= _capacity) {
  465.                     bool allocatedNewArray = EnsureCapacity(newLength);
  466.                     if (allocatedNewArray)
  467.                         mustZero = false;
  468.                 }
  469.                 if (mustZero)
  470.                     Array.Clear(_buffer, _length, _position - _length);
  471.                 _length = newLength;
  472.             }
  473.             _buffer[_position++] = value;
  474.         }
  475.        
  476.         // Writes this MemoryStream to another stream.
  477.         public virtual void WriteTo(Stream stream)
  478.         {
  479.             if (!_isOpen)
  480.                 __Error.StreamIsClosed();
  481.             if (stream == null)
  482.                 throw new ArgumentNullException("stream", Environment.GetResourceString("ArgumentNull_Stream"));
  483.             stream.Write(_buffer, _origin, _length - _origin);
  484.         }
  485.     }
  486. }

Developer Fusion