X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fclass%2Fcorlib%2FSystem.IO%2FMemoryStream.cs;h=4ce86df30b616f0b9ff96498f8d7fa783d76a698;hb=e41cdd1666eb179e2a9bc83820f361fa5a56ceec;hp=a68fe6ad30bed281fb159fbd45091c87eb1a632c;hpb=b6b13e72e91d5b529a6306ce53bda685932c77db;p=mono.git diff --git a/mcs/class/corlib/System.IO/MemoryStream.cs b/mcs/class/corlib/System.IO/MemoryStream.cs index a68fe6ad30b..4ce86df30b6 100644 --- a/mcs/class/corlib/System.IO/MemoryStream.cs +++ b/mcs/class/corlib/System.IO/MemoryStream.cs @@ -1,17 +1,15 @@ // -// System.IO.MemoryStream +// System.IO.MemoryStream.cs // // Authors: Marcin Szczepanski (marcins@zipworld.com.au) // Patrik Torstensson // Gonzalo Paniagua Javier (gonzalo@ximian.com) +// Marek Safar (marek.safar@gmail.com) // // (c) 2001,2002 Marcin Szczepanski, Patrik Torstensson // (c) 2003 Ximian, Inc. (http://www.ximian.com) -// Copyright (C) 2004 Novell (http://www.novell.com) -// - -// // Copyright (C) 2004 Novell, Inc (http://www.novell.com) +// Copyright 2011 Xamarin, Inc (http://www.xamarin.com) // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -35,11 +33,16 @@ using System.Globalization; using System.Runtime.InteropServices; +using System.Threading; +#if NET_4_5 +using System.Threading.Tasks; +#endif namespace System.IO { [Serializable] - [MonoTODO ("Fix serialization compatibility with MS.NET")] + [ComVisible (true)] + [MonoLimitation ("Serialization format not compatible with .NET")] public class MemoryStream : Stream { bool canWrite; @@ -51,6 +54,11 @@ namespace System.IO bool expandable; bool streamClosed; int position; + int dirty_bytes; +#if NET_4_5 + [NonSerialized] + Task read_task; +#endif public MemoryStream () : this (0) { @@ -78,12 +86,12 @@ namespace System.IO InternalConstructor (buffer, 0, buffer.Length, true, false); } - public MemoryStream (byte [] buffer, bool writeable) + public MemoryStream (byte [] buffer, bool writable) { if (buffer == null) throw new ArgumentNullException ("buffer"); - InternalConstructor (buffer, 0, buffer.Length, writeable, false); + InternalConstructor (buffer, 0, buffer.Length, writable, false); } public MemoryStream (byte [] buffer, int index, int count) @@ -91,17 +99,17 @@ namespace System.IO InternalConstructor (buffer, index, count, true, false); } - public MemoryStream (byte [] buffer, int index, int count, bool writeable) + public MemoryStream (byte [] buffer, int index, int count, bool writable) { - InternalConstructor (buffer, index, count, writeable, false); + InternalConstructor (buffer, index, count, writable, false); } - public MemoryStream (byte [] buffer, int index, int count, bool writeable, bool publicallyVisible) + public MemoryStream (byte [] buffer, int index, int count, bool writable, bool publiclyVisible) { - InternalConstructor (buffer, index, count, writeable, publicallyVisible); + InternalConstructor (buffer, index, count, writable, publiclyVisible); } - void InternalConstructor (byte [] buffer, int index, int count, bool writeable, bool publicallyVisible) + void InternalConstructor (byte [] buffer, int index, int count, bool writable, bool publicallyVisible) { if (buffer == null) throw new ArgumentNullException ("buffer"); @@ -113,7 +121,7 @@ namespace System.IO throw new ArgumentException ("index+count", "The size of the buffer is less than index + count."); - canWrite = writeable; + canWrite = writable; internalBuffer = buffer; capacity = count + index; @@ -131,12 +139,6 @@ namespace System.IO throw new ObjectDisposedException ("MemoryStream"); } - void CheckIfClosedThrowIO () - { - if (streamClosed) - throw new IOException ("MemoryStream is closed"); - } - public override bool CanRead { get { return !streamClosed; } } @@ -157,8 +159,6 @@ namespace System.IO set { CheckIfClosedThrowDisposed (); - if (value == capacity) - return; // LAMENESS: see MemoryStreamTest.ConstructorFive if (!expandable) throw new NotSupportedException ("Cannot expand this MemoryStream"); @@ -167,12 +167,17 @@ namespace System.IO throw new ArgumentOutOfRangeException ("value", "New capacity cannot be negative or less than the current capacity " + value + " " + capacity); + if (internalBuffer != null && value == internalBuffer.Length) + return; + byte [] newBuffer = null; if (value != 0) { newBuffer = new byte [value]; - Buffer.BlockCopyInternal (internalBuffer, 0, newBuffer, 0, length); + if (internalBuffer != null) + Buffer.BlockCopy (internalBuffer, 0, newBuffer, 0, length); } + dirty_bytes = 0; // discard any dirty area beyond previous length internalBuffer = newBuffer; // It's null when capacity is set to 0 capacity = value; } @@ -212,7 +217,7 @@ namespace System.IO } } - public override void Close () + protected override void Dispose (bool disposing) { streamClosed = true; expandable = false; @@ -233,8 +238,6 @@ namespace System.IO public override int Read ([In,Out] byte [] buffer, int offset, int count) { - CheckIfClosedThrowDisposed (); - if (buffer == null) throw new ArgumentNullException ("buffer"); @@ -245,13 +248,15 @@ namespace System.IO throw new ArgumentException ("offset+count", "The size of the buffer is less than offset + count."); + CheckIfClosedThrowDisposed (); + if (position >= length || count == 0) return 0; if (position > length - count) count = length - position; - Buffer.BlockCopyInternal (internalBuffer, position, buffer, offset, count); + Buffer.BlockCopy (internalBuffer, position, buffer, offset, count); position += count; return count; } @@ -316,6 +321,18 @@ namespace System.IO return minimum; } + void Expand (int newSize) + { + // We don't need to take into account the dirty bytes when incrementing the + // Capacity, as changing it will only preserve the valid clear region. + if (newSize > capacity) + Capacity = CalculateNewCapacity (newSize); + else if (dirty_bytes > 0) { + Array.Clear (internalBuffer, length, dirty_bytes); + dirty_bytes = 0; + } + } + public override void SetLength (long value) { if (!expandable && value > capacity) @@ -336,12 +353,11 @@ namespace System.IO throw new ArgumentOutOfRangeException (); int newSize = (int) value + initialIndex; - if (newSize > capacity) - Capacity = CalculateNewCapacity (newSize); - else if (newSize < length) - // zeroize present data (so we don't get it - // back if we expand the stream using Seek) - Array.Clear (internalBuffer, newSize, length - newSize); + + if (newSize > length) + Expand (newSize); + else if (newSize < length) // Postpone the call to Array.Clear till expand time + dirty_bytes += length - newSize; length = newSize; if (position > length) @@ -353,17 +369,13 @@ namespace System.IO int l = length - initialIndex; byte[] outBuffer = new byte [l]; - Buffer.BlockCopyInternal (internalBuffer, initialIndex, outBuffer, 0, l); + if (internalBuffer != null) + Buffer.BlockCopy (internalBuffer, initialIndex, outBuffer, 0, l); return outBuffer; } public override void Write (byte [] buffer, int offset, int count) { - CheckIfClosedThrowDisposed (); - - if (!canWrite) - throw new NotSupportedException ("Cannot write to this stream."); - if (buffer == null) throw new ArgumentNullException ("buffer"); @@ -374,11 +386,16 @@ namespace System.IO throw new ArgumentException ("offset+count", "The size of the buffer is less than offset + count."); + CheckIfClosedThrowDisposed (); + + if (!CanWrite) + throw new NotSupportedException ("Cannot write to this stream."); + // reordered to avoid possible integer overflow - if (position > capacity - count) - Capacity = CalculateNewCapacity (position + count); + if (position > length - count) + Expand (position + count); - Buffer.BlockCopyInternal (buffer, offset, internalBuffer, position, count); + Buffer.BlockCopy (buffer, offset, internalBuffer, position, count); position += count; if (position >= length) length = position; @@ -390,11 +407,10 @@ namespace System.IO if (!canWrite) throw new NotSupportedException ("Cannot write to this stream."); - if (position >= capacity) - Capacity = CalculateNewCapacity (position + 1); - - if (position >= length) + if (position >= length) { + Expand (position + 1); length = position + 1; + } internalBuffer [position++] = value; } @@ -408,5 +424,77 @@ namespace System.IO stream.Write (internalBuffer, initialIndex, length - initialIndex); } + +#if NET_4_5 + + public override Task CopyToAsync (Stream destination, int bufferSize, CancellationToken cancellationToken) + { + // TODO: Specialization but what for? + return base.CopyToAsync (destination, bufferSize, cancellationToken); + } + + public override Task FlushAsync (CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + return TaskConstants.Canceled; + + try { + Flush (); + return TaskConstants.Finished; + } catch (Exception ex) { + return Task.FromException (ex); + } + } + + public override Task ReadAsync (byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + if (buffer == null) + throw new ArgumentNullException ("buffer"); + + if (offset < 0 || count < 0) + throw new ArgumentOutOfRangeException ("offset or count less than zero."); + + if (buffer.Length - offset < count ) + throw new ArgumentException ("offset+count", + "The size of the buffer is less than offset + count."); + if (cancellationToken.IsCancellationRequested) + return TaskConstants.Canceled; + + try { + count = Read (buffer, offset, count); + + // Try not to allocate a new task for every buffer read + if (read_task == null || read_task.Result != count) + read_task = Task.FromResult (count); + + return read_task; + } catch (Exception ex) { + return Task.FromException (ex); + } + } + + public override Task WriteAsync (byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + if (buffer == null) + throw new ArgumentNullException ("buffer"); + + if (offset < 0 || count < 0) + throw new ArgumentOutOfRangeException (); + + if (buffer.Length - offset < count) + throw new ArgumentException ("offset+count", + "The size of the buffer is less than offset + count."); + + if (cancellationToken.IsCancellationRequested) + return TaskConstants.Canceled; + + try { + Write (buffer, offset, count); + return TaskConstants.Finished; + } catch (Exception ex) { + return Task.FromException (ex); + } + } +#endif } }