1 //
2 // GioStream.cs - provide a System.IO.Stream api to [Input|Output]Streams
3 //
4 // Author(s):
5 //	Stephane Delcroix  <stephane@delcroix.org>
6 //	Gabriel Burt  <gabriel.burt@gmail.com>
7 //
8 // Copyright (c) 2008 Stephane Delcroix
9 // Copyright (c) 2010 Novell, Inc.
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 //
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 //
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30 
31 using System;
32 
33 namespace GLib
34 {
35 	public class GioStream : System.IO.Stream
36 	{
37 		object stream;
38 		bool can_read;
39 		bool can_seek;
40 		bool can_write;
41 		bool is_disposed;
42 
GioStream(Uri uri, System.IO.FileMode mode)43 		public GioStream (Uri uri, System.IO.FileMode mode)
44 		{
45 			throw new NotImplementedException ();
46 		}
47 
GioStream(string filename, System.IO.FileMode mode)48 		public GioStream (string filename, System.IO.FileMode mode)
49 		{
50 			throw new NotImplementedException ();
51 		}
52 
GioStream(InputStream stream)53 		public GioStream (InputStream stream)
54 		{
55 			this.stream = stream;
56 			can_read = true;
57 			can_seek = stream is Seekable && (stream as Seekable).CanSeek;
58 		}
59 
GioStream(OutputStream stream)60 		public GioStream (OutputStream stream)
61 		{
62 			this.stream = stream;
63 			can_write = true;
64 			can_seek = stream is Seekable && (stream as Seekable).CanSeek;
65 		}
66 
67 #if GIO_SHARP_2_22
GioStream(IOStream stream)68 		public GioStream (IOStream stream)
69 		{
70 			this.stream = stream;
71 			can_read = true;
72 			can_write = true;
73 			can_seek = stream is Seekable && (stream as Seekable).CanSeek;
74 		}
75 #endif
76 
77 		public override bool CanSeek {
78 			get { return can_seek; }
79 		}
80 
81 		public override bool CanRead {
82 			get { return can_read; }
83 		}
84 
85 		public override bool CanWrite {
86 			get { return can_write; }
87 		}
88 
89 		public override long Length {
90 			get {
91 				if (!CanSeek)
92 					throw new NotSupportedException ("This stream doesn't support seeking");
93 				if (is_disposed)
94 					throw new ObjectDisposedException ("The stream is closed");
95 
96 				if (stream is FileInputStream) {
97 					FileInfo info = (stream as FileInputStream).QueryInfo ("standard::size", null);
98 					return info.Size;
99 				}
100 				if (stream is FileOutputStream) {
101 					FileInfo info = (stream as FileOutputStream).QueryInfo ("standard::size", null);
102 					return info.Size;
103 				}
104 #if GIO_SHARP_2_22
105 				if (stream is FileIOStream) {
106 					FileInfo info = (stream as FileIOStream).QueryInfo ("standard::size", null);
107 					return info.Size;
108 				}
109 #endif
110 				throw new NotImplementedException (String.Format ("not implemented for {0} streams", stream.GetType()));
111 			}
112 		}
113 
114 		public override long Position {
115 			get {
116 				if (!CanSeek)
117 					throw new NotSupportedException ("This stream doesn't support seeking");
118 				if (is_disposed)
119 					throw new ObjectDisposedException ("The stream is closed");
120 				return (stream as Seekable).Position;
121 			}
122 			set {
123 				Seek (value, System.IO.SeekOrigin.Begin);
124 			}
125 		}
126 
Flush()127 		public override void Flush ()
128 		{
129 			if (is_disposed)
130 				throw new ObjectDisposedException ("The stream is closed");
131 		}
132 
Read(byte[] buffer, int offset, int count)133 		public override int Read (byte[] buffer, int offset, int count)
134 		{
135 			if (buffer == null)
136 				throw new ArgumentNullException ("buffer");
137 			if (offset + count - 1 > buffer.Length)
138 				throw new ArgumentException ("(offset + count - 1) is greater than the length of buffer");
139 			if (offset < 0)
140 				throw new ArgumentOutOfRangeException ("offset");
141 			if (count < 0)
142 				throw new ArgumentOutOfRangeException ("count");
143 			if (!CanRead)
144 				throw new NotSupportedException ("The stream does not support reading");
145 			if (is_disposed)
146 				throw new ObjectDisposedException ("The stream is closed");
147 			InputStream input_stream = null;
148 			if (stream is InputStream)
149 				input_stream = stream as InputStream;
150 #if GIO_SHARP_2_22
151 			else if (stream is IOStream)
152 				input_stream = (stream as IOStream).InputStream;
153 #endif
154 			if (input_stream == null)
155 				throw new System.Exception ("this shouldn't happen");
156 
157 			if (offset == 0)
158 				return (int)input_stream.Read (buffer, (ulong)count, null);
159 			else {
160 				byte[] buf = new byte[count];
161 				int ret = (int)input_stream.Read (buf, (ulong)count, null);
162 				buf.CopyTo (buffer, offset);
163 				return ret;
164 			}
165 		}
166 
Write(byte[] buffer, int offset, int count)167 		public override void Write (byte[] buffer, int offset, int count)
168 		{
169 			if (buffer == null)
170 				throw new ArgumentNullException ("buffer");
171 			if (offset + count  > buffer.Length)
172 				throw new ArgumentException ("(offset + count) is greater than the length of buffer");
173 			if (offset < 0)
174 				throw new ArgumentOutOfRangeException ("offset");
175 			if (count < 0)
176 				throw new ArgumentOutOfRangeException ("count");
177 			if (!CanWrite)
178 				throw new NotSupportedException ("The stream does not support writing");
179 			if (is_disposed)
180 				throw new ObjectDisposedException ("The stream is closed");
181 			OutputStream output_stream = null;
182 			if (stream is OutputStream)
183 				output_stream = stream as OutputStream;
184 #if GIO_SHARP_2_22
185 			else if (stream is IOStream)
186 				output_stream = (stream as IOStream).OutputStream;
187 #endif
188 			if (output_stream == null)
189 				throw new System.Exception ("this shouldn't happen");
190 			if (offset == 0) {
191 				output_stream.Write (buffer, (ulong)count, null);
192 				return;
193 			} else {
194 				byte[] buf = new byte[count];
195 				Array.Copy (buffer, offset, buf, 0, count);
196 				output_stream.Write (buf, (ulong)count, null);
197 				return;
198 			}
199 		}
200 
Seek(long offset, System.IO.SeekOrigin origin)201 		public override long Seek (long offset, System.IO.SeekOrigin origin)
202 		{
203 			if (!CanSeek)
204 				throw new NotSupportedException ("This stream doesn't support seeking");
205 			if (is_disposed)
206 				throw new ObjectDisposedException ("The stream is closed");
207 			Seekable seekable = stream as Seekable;
208 
209 			SeekType seek_type;
210 			switch (origin) {
211 			case System.IO.SeekOrigin.Current:
212 				seek_type = SeekType.Cur;
213 				break;
214 			case System.IO.SeekOrigin.End:
215 				seek_type = SeekType.End;
216 				break;
217 			case System.IO.SeekOrigin.Begin:
218 			default:
219 				seek_type = SeekType.Set;
220 				break;
221 			}
222 			seekable.Seek (offset, seek_type, null);
223 			return Position;
224 		}
225 
SetLength(long value)226 		public override void SetLength (long value)
227 		{
228 			if (!CanSeek || !CanWrite)
229 				throw new NotSupportedException ("This stream doesn't support seeking");
230 
231 			var seekable = stream as Seekable;
232 
233 			if (!seekable.CanTruncate ())
234 				throw new NotSupportedException ("This stream doesn't support truncating");
235 
236 			if (is_disposed)
237 				throw new ObjectDisposedException ("The stream is closed");
238 
239 			seekable.Truncate (value, null);
240 		}
241 
Close()242 		public override void Close ()
243 		{
244 			if (stream is InputStream)
245 				(stream as InputStream).Close (null);
246 			if (stream is OutputStream)
247 				(stream as OutputStream).Close (null);
248 #if GIO_SHARP_2_22
249 			if (stream is IOStream)
250 				(stream as IOStream).Close (null);
251 #endif
252 			is_disposed = true;
253 		}
254 	}
255 }
256