Wed Feb 24 15:47:16 CET 2010 Paolo Molaro <lupus@ximian.com>
[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 //
9 // (C) 2001, 2002 Ximian, Inc.  http://www.ximian.com
10 // (c) 2004 Novell, Inc. (http://www.novell.com)
11 //
12
13 //
14 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
15 //
16 // Permission is hereby granted, free of charge, to any person obtaining
17 // a copy of this software and associated documentation files (the
18 // "Software"), to deal in the Software without restriction, including
19 // without limitation the rights to use, copy, modify, merge, publish,
20 // distribute, sublicense, and/or sell copies of the Software, and to
21 // permit persons to whom the Software is furnished to do so, subject to
22 // the following conditions:
23 // 
24 // The above copyright notice and this permission notice shall be
25 // included in all copies or substantial portions of the Software.
26 // 
27 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
31 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
32 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
33 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 //
35
36 using System.Threading;
37 using System.Runtime.Remoting.Messaging;
38 using System.Runtime.InteropServices;
39
40 namespace System.IO
41 {
42         [Serializable]
43         [ComVisible (true)]
44 #if NET_2_1
45         public abstract class Stream : IDisposable
46 #else
47         public abstract class Stream : MarshalByRefObject, IDisposable
48 #endif
49         {
50                 public static readonly Stream Null = new NullStream ();
51
52                 protected Stream ()
53                 {
54                 }
55
56                 public abstract bool CanRead
57                 {
58                         get;
59                 }
60
61                 public abstract bool CanSeek
62                 {
63                         get;
64                 }
65
66                 public abstract bool CanWrite
67                 {
68                         get;
69                 }
70
71                 [ComVisible (false)]
72                 public virtual bool CanTimeout {
73                         get {
74                                 return false;
75                         }
76                 }
77
78                 public abstract long Length
79                 {
80                         get;
81                 }
82
83                 public abstract long Position
84                 {
85                         get;
86                         set;
87                 }
88
89
90                 // 2.0 version of Dispose.
91                 public void Dispose ()
92                 {
93                         Close ();
94                 }
95
96                 // 2.0 version of Dispose.
97                 protected virtual void Dispose (bool disposing)
98                 {
99                         // nothing.
100                 }
101
102                 //
103                 // 2.0 version of Close (): calls Dispose (true)
104                 //
105                 public virtual void Close ()
106                 {
107                         Dispose (true);
108                 }
109
110                 [ComVisible (false)]
111                 public virtual int ReadTimeout {
112                         get {
113                                 throw new InvalidOperationException ("Timeouts are not supported on this stream.");
114                         }
115                         set {
116                                 throw new InvalidOperationException ("Timeouts are not supported on this stream.");
117                         }
118                 }
119
120                 [ComVisible (false)]
121                 public virtual int WriteTimeout {
122                         get {
123                                 throw new InvalidOperationException ("Timeouts are not supported on this stream.");
124                         }
125                         set {
126                                 throw new InvalidOperationException ("Timeouts are not supported on this stream.");
127                         }
128                 }
129
130                 public static Stream Synchronized (Stream stream)
131                 {
132                         return new SynchronizedStream (stream);
133                 }
134
135                 [Obsolete ("CreateWaitHandle is due for removal.  Use \"new ManualResetEvent(false)\" instead.")]
136                 protected virtual WaitHandle CreateWaitHandle()
137                 {
138                         return new ManualResetEvent (false);
139                 }
140                 
141                 public abstract void Flush ();
142
143                 public abstract int Read ([In,Out] byte[] buffer, int offset, int count);
144
145                 public virtual int ReadByte ()
146                 {
147                         byte[] buffer = new byte [1];
148
149                         if (Read (buffer, 0, 1) == 1)
150                                 return buffer [0];
151                         
152                         return -1;
153                 }
154
155                 public abstract long Seek (long offset, SeekOrigin origin);
156
157                 public abstract void SetLength (long value);
158
159                 public abstract void Write (byte[] buffer, int offset, int count);
160
161                 public virtual void WriteByte (byte value)
162                 {
163                         byte[] buffer = new byte [1];
164
165                         buffer [0] = value;
166
167                         Write (buffer, 0, 1);
168                 }
169
170                 public virtual IAsyncResult
171                 BeginRead (byte [] buffer, int offset, int count, AsyncCallback callback, object state)
172                 {
173                         if (!CanRead)
174                                 throw new NotSupportedException ("This stream does not support reading");
175
176                         // Creating a class derived from Stream that doesn't override BeginRead
177                         // shows that it actually calls Read and does everything synchronously.
178                         // Just put this in the Read override:
179                         //      Console.WriteLine ("Read");
180                         //      Console.WriteLine (Environment.StackTrace);
181                         //      Thread.Sleep (10000);
182                         //      return 10;
183
184                         StreamAsyncResult result = new StreamAsyncResult (state);
185                         try {
186                                 int nbytes = Read (buffer, offset, count);
187                                 result.SetComplete (null, nbytes);
188                         } catch (Exception e) {
189                                 result.SetComplete (e, 0);
190                         }
191
192                         if (callback != null)
193                                 callback (result);
194
195                         return result;
196                 }
197
198 //              delegate void WriteDelegate (byte [] buffer, int offset, int count);
199
200                 public virtual IAsyncResult
201                 BeginWrite (byte [] buffer, int offset, int count, AsyncCallback callback, object state)
202                 {
203                         if (!CanWrite)
204                                 throw new NotSupportedException ("This stream does not support writing");
205         
206                         // Creating a class derived from Stream that doesn't override BeginWrite
207                         // shows that it actually calls Write and does everything synchronously except
208                         // when invoking the callback, which is done from the ThreadPool.
209                         // Just put this in the Write override:
210                         //      Console.WriteLine ("Write");
211                         //      Console.WriteLine (Environment.StackTrace);
212                         //      Thread.Sleep (10000);
213
214                         StreamAsyncResult result = new StreamAsyncResult (state);
215                         try {
216                                 Write (buffer, offset, count);
217                                 result.SetComplete (null);
218                         } catch (Exception e) {
219                                 result.SetComplete (e);
220                         }
221
222                         if (callback != null)
223                                 callback.BeginInvoke (result, null, null);
224
225                         return result;
226                 }
227                 
228                 public virtual int EndRead (IAsyncResult asyncResult)
229                 {
230                         if (asyncResult == null)
231                                 throw new ArgumentNullException ("asyncResult");
232
233                         StreamAsyncResult result = asyncResult as StreamAsyncResult;
234                         if (result == null || result.NBytes == -1)
235                                 throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
236
237                         if (result.Done)
238                                 throw new InvalidOperationException ("EndRead already called.");
239
240                         result.Done = true;
241                         if (result.Exception != null)
242                                 throw result.Exception;
243
244                         return result.NBytes;
245                 }
246
247                 public virtual void EndWrite (IAsyncResult asyncResult)
248                 {
249                         if (asyncResult == null)
250                                 throw new ArgumentNullException ("asyncResult");
251
252                         StreamAsyncResult result = asyncResult as StreamAsyncResult;
253                         if (result == null || result.NBytes != -1)
254                                 throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
255
256                         if (result.Done)
257                                 throw new InvalidOperationException ("EndWrite already called.");
258
259                         result.Done = true;
260                         if (result.Exception != null)
261                                 throw result.Exception;
262                 }
263
264 #if NET_4_0
265                 public void CopyTo (Stream destination)
266                 {
267                         CopyTo (destination, 16*1024);
268                 }
269
270                 public void CopyTo (Stream destination, int bufferSize)
271                 {
272                         if (destination == null)
273                                 throw new ArgumentNullException ("destination");
274                         if (!CanRead)
275                                 throw new NotSupportedException ("This stream does not support reading");
276                         if (!destination.CanWrite)
277                                 throw new NotSupportedException ("This destination stream does not support writing");
278                         if (bufferSize <= 0)
279                                 throw new ArgumentOutOfRangeException ("bufferSize");
280
281                         var buffer = new byte [bufferSize];
282                         int nread;
283                         while ((nread = Read (buffer, 0, bufferSize)) != 0)
284                                 destination.Write (buffer, 0, nread);
285                 }
286
287                 protected virtual void ObjectInvariant ()
288                 {
289                 }
290 #endif
291         }
292
293         class NullStream : Stream
294         {
295                 public override bool CanRead
296                 {
297                         get {
298                                 return true;
299                         }
300                 }
301
302                 public override bool CanSeek
303                 {
304                         get {
305                                 return true;
306                         }
307                 }
308
309                 public override bool CanWrite
310                 {
311                         get {
312                                 return true;
313                         }
314                 }
315
316                 public override long Length
317                 {
318                         get {
319                                 return 0;
320                         }
321                 }
322
323                 public override long Position
324                 {
325                         get {
326                                 return 0;
327                         }
328                         set {
329                         }
330                 }
331
332                 public override void Flush ()
333                 {
334                 }
335
336                 public override int Read (byte[] buffer, int offset, int count)
337                 {
338                         return 0;
339                 }
340
341                 public override int ReadByte ()
342                 {
343                         return -1;
344                 }
345
346                 public override long Seek (long offset, SeekOrigin origin)
347                 {
348                         return 0;
349                 }
350
351                 public override void SetLength (long value)
352                 {
353                 }
354
355                 public override void Write (byte[] buffer, int offset, int count)
356                 {
357                 }
358
359                 public override void WriteByte (byte value)
360                 {
361                 }
362         }
363
364         class SynchronizedStream : Stream {
365                 Stream source;
366                 object slock;
367                         
368                 internal SynchronizedStream (Stream source)
369                 {
370                         this.source = source;
371                         slock = new object ();
372                 }
373                 
374                 public override bool CanRead
375                 {
376                         get {
377                                 lock (slock)
378                                         return source.CanRead;
379                         }
380                 }
381
382                 public override bool CanSeek
383                 {
384                         get {
385                                 lock (slock)
386                                         return source.CanSeek;
387                         }
388                 }
389
390                 public override bool CanWrite
391                 {
392                         get {
393                                 lock (slock)
394                                         return source.CanWrite;
395                         }
396                 }
397
398                 public override long Length
399                 {
400                         get {
401                                 lock (slock)
402                                         return source.Length;
403                         }
404                 }
405
406                 public override long Position
407                 {
408                         get {
409                                 lock (slock)
410                                         return source.Position;
411                         }
412                         set {
413                                 lock (slock)
414                                         source.Position = value;
415                         }
416                 }
417
418                 public override void Flush ()
419                 {
420                         lock (slock)
421                                 source.Flush ();
422                 }
423
424                 public override int Read (byte[] buffer, int offset, int count)
425                 {
426                         lock (slock)
427                                 return source.Read (buffer, offset, count);
428                 }
429
430                 public override int ReadByte ()
431                 {
432                         lock (slock)
433                                 return source.ReadByte ();
434                 }
435
436                 public override long Seek (long offset, SeekOrigin origin)
437                 {
438                         lock (slock)
439                                 return source.Seek (offset, origin);
440                 }
441
442                 public override void SetLength (long value)
443                 {
444                         lock (slock)
445                                 source.SetLength (value);
446                 }
447
448                 public override void Write (byte[] buffer, int offset, int count)
449                 {
450                         lock (slock)
451                                 source.Write (buffer, offset, count);
452                 }
453
454                 public override void WriteByte (byte value)
455                 {
456                         lock (slock)
457                                 source.WriteByte (value);
458                 }
459         }
460 }