Warnings cleanup
[mono.git] / mcs / class / corlib / System.IO / UnmanagedMemoryStream.cs
1 //
2 // System.IO.UnmanagedMemoryStream.cs
3 //
4 // Copyright (C) 2006 Sridhar Kulkarni, All Rights Reserved
5 //
6 // Authors:
7 //      Sridhar Kulkarni (sridharkulkarni@gmail.com)
8 //      Gert Driesen (drieseng@users.sourceforge.net)
9 //
10 // Copyright (C) 2005-2006 Novell, Inc (http://www.novell.com)
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 //
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 //
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31
32 #if NET_2_0
33
34 using System;
35 using System.IO;
36 using System.Runtime.InteropServices;
37
38 namespace System.IO
39 {
40         [CLSCompliantAttribute(false)]
41         public class UnmanagedMemoryStream : Stream
42         {
43                 long length;
44                 bool closed;
45 //              bool canseek;
46                 long capacity;
47                 FileAccess fileaccess;
48                 IntPtr initial_pointer;
49                 long initial_position;
50                 long current_position;
51                 
52                 internal event EventHandler Closed;
53                 
54 #region Constructor
55                 protected UnmanagedMemoryStream()
56                 {
57                         fileaccess = FileAccess.Read;
58 //                      canseek = true;
59                 }
60                 
61                 public unsafe UnmanagedMemoryStream (byte *pointer, long length)
62                         : this ()
63                 {
64                         if (pointer == null)
65                                 throw new ArgumentNullException("pointer");
66                         if (length < 0)
67                                 throw new ArgumentOutOfRangeException("length", "Non-negative number required.");
68
69                         this.length = length;
70                         capacity = length;
71                         initial_pointer = new IntPtr((void*)pointer);
72                 }
73                 
74                 public unsafe UnmanagedMemoryStream (byte *pointer, long length, long capacity, FileAccess access)
75                 {
76                         if (pointer == null)
77                                 throw new ArgumentNullException("pointer");
78                         if (length < 0)
79                                 throw new ArgumentOutOfRangeException("length", "Non-negative number required.");
80                         if (capacity < 0)
81                                 throw new ArgumentOutOfRangeException("capacity", "Non-negative number required.");
82                         if (length > capacity)
83                                 throw new ArgumentOutOfRangeException("length", "The length cannot be greater than the capacity.");
84                         if (!Enum.IsDefined (typeof (FileAccess), access))
85                                 throw new ArgumentOutOfRangeException ("access", "Enum value was out of legal range.");
86                                 
87                         fileaccess = access;
88                         this.length = length;
89                         this.capacity = capacity;
90 //                      canseek = true;
91                         initial_pointer = new IntPtr ((void*)pointer);
92                 }
93 #endregion
94         
95 #region Properties
96                 public override bool CanRead {
97                         get {
98                                 if (closed)
99                                         return false;
100                                 return (fileaccess == FileAccess.Read || fileaccess == FileAccess.ReadWrite);
101                         }
102                 }
103
104                 public override bool CanSeek {
105                         get {
106                                 return !closed;
107                         }
108                 }
109                 
110                 public override bool CanWrite {
111                         get {
112                                 if (closed)
113                                         return (false);
114                                 return (fileaccess == FileAccess.Write || fileaccess == FileAccess.ReadWrite);
115                         }
116                 }
117                 public long Capacity {
118                         get {
119                                 if (closed)
120                                         throw new ObjectDisposedException("The stream is closed");
121                                 else
122                                         return (capacity);
123                         }
124                 }
125                 public override long Length {
126                         get {
127                                 if (closed)
128                                         throw new ObjectDisposedException("The stream is closed");
129                                 else
130                                         return (length);
131                         }
132                 }
133                 public override long Position {
134                         get {
135                                 if (closed)
136                                         throw new ObjectDisposedException("The stream is closed");
137                                 return (current_position);
138                         }
139                         set {
140                                 if (closed)
141                                         throw new ObjectDisposedException("The stream is closed");
142                                 if (value < 0)
143                                         throw new ArgumentOutOfRangeException("value", "Non-negative number required.");
144                                 if (value > (long)Int32.MaxValue)
145                                         throw new ArgumentOutOfRangeException("value", "The position is larger than Int32.MaxValue.");
146                                 current_position = value;
147                         }
148                 }
149
150 #if NET_2_1
151                 [CLSCompliantAttribute(false)]
152 #endif
153                 public unsafe byte* PositionPointer {
154                         get {
155                                 return (byte *) initial_pointer + current_position;
156                         }
157                         set {
158                                 if (value < (byte *)initial_pointer)
159                                         throw new IOException ("Address is below the inital address");
160
161                                 if (value >= (byte *) ((byte *)initial_pointer + length))
162                                         throw new ArgumentOutOfRangeException ("value");
163
164                                 current_position = (long) (value - (byte *) initial_pointer);
165                         }
166                 }
167 #endregion
168                 
169 #region Methods
170                 public override int Read ([InAttribute] [OutAttribute] byte[] buffer, int offset, int count)
171                 {
172                         if (closed)
173                                 throw new ObjectDisposedException("The stream is closed");
174                         
175                         if (buffer == null)
176                                 throw new ArgumentNullException("buffer");
177                         if (offset < 0)
178                                 throw new ArgumentOutOfRangeException("offset", "Non-negative number required.");
179                         if (count < 0)
180                                 throw new ArgumentOutOfRangeException("count", "Non-negative number required.");
181                         if ((buffer.Length - offset) < count)
182                                 throw new ArgumentException("The length of the buffer array minus the offset parameter is less than the count parameter");
183                         
184                         if (fileaccess == FileAccess.Write)
185                                 throw new NotSupportedException("Stream does not support reading");
186                         else {
187                                 if (current_position >= length)
188                                         return (0);
189                                 else {
190                                         int progress = current_position + count < length ? count : (int) (length - current_position);
191                                         for (int i = 0; i < progress; i++)
192                                                 buffer [offset + i] = Marshal.ReadByte (initial_pointer, (int) current_position++);
193                                         return progress;
194                                 }
195                         }
196                 }
197
198                 public override int ReadByte ()
199                 {
200                         if (closed)
201                                 throw new ObjectDisposedException("The stream is closed");
202                         
203                         if (fileaccess== FileAccess.Write)
204                                 throw new NotSupportedException("Stream does not support reading");
205                         else {
206                                 if (current_position >= length)
207                                         return (-1);
208                                 return (int) Marshal.ReadByte(initial_pointer, (int) current_position++);
209                         }
210                 }
211                 
212                 public override long Seek (long offset, SeekOrigin loc)
213                 {
214                         if (closed)
215                                 throw new ObjectDisposedException("The stream is closed");
216
217                         long refpoint;
218                         switch(loc) {
219                         case SeekOrigin.Begin:
220                                 if (offset < 0)
221                                         throw new IOException("An attempt was made to seek before the beginning of the stream");
222                                 refpoint = initial_position;
223                                 break;
224                         case SeekOrigin.Current:
225                                 refpoint = current_position;
226                                 break;
227                         case SeekOrigin.End:
228                                 refpoint = length;
229                                 break;
230                         default:
231                                 throw new ArgumentException("Invalid SeekOrigin option");
232                         }
233                         refpoint += (int)offset;
234                         if (refpoint < initial_position)
235                                 throw new IOException("An attempt was made to seek before the beginning of the stream");
236                         current_position = refpoint;
237                         return(current_position);
238                 }
239                  
240                 public override void SetLength (long value)
241                 {
242                         if (closed)
243                                 throw new ObjectDisposedException("The stream is closed");
244                         if (value < 0)
245                                 throw new ArgumentOutOfRangeException("length", "Non-negative number required.");
246                         if (value > capacity)
247                                 throw new IOException ("Unable to expand length of this stream beyond its capacity.");
248                         if (fileaccess == FileAccess.Read)
249                                 throw new NotSupportedException ("Stream does not support writing.");
250                         length = value;
251                         if (length < current_position)
252                                 current_position = length;
253                 }
254
255                 public override void Flush ()
256                 {
257                         if (closed)
258                                 throw new ObjectDisposedException("The stream is closed");
259                         //This method performs no action for this class
260                         //but is included as part of the Stream base class
261                 }
262                  
263                 protected override void Dispose (bool disposing)
264                 {
265                         if (closed)
266                                 return;
267                         closed = true;
268                         if (Closed != null)
269                                 Closed (this, null);
270                 }
271                  
272                 public override void Write (byte[] buffer, int offset, int count)
273                 {
274                         if (closed)
275                                 throw new ObjectDisposedException("The stream is closed");
276                         if (buffer == null)
277                                 throw new ArgumentNullException("The buffer parameter is a null reference");
278                         if ((current_position + count) > capacity)
279                                 throw new NotSupportedException ("Unable to expand length of this stream beyond its capacity.");
280                         if (offset < 0)
281                                 throw new ArgumentOutOfRangeException("offset", "Non-negative number required.");
282                         if (count < 0)
283                                 throw new ArgumentOutOfRangeException("count", "Non-negative number required.");
284                         if ((buffer.Length - offset) < count)
285                                 throw new ArgumentException("The length of the buffer array minus the offset parameter is less than the count parameter");
286                         if (fileaccess == FileAccess.Read)
287                                 throw new NotSupportedException ("Stream does not support writing.");
288                         else {
289                                 unsafe {
290                                         // use Marshal.WriteByte since that allow us to start writing
291                                         // from the current position
292                                         for (int i = 0; i < count; i++)
293                                                 Marshal.WriteByte (initial_pointer, (int) current_position++, buffer [offset + i]);
294
295                                         if (current_position > length)
296                                                 length = current_position;
297                                 }
298                         }
299                 }
300                 
301                 public override void WriteByte (byte value)
302                 {
303                         if (closed)
304                                 throw new ObjectDisposedException("The stream is closed");
305                         
306                         if (current_position == capacity)
307                                 throw new NotSupportedException("The current position is at the end of the capacity of the stream");
308                         if (fileaccess == FileAccess.Read)
309                                 throw new NotSupportedException("Stream does not support writing.");
310                         else {
311                                 unsafe {
312                                         Marshal.WriteByte(initial_pointer, (int)current_position, value);
313                                         current_position++;
314                                         if (current_position > length)
315                                                 length = current_position;
316                                 }
317                         }
318                 }
319
320                 protected unsafe void Initialize (byte* pointer, long length,
321                                                   long capacity,
322                                                   FileAccess access)
323                 {
324                         fileaccess = access;
325                         this.length = length;
326                         this.capacity = capacity;
327                         initial_position = 0;
328                         current_position = initial_position;
329 //                      canseek = true;
330                         initial_pointer = new IntPtr ((void *)pointer);
331                         closed = false;
332                 }
333 #endregion
334         }
335 }
336 #endif
337