* UnmanagedMemoryStream.cs: In Read and ReadByte, use Marshal.ReadByte
[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 = false;
46                 long capacity;
47                 FileAccess fileaccess;
48                 IntPtr initial_pointer;
49                 IntPtr pointer_position;
50                 long initial_position;
51                 long current_position;
52                 
53 #region Constructor
54                 protected UnmanagedMemoryStream()
55                 {
56                         fileaccess = FileAccess.Read;
57                         initial_position = 0;
58                         canseek = true;
59                         closed = false;
60                         current_position = initial_position;
61                 }
62                 
63                 public unsafe UnmanagedMemoryStream (byte *pointer, long length)
64                 {
65                         if (pointer == null)
66                                 throw new ArgumentNullException("pointer");
67                         if (length < 0)
68                                 throw new ArgumentOutOfRangeException("length", "Non-negative number required.");
69                         fileaccess = FileAccess.Read;
70                         this.length = length;
71                         capacity = length;
72                         initial_position = 0;
73                         current_position = initial_position;
74                         canseek = true;
75                         closed = false;
76                         initial_pointer = new IntPtr((void*)pointer);
77                 }
78                 
79                 public unsafe UnmanagedMemoryStream (byte *pointer, long length, long capacity, FileAccess access)
80                 {
81                         if (pointer == null)
82                                 throw new ArgumentNullException("pointer");
83                         if (length < 0)
84                                 throw new ArgumentOutOfRangeException("length", "Non-negative number required.");
85                         if (capacity < 0)
86                                 throw new ArgumentOutOfRangeException("capacity", "Non-negative number required.");
87                         if (length > capacity)
88                                 throw new ArgumentOutOfRangeException("length", "The length cannot be greater than the capacity.");
89                         if (!Enum.IsDefined (typeof (FileAccess), access))
90                                 throw new ArgumentOutOfRangeException ("access", "Enum value was out of legal range.");
91                         fileaccess = access;
92                         this.length = length;
93                         this.capacity = capacity;
94                         initial_position = 0;
95                         current_position = initial_position;
96                         canseek = true;
97                         initial_pointer = new IntPtr ((void*)pointer);
98                         closed = false;
99                         fileaccess = access;
100                 }
101 #endregion
102         
103 #region Properties
104                 public override bool CanRead {
105                         get {
106                                 if (closed)
107                                         return false;
108                                 return (fileaccess == FileAccess.Read || fileaccess == FileAccess.ReadWrite);
109                         }
110                 }
111
112                 public override bool CanSeek {
113                         get {
114                                 return !closed;
115                         }
116                 }
117                 
118                 public override bool CanWrite {
119                         get {
120                                 if (closed)
121                                         return (false);
122                                 return (fileaccess == FileAccess.Write || fileaccess == FileAccess.ReadWrite);
123                         }
124                 }
125                 public long Capacity {
126                         get {
127                                 if (closed)
128                                         throw new ObjectDisposedException("The stream is closed");
129                                 else
130                                         return (capacity);
131                         }
132                 }
133                 public override long Length {
134                         get {
135                                 if (closed)
136                                         throw new ObjectDisposedException("The stream is closed");
137                                 else
138                                         return (length);
139                         }
140                 }
141                 public override long Position {
142                         get {
143                                 if (closed)
144                                         throw new ObjectDisposedException("The stream is closed");
145                                 return (current_position);
146                         }
147                         set {
148                                 if (closed)
149                                         throw new ObjectDisposedException("The stream is closed");
150                                 if (value < 0)
151                                         throw new ArgumentOutOfRangeException("value", "Non-negative number required.");
152                                 if (value > (long)Int32.MaxValue)
153                                         throw new ArgumentOutOfRangeException("value", "The position is larger than Int32.MaxValue.");
154                                 current_position = value;
155                         }
156                 }
157
158                 public unsafe byte* PositionPointer {
159                         get {
160                                 throw new NotImplementedException("Error");
161                         }
162                         set {
163                                 throw new NotImplementedException("Error");
164                         }
165                 }
166 #endregion
167                 
168 #region Methods
169                 public override int Read ([InAttribute] [OutAttribute] byte[] buffer, int offset, int count)
170                          {
171                                 if (closed)
172                                         throw new ObjectDisposedException("The stream is closed");
173
174                                 if (buffer == null)
175                                         throw new ArgumentNullException("buffer");
176                                 if (offset < 0)
177                                         throw new ArgumentOutOfRangeException("offset", "Non-negative number required.");
178                                 if (count < 0)
179                                         throw new ArgumentOutOfRangeException("count", "Non-negative number required.");
180                                 if ((buffer.Length - offset) < count)
181                                         throw new ArgumentException("The length of the buffer array minus the offset parameter is less than the count parameter");
182
183                                 if (fileaccess == FileAccess.Write)
184                                         throw new NotSupportedException("Stream does not support reading");
185                                 else {
186                                         if (current_position >= length)
187                                                 return (0);
188                                         else {
189                                                 int progress = current_position + count < length ? count : (int) (length - current_position);
190                                                 for (int i = 0; i < progress; i++)
191                                                         buffer [offset + i] = Marshal.ReadByte (initial_pointer, (int) current_position++);
192                                                 return progress;
193                                         }
194                                 }
195                         }
196                 public override int ReadByte () {
197                         if (closed)
198                                 throw new ObjectDisposedException("The stream is closed");
199
200                         if (fileaccess== FileAccess.Write)
201                                 throw new NotSupportedException("Stream does not support reading");
202                         else {
203                                 if (current_position >= length)
204                                         return (-1);
205                                 return (int) Marshal.ReadByte(initial_pointer, (int) current_position++);
206                         }
207                 }
208                 public override long Seek (long offset, SeekOrigin loc) {
209                         if (closed)
210                                 throw new ObjectDisposedException("The stream is closed");
211
212                         long refpoint;
213                         switch(loc) {
214                         case SeekOrigin.Begin:
215                                 if (offset < 0)
216                                         throw new IOException("An attempt was made to seek before the beginning of the stream");
217                                 refpoint = initial_position;
218                                 break;
219                         case SeekOrigin.Current:
220                                 refpoint = current_position;
221                                 break;
222                         case SeekOrigin.End:
223                                 refpoint = length;
224                                 break;
225                         default:
226                                 throw new ArgumentException("Invalid SeekOrigin option");
227                         }
228                         refpoint += (int)offset;
229                         if (refpoint < initial_position)
230                                 throw new IOException("An attempt was made to seek before the beginning of the stream");
231                         current_position = refpoint;
232                         return(current_position);
233                 }
234                  
235                 public override void SetLength (long value)
236                 {
237                         if (closed)
238                                 throw new ObjectDisposedException("The stream is closed");
239                         if (value < 0)
240                                 throw new ArgumentOutOfRangeException("length", "Non-negative number required.");
241                         if (value > capacity)
242                                 throw new IOException ("Unable to expand length of this stream beyond its capacity.");
243                         if (fileaccess == FileAccess.Read)
244                                 throw new NotSupportedException ("Stream does not support writing.");
245                         length = value;
246                         if (length < current_position)
247                                 current_position = length;
248                 }
249
250                 public override void Flush ()
251                 {
252                         if (closed)
253                                 throw new ObjectDisposedException("The stream is closed");
254                         //This method performs no action for this class
255                         //but is included as part of the Stream base class
256                 }
257                  
258                 protected override void Dispose (bool disposing)
259                 {
260
261                         closed = true;
262                 }
263                  
264                 public override void Write (byte[] buffer, int offset, int count)
265                 {
266                         if (closed)
267                                 throw new ObjectDisposedException("The stream is closed");
268                         if (buffer == null)
269                                 throw new ArgumentNullException("The buffer parameter is a null reference");
270                         if ((current_position + count) > capacity)
271                                 throw new NotSupportedException ("Unable to expand length of this stream beyond its capacity.");
272                         if (offset < 0)
273                                 throw new ArgumentOutOfRangeException("offset", "Non-negative number required.");
274                         if (count < 0)
275                                 throw new ArgumentOutOfRangeException("count", "Non-negative number required.");
276                         if ((buffer.Length - offset) < count)
277                                 throw new ArgumentException("The length of the buffer array minus the offset parameter is less than the count parameter");
278                         if (fileaccess == FileAccess.Read)
279                                 throw new NotSupportedException ("Stream does not support writing.");
280                         else {
281                                 unsafe {
282                                         // use Marshal.WriteByte since that allow us to start writing
283                                         // from the current position
284                                         for (int i = 0; i < count; i++)
285                                                 Marshal.WriteByte (initial_pointer, (int) current_position++, buffer [offset + i]);
286
287                                         if (current_position > length)
288                                                 length = current_position;
289                                 }
290                         }
291                 }
292                 
293                 public override void WriteByte (byte value)
294                  {
295                         if (closed)
296                                 throw new ObjectDisposedException("The stream is closed");
297                         
298                         if (current_position == capacity)
299                                 throw new NotSupportedException("The current position is at the end of the capacity of the stream");
300                         if (fileaccess == FileAccess.Read)
301                                 throw new NotSupportedException("Stream does not support writing.");
302                         else {
303                                 unsafe {
304                                         Marshal.WriteByte(initial_pointer, (int)current_position, value);
305                                         current_position++;
306                                         if (current_position > length)
307                                                 length = current_position;
308                                 }
309                         }
310                 }
311
312                 protected unsafe void Initialize (byte* pointer, long length,
313                                                   long capacity,
314                                                   FileAccess access)
315                 {
316                         fileaccess = access;
317                         this.length = length;
318                         this.capacity = capacity;
319                         initial_position = 0;
320                         current_position = initial_position;
321                         canseek = true;
322                         initial_pointer = new IntPtr ((void *)pointer);
323                         closed = false;
324                 }
325 #endregion
326         }
327 }
328 #endif
329