BindingFlags.Public needed here as Exception.HResult is now public in .NET 4.5. This...
[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                 Func<byte[], int, int, int> async_read;
54                 Action<byte[], int, int> async_write;
55                 AutoResetEvent async_event;
56
57                 protected Stream ()
58                 {
59                 }
60
61                 public abstract bool CanRead
62                 {
63                         get;
64                 }
65
66                 public abstract bool CanSeek
67                 {
68                         get;
69                 }
70
71                 public abstract bool CanWrite
72                 {
73                         get;
74                 }
75
76                 [ComVisible (false)]
77                 public virtual bool CanTimeout {
78                         get {
79                                 return false;
80                         }
81                 }
82
83                 public abstract long Length
84                 {
85                         get;
86                 }
87
88                 public abstract long Position
89                 {
90                         get;
91                         set;
92                 }
93
94
95                 public void Dispose ()
96                 {
97                         Close ();
98                 }
99
100                 protected virtual void Dispose (bool disposing)
101                 {
102                         if (async_event != null && disposing) {
103                                 async_event.Close ();
104                                 async_event = null;
105                         }
106                 }
107
108                 public virtual void Close ()
109                 {
110                         Dispose (true);
111                         GC.SuppressFinalize (this);
112                 }
113
114                 [ComVisible (false)]
115                 public virtual int ReadTimeout {
116                         get {
117                                 throw new InvalidOperationException ("Timeouts are not supported on this stream.");
118                         }
119                         set {
120                                 throw new InvalidOperationException ("Timeouts are not supported on this stream.");
121                         }
122                 }
123
124                 [ComVisible (false)]
125                 public virtual int WriteTimeout {
126                         get {
127                                 throw new InvalidOperationException ("Timeouts are not supported on this stream.");
128                         }
129                         set {
130                                 throw new InvalidOperationException ("Timeouts are not supported on this stream.");
131                         }
132                 }
133
134                 public static Stream Synchronized (Stream stream)
135                 {
136                         return new SynchronizedStream (stream);
137                 }
138
139                 [Obsolete ("CreateWaitHandle is due for removal.  Use \"new ManualResetEvent(false)\" instead.")]
140                 protected virtual WaitHandle CreateWaitHandle()
141                 {
142                         return new ManualResetEvent (false);
143                 }
144                 
145                 public abstract void Flush ();
146
147                 public abstract int Read ([In,Out] byte[] buffer, int offset, int count);
148
149                 public virtual int ReadByte ()
150                 {
151                         byte[] buffer = new byte [1];
152
153                         if (Read (buffer, 0, 1) == 1)
154                                 return buffer [0];
155                         
156                         return -1;
157                 }
158
159                 public abstract long Seek (long offset, SeekOrigin origin);
160
161                 public abstract void SetLength (long value);
162
163                 public abstract void Write (byte[] buffer, int offset, int count);
164
165                 public virtual void WriteByte (byte value)
166                 {
167                         byte[] buffer = new byte [1];
168
169                         buffer [0] = value;
170
171                         Write (buffer, 0, 1);
172                 }
173
174                 public virtual IAsyncResult BeginRead (byte[] buffer, int offset, int count, AsyncCallback callback, object state)
175                 {
176                         if (!CanRead)
177                                 throw new NotSupportedException ("This stream does not support reading");
178
179                         if (async_event == null) {
180                                 lock (this) {
181                                         if (async_event == null)
182                                                 async_event = new AutoResetEvent (true);
183                                 }
184                         }
185
186                         async_event.WaitOne ();
187                         async_read = Read;
188                         return async_read.BeginInvoke (buffer, offset, count, callback, state);
189                 }
190
191                 public virtual IAsyncResult BeginWrite (byte[] buffer, int offset, int count, AsyncCallback callback, object state)
192                 {
193                         if (!CanWrite)
194                                 throw new NotSupportedException ("This stream does not support writing");
195
196                         if (async_event == null) {
197                                 lock (this) {
198                                         if (async_event == null)
199                                                 async_event = new AutoResetEvent (true);
200                                 }
201                         }
202
203                         async_event.WaitOne ();
204                         async_write = Write;
205                         return async_write.BeginInvoke (buffer, offset, count, callback, state);
206                 }
207                 
208                 public virtual int EndRead (IAsyncResult asyncResult)
209                 {
210                         if (asyncResult == null)
211                                 throw new ArgumentNullException ("asyncResult");
212
213                         if (async_read == null)
214                                 throw new ArgumentException ("EndRead cannot be called multiple times");
215
216                         try {
217                                 return async_read.EndInvoke (asyncResult);
218                         } finally {
219                                 async_read = null;
220                                 async_event.Set ();
221                         }
222                 }
223
224                 public virtual void EndWrite (IAsyncResult asyncResult)
225                 {
226                         if (asyncResult == null)
227                                 throw new ArgumentNullException ("asyncResult");
228
229                         if (async_write == null)
230                                 throw new ArgumentException ("EndWrite cannot be called multiple times");
231
232                         try {
233                                 async_write.EndInvoke (asyncResult);
234                         } finally {
235                                 async_write = null;
236                                 async_event.Set ();
237                         }
238                 }
239
240 #if MOONLIGHT || NET_4_0 || MOBILE
241                 public void CopyTo (Stream destination)
242                 {
243                         CopyTo (destination, 16*1024);
244                 }
245
246                 public void CopyTo (Stream destination, int bufferSize)
247                 {
248                         if (destination == null)
249                                 throw new ArgumentNullException ("destination");
250                         if (!CanRead)
251                                 throw new NotSupportedException ("This stream does not support reading");
252                         if (!destination.CanWrite)
253                                 throw new NotSupportedException ("This destination stream does not support writing");
254                         if (bufferSize <= 0)
255                                 throw new ArgumentOutOfRangeException ("bufferSize");
256
257                         var buffer = new byte [bufferSize];
258                         int nread;
259                         while ((nread = Read (buffer, 0, bufferSize)) != 0)
260                                 destination.Write (buffer, 0, nread);
261                 }
262
263 #if NET_4_5
264                 [ObsoleteAttribute("Do not call or override this method")]
265 #endif
266                 protected virtual void ObjectInvariant ()
267                 {
268                 }
269 #endif
270                 
271 #if NET_4_5
272
273                 public Task CopyToAsync (Stream destination)
274                 {
275                         return CopyToAsync (destination, 16 * 1024, CancellationToken.None);
276                 }
277
278                 public Task CopyToAsync (Stream destination, int bufferSize)
279                 {
280                         return CopyToAsync (destination, bufferSize, CancellationToken.None);
281                 }
282
283                 public virtual Task CopyToAsync (Stream destination, int bufferSize, CancellationToken cancellationToken)
284                 {
285                         if (destination == null)
286                                 throw new ArgumentNullException ("destination");
287                         if (!CanRead)
288                                 throw new NotSupportedException ("This stream does not support reading");
289                         if (!destination.CanWrite)
290                                 throw new NotSupportedException ("This destination stream does not support writing");
291                         if (bufferSize <= 0)
292                                 throw new ArgumentOutOfRangeException ("bufferSize");
293
294                         if (cancellationToken.IsCancellationRequested)
295                                 return TaskConstants.Canceled;
296
297                         return CopyToAsync (destination, new byte[bufferSize], cancellationToken);
298                 }
299
300                 async Task CopyToAsync (Stream destination, byte[] buffer, CancellationToken cancellationToken)
301                 {
302                         int nread;
303                         while ((nread = await ReadAsync (buffer, 0, buffer.Length).ConfigureAwait (false)) != 0)
304                                 await destination.WriteAsync (buffer, 0, nread, cancellationToken).ConfigureAwait (false);
305                 }
306
307                 public Task FlushAsync ()
308                 {
309                         return FlushAsync (CancellationToken.None);
310                 }
311
312                 public virtual Task FlushAsync (CancellationToken cancellationToken)
313                 {
314                         if (cancellationToken.IsCancellationRequested)
315                                 return TaskConstants.Canceled;
316
317                         return Task.Factory.StartNew (l => ((Stream) l).Flush (), this, cancellationToken);
318                 }
319
320                 public Task<int> ReadAsync (byte[] buffer, int offset, int count)
321                 {
322                         return ReadAsync (buffer, offset, count, CancellationToken.None);
323                 }
324
325                 public virtual Task<int> ReadAsync (byte[] buffer, int offset, int count, CancellationToken cancellationToken)
326                 {
327                         if (cancellationToken.IsCancellationRequested)
328                                 return TaskConstants<int>.Canceled;
329
330                         return Task<int>.Factory.FromAsync (BeginRead, EndRead, buffer, offset, count, null);
331                 }
332
333                 public Task WriteAsync (byte[] buffer, int offset, int count)
334                 {
335                         return WriteAsync (buffer, offset, count, CancellationToken.None);
336                 }
337
338                 public virtual Task WriteAsync (byte[] buffer, int offset, int count, CancellationToken cancellationToken)
339                 {
340                         return Task.Factory.FromAsync (BeginWrite, EndWrite, buffer, offset, count, null);
341                 }
342 #endif
343         }
344
345         class NullStream : Stream
346         {
347                 public override bool CanRead
348                 {
349                         get {
350                                 return true;
351                         }
352                 }
353
354                 public override bool CanSeek
355                 {
356                         get {
357                                 return true;
358                         }
359                 }
360
361                 public override bool CanWrite
362                 {
363                         get {
364                                 return true;
365                         }
366                 }
367
368                 public override long Length
369                 {
370                         get {
371                                 return 0;
372                         }
373                 }
374
375                 public override long Position
376                 {
377                         get {
378                                 return 0;
379                         }
380                         set {
381                         }
382                 }
383
384                 public override void Flush ()
385                 {
386                 }
387
388                 public override int Read (byte[] buffer, int offset, int count)
389                 {
390                         return 0;
391                 }
392
393                 public override int ReadByte ()
394                 {
395                         return -1;
396                 }
397
398                 public override long Seek (long offset, SeekOrigin origin)
399                 {
400                         return 0;
401                 }
402
403                 public override void SetLength (long value)
404                 {
405                 }
406
407                 public override void Write (byte[] buffer, int offset, int count)
408                 {
409                 }
410
411                 public override void WriteByte (byte value)
412                 {
413                 }
414         }
415
416         class SynchronizedStream : Stream {
417                 Stream source;
418                 object slock;
419                         
420                 internal SynchronizedStream (Stream source)
421                 {
422                         this.source = source;
423                         slock = new object ();
424                 }
425                 
426                 public override bool CanRead
427                 {
428                         get {
429                                 lock (slock)
430                                         return source.CanRead;
431                         }
432                 }
433
434                 public override bool CanSeek
435                 {
436                         get {
437                                 lock (slock)
438                                         return source.CanSeek;
439                         }
440                 }
441
442                 public override bool CanWrite
443                 {
444                         get {
445                                 lock (slock)
446                                         return source.CanWrite;
447                         }
448                 }
449
450                 public override long Length
451                 {
452                         get {
453                                 lock (slock)
454                                         return source.Length;
455                         }
456                 }
457
458                 public override long Position
459                 {
460                         get {
461                                 lock (slock)
462                                         return source.Position;
463                         }
464                         set {
465                                 lock (slock)
466                                         source.Position = value;
467                         }
468                 }
469
470                 public override void Flush ()
471                 {
472                         lock (slock)
473                                 source.Flush ();
474                 }
475
476                 public override int Read (byte[] buffer, int offset, int count)
477                 {
478                         lock (slock)
479                                 return source.Read (buffer, offset, count);
480                 }
481
482                 public override int ReadByte ()
483                 {
484                         lock (slock)
485                                 return source.ReadByte ();
486                 }
487
488                 public override long Seek (long offset, SeekOrigin origin)
489                 {
490                         lock (slock)
491                                 return source.Seek (offset, origin);
492                 }
493
494                 public override void SetLength (long value)
495                 {
496                         lock (slock)
497                                 source.SetLength (value);
498                 }
499
500                 public override void Write (byte[] buffer, int offset, int count)
501                 {
502                         lock (slock)
503                                 source.Write (buffer, offset, count);
504                 }
505
506                 public override void WriteByte (byte value)
507                 {
508                         lock (slock)
509                                 source.WriteByte (value);
510                 }
511         }
512 }