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