2 // Mono.Unix/StdioFileStream.cs
5 // Jonathan Pryor (jonpryor@vt.edu)
7 // (C) 2005 Jonathan Pryor
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 using System.Runtime.InteropServices;
37 public class StdioFileStream : Stream, IDisposable
39 public static readonly IntPtr InvalidFileStream = IntPtr.Zero;
40 public static readonly IntPtr StandardInput = Stdlib.stdin;
41 public static readonly IntPtr StandardOutput = Stdlib.stdout;
42 public static readonly IntPtr StandardError = Stdlib.stderr;
44 public StdioFileStream (IntPtr fileStream)
45 : this (fileStream, true) {}
47 public StdioFileStream (IntPtr fileStream, bool ownsHandle)
49 if (InvalidFileStream == fileStream)
50 throw new ArgumentException (Locale.GetText ("Invalid file stream"), "fileStream");
52 this.file = fileStream;
53 this.owner = ownsHandle;
55 long offset = Stdlib.fseek (file, 0, SeekFlags.SEEK_CUR);
58 Stdlib.fread (IntPtr.Zero, 0, 0, file);
59 if (Stdlib.ferror (file) == 0)
61 Stdlib.fwrite (IntPtr.Zero, 0, 0, file);
62 if (Stdlib.ferror (file) == 0)
64 Stdlib.clearerr (file);
67 private void AssertNotDisposed ()
69 if (file == InvalidFileStream)
70 throw new ObjectDisposedException ("Invalid File Stream");
73 public IntPtr FileStream {
77 public override bool CanRead {
81 public override bool CanSeek {
85 public override bool CanWrite {
86 get {return canWrite;}
89 public override long Length {
93 throw new NotSupportedException ("File Stream doesn't support seeking");
94 long curPos = Stdlib.ftell (file);
96 throw new NotSupportedException ("Unable to obtain current file position");
97 int r = Stdlib.fseek (file, 0, SeekFlags.SEEK_END);
98 UnixMarshal.ThrowExceptionForLastErrorIf (r);
100 long endPos = Stdlib.ftell (file);
102 UnixMarshal.ThrowExceptionForLastError ();
104 r = Stdlib.fseek (file, curPos, SeekFlags.SEEK_SET);
105 UnixMarshal.ThrowExceptionForLastErrorIf (r);
107 return endPos - curPos;
111 public override long Position {
113 AssertNotDisposed ();
115 throw new NotSupportedException ("The stream does not support seeking");
116 long pos = Stdlib.ftell (file);
118 UnixMarshal.ThrowExceptionForLastError ();
122 Seek (value, SeekOrigin.Begin);
126 public FilePosition FilePosition {
128 FilePosition pos = new FilePosition ();
129 int r = Stdlib.fgetpos (file, pos);
130 UnixMarshal.ThrowExceptionForLastErrorIf (r);
135 throw new ArgumentNullException ("value");
136 int r = Stdlib.fsetpos (file, value);
137 UnixMarshal.ThrowExceptionForLastErrorIf (r);
141 public override void Flush ()
143 int r = Stdlib.fflush (file);
145 UnixMarshal.ThrowExceptionForLastError ();
148 public override unsafe int Read ([In, Out] byte[] buffer, int offset, int count)
150 AssertNotDisposed ();
151 AssertValidBuffer (buffer, offset, count);
153 throw new NotSupportedException ("Stream does not support reading");
156 fixed (byte* buf = &buffer[offset]) {
157 r = Stdlib.fread (buf, 1, (ulong) count, file);
159 if (r != (ulong) count) {
160 if (Stdlib.feof (file) != 0)
161 throw new EndOfStreamException ();
162 if (Stdlib.ferror (file) != 0)
163 throw new IOException ();
168 private void AssertValidBuffer (byte[] buffer, int offset, int count)
171 throw new ArgumentNullException ("buffer");
173 throw new ArgumentOutOfRangeException ("offset", "< 0");
175 throw new ArgumentOutOfRangeException ("count", "< 0");
176 if (offset > buffer.Length)
177 throw new ArgumentException ("destination offset is beyond array size");
178 if (offset > (buffer.Length - count))
179 throw new ArgumentException ("would overrun buffer");
182 public void Rewind ()
184 Stdlib.rewind (file);
187 public override long Seek (long offset, SeekOrigin origin)
189 AssertNotDisposed ();
191 throw new NotSupportedException ("The File Stream does not support seeking");
193 SeekFlags sf = SeekFlags.SEEK_CUR;
195 case SeekOrigin.Begin: sf = SeekFlags.SEEK_SET; break;
196 case SeekOrigin.Current: sf = SeekFlags.SEEK_CUR; break;
197 case SeekOrigin.End: sf = SeekFlags.SEEK_END; break;
200 int r = Stdlib.fseek (file, offset, sf);
202 UnixMarshal.ThrowExceptionForLastError ();
204 long pos = Stdlib.ftell (file);
206 UnixMarshal.ThrowExceptionForLastError ();
211 public override void SetLength (long value)
213 throw new NotSupportedException ("ANSI C doesn't provide a way to truncate a file");
216 public override unsafe void Write (byte[] buffer, int offset, int count)
218 AssertNotDisposed ();
219 AssertValidBuffer (buffer, offset, count);
221 throw new NotSupportedException ("File Stream does not support writing");
224 fixed (byte* buf = &buffer[offset]) {
225 r = Stdlib.fwrite (buf, (ulong) 1, (ulong) count, file);
227 if (r != (ulong) count)
228 UnixMarshal.ThrowExceptionForLastError ();
236 public override void Close ()
238 if (file == InvalidFileStream)
242 int r = Stdlib.fclose (file);
244 UnixMarshal.ThrowExceptionForLastError ();
245 file = InvalidFileStream;
248 void IDisposable.Dispose ()
250 AssertNotDisposed ();
251 GC.SuppressFinalize (this);
257 private bool canSeek = false;
258 private bool canRead = false;
259 private bool canWrite = false;
260 private bool owner = true;
261 private IntPtr file = InvalidFileStream;