Merge branch 'BigIntegerParse'
[mono.git] / mcs / class / corlib / System.IO / Stream.cs
1 //
2 // System.IO.Stream.cs
3 //
4 // Authors:
5 //   Dietmar Maurer (dietmar@ximian.com)
6 //   Miguel de Icaza (miguel@ximian.com)
7 //   Gonzalo Paniagua Javier (gonzalo@ximian.com)
8 //   Marek Safar (marek.safar@gmail.com)
9 //
10 // (C) 2001, 2002 Ximian, Inc.  http://www.ximian.com
11 // (c) 2004 Novell, Inc. (http://www.novell.com)
12 // Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
13 //
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
21 // 
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
24 // 
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 //
33
34 using System.Threading;
35 using System.Runtime.Remoting.Messaging;
36 using System.Runtime.InteropServices;
37 #if NET_4_5
38 using System.Threading.Tasks;
39 #endif
40
41 namespace System.IO
42 {
43         [Serializable]
44         [ComVisible (true)]
45 #if NET_2_1
46         public abstract class Stream : IDisposable
47 #else
48         public abstract class Stream : MarshalByRefObject, IDisposable
49 #endif
50         {
51                 public static readonly Stream Null = new NullStream ();
52
53                 [NonSerialized]
54                 Func<byte[], int, int, int> async_read;
55                 [NonSerialized]
56                 Action<byte[], int, int> async_write;
57                 [NonSerialized]
58                 AutoResetEvent async_event;
59
60                 protected Stream ()
61                 {
62                 }
63
64                 public abstract bool CanRead
65                 {
66                         get;
67                 }
68
69                 public abstract bool CanSeek
70                 {
71                         get;
72                 }
73
74                 public abstract bool CanWrite
75                 {
76                         get;
77                 }
78
79                 [ComVisible (false)]
80                 public virtual bool CanTimeout {
81                         get {
82                                 return false;
83                         }
84                 }
85
86                 public abstract long Length
87                 {
88                         get;
89                 }
90
91                 public abstract long Position
92                 {
93                         get;
94                         set;
95                 }
96
97
98                 public void Dispose ()
99                 {
100                         Close ();
101                 }
102
103                 protected virtual void Dispose (bool disposing)
104                 {
105                         if (async_event != null && disposing) {
106                                 async_event.Close ();
107                                 async_event = null;
108                         }
109                 }
110
111                 public virtual void Close ()
112                 {
113                         Dispose (true);
114                         GC.SuppressFinalize (this);
115                 }
116
117                 [ComVisible (false)]
118                 public virtual int ReadTimeout {
119                         get {
120                                 throw new InvalidOperationException ("Timeouts are not supported on this stream.");
121                         }
122                         set {
123                                 throw new InvalidOperationException ("Timeouts are not supported on this stream.");
124                         }
125                 }
126
127                 [ComVisible (false)]
128                 public virtual int WriteTimeout {
129                         get {
130                                 throw new InvalidOperationException ("Timeouts are not supported on this stream.");
131                         }
132                         set {
133                                 throw new InvalidOperationException ("Timeouts are not supported on this stream.");
134                         }
135                 }
136
137                 public static Stream Synchronized (Stream stream)
138                 {
139                         return new SynchronizedStream (stream);
140                 }
141
142                 [Obsolete ("CreateWaitHandle is due for removal.  Use \"new ManualResetEvent(false)\" instead.")]
143                 protected virtual WaitHandle CreateWaitHandle()
144                 {
145                         return new ManualResetEvent (false);
146                 }
147                 
148                 public abstract void Flush ();
149
150                 public abstract int Read ([In,Out] byte[] buffer, int offset, int count);
151
152                 public virtual int ReadByte ()
153                 {
154                         byte[] buffer = new byte [1];
155
156                         if (Read (buffer, 0, 1) > 0)
157                                 return buffer [0];
158                         
159                         return -1;
160                 }
161
162                 public abstract long Seek (long offset, SeekOrigin origin);
163
164                 public abstract void SetLength (long value);
165
166                 public abstract void Write (byte[] buffer, int offset, int count);
167
168                 public virtual void WriteByte (byte value)
169                 {
170                         byte[] buffer = new byte [1];
171
172                         buffer [0] = value;
173
174                         Write (buffer, 0, 1);
175                 }
176
177                 public virtual IAsyncResult BeginRead (byte[] buffer, int offset, int count, AsyncCallback callback, object state)
178                 {
179                         if (!CanRead)
180                                 throw new NotSupportedException ("This stream does not support reading");
181
182                         if (async_event == null) {
183                                 lock (this) {
184                                         if (async_event == null)
185                                                 async_event = new AutoResetEvent (true);
186                                 }
187                         }
188
189                         async_event.WaitOne ();
190                         async_read = Read;
191                         return async_read.BeginInvoke (buffer, offset, count, callback, state);
192                 }
193
194                 public virtual IAsyncResult BeginWrite (byte[] buffer, int offset, int count, AsyncCallback callback, object state)
195                 {
196                         if (!CanWrite)
197                                 throw new NotSupportedException ("This stream does not support writing");
198
199                         if (async_event == null) {
200                                 lock (this) {
201                                         if (async_event == null)
202                                                 async_event = new AutoResetEvent (true);
203                                 }
204                         }
205
206                         async_event.WaitOne ();
207                         async_write = Write;
208                         return async_write.BeginInvoke (buffer, offset, count, callback, state);
209                 }
210                 
211                 public virtual int EndRead (IAsyncResult asyncResult)
212                 {
213                         if (asyncResult == null)
214                                 throw new ArgumentNullException ("asyncResult");
215
216                         if (async_read == null)
217                                 throw new ArgumentException ("EndRead cannot be called multiple times");
218
219                         try {
220                                 return async_read.EndInvoke (asyncResult);
221                         } finally {
222                                 async_read = null;
223                                 async_event.Set ();
224                         }
225                 }
226
227                 public virtual void EndWrite (IAsyncResult asyncResult)
228                 {
229                         if (asyncResult == null)
230                                 throw new ArgumentNullException ("asyncResult");
231
232                         if (async_write == null)
233                                 throw new ArgumentException ("EndWrite cannot be called multiple times");
234
235                         try {
236                                 async_write.EndInvoke (asyncResult);
237                         } finally {
238                                 async_write = null;
239                                 async_event.Set ();
240                         }
241                 }
242
243 #if NET_4_0
244                 public void CopyTo (Stream destination)
245                 {
246                         CopyTo (destination, 16*1024);
247                 }
248
249                 public void CopyTo (Stream destination, int bufferSize)
250                 {
251                         if (destination == null)
252                                 throw new ArgumentNullException ("destination");
253                         if (!CanRead)
254                                 throw new NotSupportedException ("This stream does not support reading");
255                         if (!destination.CanWrite)
256                                 throw new NotSupportedException ("This destination stream does not support writing");
257                         if (bufferSize <= 0)
258                                 throw new ArgumentOutOfRangeException ("bufferSize");
259
260                         var buffer = new byte [bufferSize];
261                         int nread;
262                         while ((nread = Read (buffer, 0, bufferSize)) != 0)
263                                 destination.Write (buffer, 0, nread);
264                 }
265
266 #if NET_4_5
267                 [ObsoleteAttribute("Do not call or override this method")]
268 #endif
269                 protected virtual void ObjectInvariant ()
270                 {
271                 }
272 #endif
273                 
274 #if NET_4_5
275
276                 public Task CopyToAsync (Stream destination)
277                 {
278                         return CopyToAsync (destination, 16 * 1024, CancellationToken.None);
279                 }
280
281                 public Task CopyToAsync (Stream destination, int bufferSize)
282                 {
283                         return CopyToAsync (destination, bufferSize, CancellationToken.None);
284                 }
285
286                 public virtual Task CopyToAsync (Stream destination, int bufferSize, CancellationToken cancellationToken)
287                 {
288                         if (destination == null)
289                                 throw new ArgumentNullException ("destination");
290                         if (!CanRead)
291                                 throw new NotSupportedException ("This stream does not support reading");
292                         if (!destination.CanWrite)
293                                 throw new NotSupportedException ("This destination stream does not support writing");
294                         if (bufferSize <= 0)
295                                 throw new ArgumentOutOfRangeException ("bufferSize");
296
297                         if (cancellationToken.IsCancellationRequested)
298                                 return TaskConstants.Canceled;
299
300                         return CopyToAsync (destination, new byte[bufferSize], cancellationToken);
301                 }
302
303                 async Task CopyToAsync (Stream destination, byte[] buffer, CancellationToken cancellationToken)
304                 {
305                         int nread;
306                         while ((nread = await ReadAsync (buffer, 0, buffer.Length, cancellationToken).ConfigureAwait (false)) != 0)
307                                 await destination.WriteAsync (buffer, 0, nread, cancellationToken).ConfigureAwait (false);
308                 }
309
310                 public Task FlushAsync ()
311                 {
312                         return FlushAsync (CancellationToken.None);
313                 }
314
315                 public virtual Task FlushAsync (CancellationToken cancellationToken)
316                 {
317                         if (cancellationToken.IsCancellationRequested)
318                                 return TaskConstants.Canceled;
319
320                         return Task.Factory.StartNew (l => ((Stream) l).Flush (), this, cancellationToken);
321                 }
322
323                 public Task<int> ReadAsync (byte[] buffer, int offset, int count)
324                 {
325                         return ReadAsync (buffer, offset, count, CancellationToken.None);
326                 }
327
328                 public virtual Task<int> ReadAsync (byte[] buffer, int offset, int count, CancellationToken cancellationToken)
329                 {
330                         if (cancellationToken.IsCancellationRequested)
331                                 return TaskConstants<int>.Canceled;
332
333                         return Task<int>.Factory.FromAsync (BeginRead, EndRead, buffer, offset, count, null);
334                 }
335
336                 public Task WriteAsync (byte[] buffer, int offset, int count)
337                 {
338                         return WriteAsync (buffer, offset, count, CancellationToken.None);
339                 }
340
341                 public virtual Task WriteAsync (byte[] buffer, int offset, int count, CancellationToken cancellationToken)
342                 {
343                         return Task.Factory.FromAsync (BeginWrite, EndWrite, buffer, offset, count, null);
344                 }
345 #endif
346         }
347
348         class NullStream : Stream
349         {
350                 public override bool CanRead
351                 {
352                         get {
353                                 return true;
354                         }
355                 }
356
357                 public override bool CanSeek
358                 {
359                         get {
360                                 return true;
361                         }
362                 }
363
364                 public override bool CanWrite
365                 {
366                         get {
367                                 return true;
368                         }
369                 }
370
371                 public override long Length
372                 {
373                         get {
374                                 return 0;
375                         }
376                 }
377
378                 public override long Position
379                 {
380                         get {
381                                 return 0;
382                         }
383                         set {
384                         }
385                 }
386
387                 public override void Flush ()
388                 {
389                 }
390
391                 public override int Read (byte[] buffer, int offset, int count)
392                 {
393                         return 0;
394                 }
395
396                 public override int ReadByte ()
397                 {
398                         return -1;
399                 }
400
401                 public override long Seek (long offset, SeekOrigin origin)
402                 {
403                         return 0;
404                 }
405
406                 public override void SetLength (long value)
407                 {
408                 }
409
410                 public override void Write (byte[] buffer, int offset, int count)
411                 {
412                 }
413
414                 public override void WriteByte (byte value)
415                 {
416                 }
417         }
418
419         class SynchronizedStream : Stream {
420                 Stream source;
421                 object slock;
422                         
423                 internal SynchronizedStream (Stream source)
424                 {
425                         this.source = source;
426                         slock = new object ();
427                 }
428                 
429                 public override bool CanRead
430                 {
431                         get {
432                                 lock (slock)
433                                         return source.CanRead;
434                         }
435                 }
436
437                 public override bool CanSeek
438                 {
439                         get {
440                                 lock (slock)
441                                         return source.CanSeek;
442                         }
443                 }
444
445                 public override bool CanWrite
446                 {
447                         get {
448                                 lock (slock)
449                                         return source.CanWrite;
450                         }
451                 }
452
453                 public override long Length
454                 {
455                         get {
456                                 lock (slock)
457                                         return source.Length;
458                         }
459                 }
460
461                 public override long Position
462                 {
463                         get {
464                                 lock (slock)
465                                         return source.Position;
466                         }
467                         set {
468                                 lock (slock)
469                                         source.Position = value;
470                         }
471                 }
472
473                 public override void Flush ()
474                 {
475                         lock (slock)
476                                 source.Flush ();
477                 }
478
479                 public override int Read (byte[] buffer, int offset, int count)
480                 {
481                         lock (slock)
482                                 return source.Read (buffer, offset, count);
483                 }
484
485                 public override int ReadByte ()
486                 {
487                         lock (slock)
488                                 return source.ReadByte ();
489                 }
490
491                 public override long Seek (long offset, SeekOrigin origin)
492                 {
493                         lock (slock)
494                                 return source.Seek (offset, origin);
495                 }
496
497                 public override void SetLength (long value)
498                 {
499                         lock (slock)
500                                 source.SetLength (value);
501                 }
502
503                 public override void Write (byte[] buffer, int offset, int count)
504                 {
505                         lock (slock)
506                                 source.Write (buffer, offset, count);
507                 }
508
509                 public override void WriteByte (byte value)
510                 {
511                         lock (slock)
512                                 source.WriteByte (value);
513                 }
514         }
515 }