| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403 |
- //
- // System.IO.MemoryStream
- //
- // Author: Marcin Szczepanski ([email protected])
- //
- // TODO: Clarify some of the lamespec issues
- //
- namespace System.IO {
- public class MemoryStream : Stream {
- private bool canRead;
- private bool canSeek;
- private bool canWrite;
-
- private bool allowGetBuffer;
- private int capacity;
- private byte[] internalBuffer;
- private int initialLength;
- private bool expandable;
- private bool streamClosed = false;
- private long position = 0;
-
- public MemoryStream() {
- canRead = true;
- canSeek = true;
- canWrite = true;
- capacity = 0;
- internalBuffer = new byte[0];
- allowGetBuffer = true;
- expandable = true;
- }
- public MemoryStream( byte[] buffer ) {
- InternalConstructor( buffer, 0, buffer.Length, true, false );
- }
- public MemoryStream( int capacity ) {
-
- canRead = true;
- canSeek = true;
- canWrite = true;
-
- this.capacity = capacity;
- initialLength = capacity;
- internalBuffer = new byte[ capacity ];
- expandable = true;
- allowGetBuffer = true;
- }
- public MemoryStream( byte[] buffer, bool writeable ) {
- if( buffer == null ) {
- throw new ArgumentNullException();
- }
- InternalConstructor( buffer, 0, buffer.Length, writeable, true );
- }
-
- public MemoryStream( byte[] buffer, int index, int count ) {
- if( buffer == null ) {
- throw new ArgumentNullException();
- }
-
- InternalConstructor( buffer, index, count, true, false );
- }
-
- public MemoryStream( byte[] buffer, int index, int count, bool writeable ) {
-
- if( buffer == null ) {
- throw new ArgumentNullException();
- }
-
- InternalConstructor( buffer, index, count, writeable, true );
- }
- public MemoryStream( byte[] buffer, int index, int count, bool writeable, bool publicallyVisible ) {
- InternalConstructor( buffer, index, count, writeable, publicallyVisible );
- }
- private void InternalConstructor( byte[] buffer, int index, int count, bool writeable, bool publicallyVisible ) {
-
- if( buffer == null ) {
- throw new ArgumentNullException();
- } else if ( index < 0 || count < 0 ) {
- throw new ArgumentOutOfRangeException();
- } else if ( buffer.Length - index < count ) {
- throw new ArgumentException();
- }
- // LAMESPEC: The spec says to throw an UnauthorisedAccessException if
- // publicallyVisibile is fale?! Doesn't that defy the point of having
- // it there in the first place. I'll leave it out for now.
-
- canRead = true;
- canSeek = true;
- canWrite = writeable;
- initialLength = count;
- internalBuffer = new byte[ count ];
- capacity = count;
- Array.Copy( buffer, index, internalBuffer, 0, count );
- allowGetBuffer = publicallyVisible;
- expandable = false;
- }
- public override bool CanRead {
- get {
- return this.canRead;
- }
- }
- public override bool CanSeek {
- get {
- return this.canSeek;
- }
- }
- public override bool CanWrite {
- get {
- return this.canWrite;
- }
- }
- public virtual int Capacity {
- get {
- return this.capacity;
- }
- set {
- if( value < 0 || value < capacity ) {
- throw new ArgumentOutOfRangeException( "New capacity cannot be negative or less than the current capacity" );
- } else if( !expandable ) {
- throw new NotSupportedException( "Cannot expand this MemoryStream" );
- }
- byte[] newBuffer = new byte[ value ];
- Array.Copy( internalBuffer, 0, newBuffer, 0, capacity );
- capacity = value;
- }
- }
- public override long Length {
- get {
- // LAMESPEC: The spec says to throw an IOException if the
- // stream is closed and an ObjectDisposedException if
- // "methods were called after the stream was closed". What
- // is the difference?
- if( streamClosed ) {
- throw new IOException( "MemoryStream is closed" );
- }
-
- return internalBuffer.Length;
- }
- }
- public override long Position {
- get {
- if( streamClosed ) {
- throw new IOException( "MemoryStream is closed" );
- }
- return position;
- }
- set {
- if( position < 0 ) {
- throw new ArgumentOutOfRangeException( "Position cannot be negative" );
- } else if( streamClosed ) {
- throw new IOException( "MemoryStream is closed" );
- }
-
- position = value;
- if( position > internalBuffer.Length + 1 ) {
- position = internalBuffer.Length + 1;
- }
- }
- }
-
- public override void Close() {
- if( streamClosed ) {
- throw new IOException( "MemoryStream already closed" );
- }
- streamClosed = true;
- Dispose( true );
- }
- protected override void Dispose( bool disposing ) { }
- public override void Flush() { }
- public virtual byte[] GetBuffer() {
- if( !allowGetBuffer ) {
- throw new UnauthorizedAccessException();
- }
- return internalBuffer;
- }
- public override int Read( byte[] buffer, int offset, int count ) {
- if( buffer == null ) {
- throw new ArgumentNullException();
- } else if( offset < 0 || count < 0 ) {
- throw new ArgumentOutOfRangeException();
- } else if( internalBuffer.Length - offset < count ) {
- throw new ArgumentException();
- } else if ( streamClosed ) {
- throw new ObjectDisposedException( "MemoryStream" );
- }
- long ReadTo;
- if( position + count > internalBuffer.Length ) {
- ReadTo = internalBuffer.Length;
- } else {
- ReadTo = position + (long)count;
- }
- Array.Copy( internalBuffer, (int)position, buffer, offset, (int)(ReadTo - position) );
- int bytesRead = (int)(ReadTo - position);
- position = ReadTo;
- return bytesRead;
- }
- public override int ReadByte( ) {
- if( streamClosed ) {
- throw new ObjectDisposedException( "MemoryStream" );
- }
- // LAMESPEC: What happens if we're at the end of the stream? It's unspecified in the
- // docs but tests against the MS impl. show it returns -1
- //
- if( position >= internalBuffer.Length ) {
- return -1;
- } else {
- return internalBuffer[ position++ ];
- }
- }
-
- public override long Seek( long offset, SeekOrigin loc ) {
- long refPoint;
- if( streamClosed ) {
- throw new ObjectDisposedException( "MemoryStream" );
- }
- switch( loc ) {
- case SeekOrigin.Begin:
- refPoint = 0;
- break;
- case SeekOrigin.Current:
- refPoint = position;
- break;
- case SeekOrigin.End:
- refPoint = internalBuffer.Length;
- break;
- default:
- throw new ArgumentException( "Invalid SeekOrigin" );
- }
- // LAMESPEC: My goodness, how may LAMESPECs are there in this
- // class! :) In the spec for the Position property it's stated
- // "The position must not be more than one byte beyond the end of the stream."
- // In the spec for seek it says "Seeking to any location beyond the length of the
- // stream is supported." That's a contradiction i'd say.
- // I guess seek can go anywhere but if you use position it may get moved back.
- if( refPoint + offset < 0 ) {
- throw new IOException( "Attempted to seek before start of MemoryStream" );
- } else if( offset > internalBuffer.Length ) {
- throw new ArgumentOutOfRangeException( "Offset cannot be greater than length of MemoryStream" );
- }
- position = refPoint + offset;
- return position;
- }
-
-
- public override void SetLength( long value ) {
- if( streamClosed ) {
- throw new ObjectDisposedException( "MemoryStream" );
- } else if( !expandable && value > capacity ) {
- throw new NotSupportedException( "Expanding this MemoryStream is not supported" );
- } else if( !canWrite ) {
- throw new IOException( "Cannot write to this MemoryStream" );
- } else if( value < 0 ) {
- // LAMESPEC: AGAIN! It says to throw this exception if value is
- // greater than "the maximum length of the MemoryStream". I haven't
- // seen anywhere mention what the maximum length of a MemoryStream is and
- // since we're this far this memory stream is expandable.
- throw new ArgumentOutOfRangeException();
- }
- byte[] newBuffer;
- newBuffer = new byte[ value ];
-
- if( value < capacity ) {
- // truncate
- Array.Copy( internalBuffer, 0, newBuffer, 0, (int)value );
- } else {
- // expand
- Array.Copy( internalBuffer, 0, newBuffer, 0, internalBuffer.Length );
- }
- internalBuffer = newBuffer;
- capacity = (int)value;
- }
-
-
- public virtual byte[] ToArray() {
-
- if( streamClosed ) {
- throw new ArgumentException( "The MemoryStream has been closed" );
- }
-
- byte[] outBuffer = new byte[capacity];
- Array.Copy( internalBuffer, 0, outBuffer, 0, capacity);
- return outBuffer;
- }
- // LAMESPEC: !! It says that "offset" is "offset in buffer at which
- // to begin writing", I presume this should be "offset in buffer at which
- // to begin reading"
- public override void Write( byte[] buffer, int offset, int count ) {
- if( buffer == null ) {
- throw new ArgumentNullException();
- } else if( !canWrite ) {
- throw new NotSupportedException();
- } else if( buffer.Length - offset < count ) {
- throw new ArgumentException();
- } else if( offset < 0 || count < 0 ) {
- throw new ArgumentOutOfRangeException();
- } else if( streamClosed ) {
- throw new ObjectDisposedException( "MemoryStream" );
- }
- if( position + count > capacity ) {
- if( expandable ) {
- // expand the buffer
- SetLength( position + count );
- } else {
- // only write as many bytes as will fit
- count = (int)((long)capacity - position);
- }
- }
- Array.Copy( buffer, offset, internalBuffer, (int)position, count );
- position += count;
-
- }
- public override void WriteByte( byte value ) {
- if( streamClosed ) {
- throw new ObjectDisposedException( "MemoryStream" );
- }
- if( position >= capacity ) {
- SetLength( capacity + 1 );
- }
- internalBuffer[ position++ ] = value;
- }
-
- public virtual void WriteTo( Stream stream ) {
- if( stream == null ) {
- throw new ArgumentNullException();
- }
- stream.Write( internalBuffer, 0, internalBuffer.Length );
-
- }
-
-
- }
- }
|