Avoid a .cctor on the initialization path.
[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                         GC.SuppressFinalize (this);
109                 }
110
111                 [ComVisible (false)]
112                 public virtual int ReadTimeout {
113                         get {
114                                 throw new InvalidOperationException ("Timeouts are not supported on this stream.");
115                         }
116                         set {
117                                 throw new InvalidOperationException ("Timeouts are not supported on this stream.");
118                         }
119                 }
120
121                 [ComVisible (false)]
122                 public virtual int WriteTimeout {
123                         get {
124                                 throw new InvalidOperationException ("Timeouts are not supported on this stream.");
125                         }
126                         set {
127                                 throw new InvalidOperationException ("Timeouts are not supported on this stream.");
128                         }
129                 }
130
131                 public static Stream Synchronized (Stream stream)
132                 {
133                         return new SynchronizedStream (stream);
134                 }
135
136                 [Obsolete ("CreateWaitHandle is due for removal.  Use \"new ManualResetEvent(false)\" instead.")]
137                 protected virtual WaitHandle CreateWaitHandle()
138                 {
139                         return new ManualResetEvent (false);
140                 }
141                 
142                 public abstract void Flush ();
143
144                 public abstract int Read ([In,Out] byte[] buffer, int offset, int count);
145
146                 public virtual int ReadByte ()
147                 {
148                         byte[] buffer = new byte [1];
149
150                         if (Read (buffer, 0, 1) == 1)
151                                 return buffer [0];
152                         
153                         return -1;
154                 }
155
156                 public abstract long Seek (long offset, SeekOrigin origin);
157
158                 public abstract void SetLength (long value);
159
160                 public abstract void Write (byte[] buffer, int offset, int count);
161
162                 public virtual void WriteByte (byte value)
163                 {
164                         byte[] buffer = new byte [1];
165
166                         buffer [0] = value;
167
168                         Write (buffer, 0, 1);
169                 }
170
171                 public virtual IAsyncResult
172                 BeginRead (byte [] buffer, int offset, int count, AsyncCallback callback, object state)
173                 {
174                         if (!CanRead)
175                                 throw new NotSupportedException ("This stream does not support reading");
176
177                         // Creating a class derived from Stream that doesn't override BeginRead
178                         // shows that it actually calls Read and does everything synchronously.
179                         // Just put this in the Read override:
180                         //      Console.WriteLine ("Read");
181                         //      Console.WriteLine (Environment.StackTrace);
182                         //      Thread.Sleep (10000);
183                         //      return 10;
184
185                         StreamAsyncResult result = new StreamAsyncResult (state);
186                         try {
187                                 int nbytes = Read (buffer, offset, count);
188                                 result.SetComplete (null, nbytes);
189                         } catch (Exception e) {
190                                 result.SetComplete (e, 0);
191                         }
192
193                         if (callback != null)
194                                 callback (result);
195
196                         return result;
197                 }
198
199 //              delegate void WriteDelegate (byte [] buffer, int offset, int count);
200
201                 public virtual IAsyncResult
202                 BeginWrite (byte [] buffer, int offset, int count, AsyncCallback callback, object state)
203                 {
204                         if (!CanWrite)
205                                 throw new NotSupportedException ("This stream does not support writing");
206         
207                         // Creating a class derived from Stream that doesn't override BeginWrite
208                         // shows that it actually calls Write and does everything synchronously except
209                         // when invoking the callback, which is done from the ThreadPool.
210                         // Just put this in the Write override:
211                         //      Console.WriteLine ("Write");
212                         //      Console.WriteLine (Environment.StackTrace);
213                         //      Thread.Sleep (10000);
214
215                         StreamAsyncResult result = new StreamAsyncResult (state);
216                         try {
217                                 Write (buffer, offset, count);
218                                 result.SetComplete (null);
219                         } catch (Exception e) {
220                                 result.SetComplete (e);
221                         }
222
223                         if (callback != null)
224                                 callback.BeginInvoke (result, null, null);
225
226                         return result;
227                 }
228                 
229                 public virtual int EndRead (IAsyncResult asyncResult)
230                 {
231                         if (asyncResult == null)
232                                 throw new ArgumentNullException ("asyncResult");
233
234                         StreamAsyncResult result = asyncResult as StreamAsyncResult;
235                         if (result == null || result.NBytes == -1)
236                                 throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
237
238                         if (result.Done)
239                                 throw new InvalidOperationException ("EndRead already called.");
240
241                         result.Done = true;
242                         if (result.Exception != null)
243                                 throw result.Exception;
244
245                         return result.NBytes;
246                 }
247
248                 public virtual void EndWrite (IAsyncResult asyncResult)
249                 {
250                         if (asyncResult == null)
251                                 throw new ArgumentNullException ("asyncResult");
252
253                         StreamAsyncResult result = asyncResult as StreamAsyncResult;
254                         if (result == null || result.NBytes != -1)
255                                 throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
256
257                         if (result.Done)
258                                 throw new InvalidOperationException ("EndWrite already called.");
259
260                         result.Done = true;
261                         if (result.Exception != null)
262                                 throw result.Exception;
263                 }
264
265 #if MOONLIGHT || NET_4_0 || MOBILE
266                 public void CopyTo (Stream destination)
267                 {
268                         CopyTo (destination, 16*1024);
269                 }
270
271                 public void CopyTo (Stream destination, int bufferSize)
272                 {
273                         if (destination == null)
274                                 throw new ArgumentNullException ("destination");
275                         if (!CanRead)
276                                 throw new NotSupportedException ("This stream does not support reading");
277                         if (!destination.CanWrite)
278                                 throw new NotSupportedException ("This destination stream does not support writing");
279                         if (bufferSize <= 0)
280                                 throw new ArgumentOutOfRangeException ("bufferSize");
281
282                         var buffer = new byte [bufferSize];
283                         int nread;
284                         while ((nread = Read (buffer, 0, bufferSize)) != 0)
285                                 destination.Write (buffer, 0, nread);
286                 }
287
288                 protected virtual void ObjectInvariant ()
289                 {
290                 }
291 #endif
292         }
293
294         class NullStream : Stream
295         {
296                 public override bool CanRead
297                 {
298                         get {
299                                 return true;
300                         }
301                 }
302
303                 public override bool CanSeek
304                 {
305                         get {
306                                 return true;
307                         }
308                 }
309
310                 public override bool CanWrite
311                 {
312                         get {
313                                 return true;
314                         }
315                 }
316
317                 public override long Length
318                 {
319                         get {
320                                 return 0;
321                         }
322                 }
323
324                 public override long Position
325                 {
326                         get {
327                                 return 0;
328                         }
329                         set {
330                         }
331                 }
332
333                 public override void Flush ()
334                 {
335                 }
336
337                 public override int Read (byte[] buffer, int offset, int count)
338                 {
339                         return 0;
340                 }
341
342                 public override int ReadByte ()
343                 {
344                         return -1;
345                 }
346
347                 public override long Seek (long offset, SeekOrigin origin)
348                 {
349                         return 0;
350                 }
351
352                 public override void SetLength (long value)
353                 {
354                 }
355
356                 public override void Write (byte[] buffer, int offset, int count)
357                 {
358                 }
359
360                 public override void WriteByte (byte value)
361                 {
362                 }
363         }
364
365         class SynchronizedStream : Stream {
366                 Stream source;
367                 object slock;
368                         
369                 internal SynchronizedStream (Stream source)
370                 {
371                         this.source = source;
372                         slock = new object ();
373                 }
374                 
375                 public override bool CanRead
376                 {
377                         get {
378                                 lock (slock)
379                                         return source.CanRead;
380                         }
381                 }
382
383                 public override bool CanSeek
384                 {
385                         get {
386                                 lock (slock)
387                                         return source.CanSeek;
388                         }
389                 }
390
391                 public override bool CanWrite
392                 {
393                         get {
394                                 lock (slock)
395                                         return source.CanWrite;
396                         }
397                 }
398
399                 public override long Length
400                 {
401                         get {
402                                 lock (slock)
403                                         return source.Length;
404                         }
405                 }
406
407                 public override long Position
408                 {
409                         get {
410                                 lock (slock)
411                                         return source.Position;
412                         }
413                         set {
414                                 lock (slock)
415                                         source.Position = value;
416                         }
417                 }
418
419                 public override void Flush ()
420                 {
421                         lock (slock)
422                                 source.Flush ();
423                 }
424
425                 public override int Read (byte[] buffer, int offset, int count)
426                 {
427                         lock (slock)
428                                 return source.Read (buffer, offset, count);
429                 }
430
431                 public override int ReadByte ()
432                 {
433                         lock (slock)
434                                 return source.ReadByte ();
435                 }
436
437                 public override long Seek (long offset, SeekOrigin origin)
438                 {
439                         lock (slock)
440                                 return source.Seek (offset, origin);
441                 }
442
443                 public override void SetLength (long value)
444                 {
445                         lock (slock)
446                                 source.SetLength (value);
447                 }
448
449                 public override void Write (byte[] buffer, int offset, int count)
450                 {
451                         lock (slock)
452                                 source.Write (buffer, offset, count);
453                 }
454
455                 public override void WriteByte (byte value)
456                 {
457                         lock (slock)
458                                 source.WriteByte (value);
459                 }
460         }
461 }