5 // Konstantin Triger <kostat@mainsoft.com>
7 // (c) 2008 Mainsoft corp. <http://www.mainsoft.com>
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;
32 using System.Runtime.Remoting.Messaging;
37 namespace System.IO.Compression
39 public class DeflateStream : Stream
41 readonly Stream _baseStream;
42 readonly InflaterInputStream _reader;
43 readonly DeflaterOutputStream _writer;
45 readonly bool _leaveOpen;
48 delegate int ReadMethod (byte [] array, int offset, int count);
49 delegate void WriteMethod (byte [] array, int offset, int count);
51 internal DeflateStream (Stream compressedStream, CompressionMode mode, bool leaveOpen, bool gzip) {
52 if (compressedStream == null)
53 throw new ArgumentNullException ("compressedStream");
56 case CompressionMode.Compress:
57 if (!compressedStream.CanWrite)
58 throw new ArgumentException ("The base stream is not writeable.");
59 OutputStream outStream = new OutputStreamImpl(compressedStream);
60 _writer = gzip ? new GZIPOutputStream (outStream) : new DeflaterOutputStream (outStream, new Deflater (Deflater.DEFAULT_COMPRESSION, true));
62 case CompressionMode.Decompress:
63 if (!compressedStream.CanRead)
64 throw new ArgumentException ("The base stream is not readable.");
65 InputStream inStream = new InputStreamImpl (compressedStream);
66 _reader = gzip ? new GZIPInputStream (inStream) : new InflaterInputStream (inStream, new Inflater (true));
69 throw new ArgumentException ("mode");
72 _baseStream = compressedStream;
73 _leaveOpen = leaveOpen;
77 public DeflateStream (Stream compressedStream, CompressionMode mode)
79 this (compressedStream, mode, false, false) { }
81 public DeflateStream (Stream compressedStream, CompressionMode mode, bool leaveOpen)
83 this (compressedStream, mode, leaveOpen, false) { }
85 protected override void Dispose (bool disposing) {
87 base.Dispose (disposing);
93 base.Dispose (disposing);
102 private int ReadInternal (byte [] array, int offset, int count) {
103 int r = _reader.read (TypeUtils.ToSByteArray (array), offset, count);
104 return r < 0 ? 0 : r;
107 public override int Read (byte [] dest, int dest_offset, int count) {
109 throw new ObjectDisposedException ("DeflateStream");
111 throw new ArgumentNullException ("Destination array is null.");
113 throw new InvalidOperationException ("Stream does not support reading.");
114 int len = dest.Length;
115 if (dest_offset < 0 || count < 0)
116 throw new ArgumentException ("Dest or count is negative.");
117 if (dest_offset > len)
118 throw new ArgumentException ("destination offset is beyond array size");
119 if ((dest_offset + count) > len)
120 throw new ArgumentException ("Reading would overrun buffer");
122 return ReadInternal (dest, dest_offset, count);
125 private void WriteInternal (byte [] array, int offset, int count) {
126 _writer.write (TypeUtils.ToSByteArray (array), offset, count);
129 public override void Write (byte [] src, int src_offset, int count) {
131 throw new ObjectDisposedException ("DeflateStream");
134 throw new ArgumentNullException ("src");
137 throw new ArgumentOutOfRangeException ("src_offset");
140 throw new ArgumentOutOfRangeException ("count");
143 throw new NotSupportedException ("Stream does not support writing");
145 WriteInternal (src, src_offset, count);
148 private void FlushInternal (bool finish) {
150 throw new ObjectDisposedException ("DeflateStream");
152 if (_writer != null) {
160 public override void Flush () {
161 FlushInternal (false);
164 public override long Seek (long offset, SeekOrigin origin) {
165 throw new System.NotSupportedException ();
168 public override void SetLength (long value) {
169 throw new System.NotSupportedException ();
172 public override IAsyncResult BeginRead (byte [] buffer, int offset, int count,
173 AsyncCallback cback, object state) {
175 throw new ObjectDisposedException ("DeflateStream");
178 throw new NotSupportedException ("This stream does not support reading");
181 throw new ArgumentNullException ("buffer");
184 throw new ArgumentOutOfRangeException ("count", "Must be >= 0");
187 throw new ArgumentOutOfRangeException ("offset", "Must be >= 0");
189 if (count + offset > buffer.Length)
190 throw new ArgumentException ("Buffer too small. count/offset wrong.");
192 ReadMethod r = new ReadMethod (ReadInternal);
193 return r.BeginInvoke (buffer, offset, count, cback, state);
196 public override IAsyncResult BeginWrite (byte [] buffer, int offset, int count,
197 AsyncCallback cback, object state) {
199 throw new ObjectDisposedException ("DeflateStream");
202 throw new InvalidOperationException ("This stream does not support writing");
205 throw new ArgumentNullException ("buffer");
208 throw new ArgumentOutOfRangeException ("count", "Must be >= 0");
211 throw new ArgumentOutOfRangeException ("offset", "Must be >= 0");
213 if (count + offset > buffer.Length)
214 throw new ArgumentException ("Buffer too small. count/offset wrong.");
216 WriteMethod w = new WriteMethod (WriteInternal);
217 return w.BeginInvoke (buffer, offset, count, cback, state);
220 public override int EndRead (IAsyncResult async_result) {
221 if (async_result == null)
222 throw new ArgumentNullException ("async_result");
224 AsyncResult ares = async_result as AsyncResult;
226 throw new ArgumentException ("Invalid IAsyncResult", "async_result");
228 ReadMethod r = ares.AsyncDelegate as ReadMethod;
230 throw new ArgumentException ("Invalid IAsyncResult", "async_result");
232 return r.EndInvoke (async_result);
235 public override void EndWrite (IAsyncResult async_result) {
236 if (async_result == null)
237 throw new ArgumentNullException ("async_result");
239 AsyncResult ares = async_result as AsyncResult;
241 throw new ArgumentException ("Invalid IAsyncResult", "async_result");
243 WriteMethod w = ares.AsyncDelegate as WriteMethod;
245 throw new ArgumentException ("Invalid IAsyncResult", "async_result");
247 w.EndInvoke (async_result);
250 public Stream BaseStream {
255 public override bool CanRead {
257 return _open && _reader != null;
260 public override bool CanSeek {
265 public override bool CanWrite {
267 return _open && _writer != null;
270 public override long Length {
272 throw new NotSupportedException ();
275 public override long Position {
277 throw new NotSupportedException ();
280 throw new NotSupportedException ();
284 #region InputStreamImpl
286 sealed class InputStreamImpl : InputStream
288 readonly Stream _stream;
290 public InputStreamImpl (Stream stream) {
294 public override void close () {
298 public override int read () {
299 return BaseStream.ReadByte ();
302 public override int read (sbyte [] b, int off, int len) {
303 int r = BaseStream.Read ((byte []) TypeUtils.ToByteArray (b), off, len);
304 return r == 0 ? -1 : r;
307 public override long skip (long n) {
308 return BaseStream.Seek (n, SeekOrigin.Current);
311 public override bool Equals (object obj) {
312 return (obj is InputStreamImpl) &&
313 BaseStream.Equals (((InputStreamImpl) obj).BaseStream);
316 public override int GetHashCode () {
317 return _stream.GetHashCode ();
320 public Stream BaseStream {
321 get { return _stream; }
327 #region OutputStreamImpl
329 sealed class OutputStreamImpl : OutputStream
331 readonly Stream _stream;
333 public OutputStreamImpl (Stream stream) {
337 public override void close () {
341 public override void flush () {
345 public override void write (int b) {
346 BaseStream.WriteByte ((byte) (b & 0xFF));
349 public override void write (sbyte [] b, int off, int len) {
350 BaseStream.Write ((byte []) TypeUtils.ToByteArray (b), off, len);
353 public override bool Equals (object obj) {
354 return (obj is OutputStreamImpl) &&
355 BaseStream.Equals (((OutputStreamImpl) obj).BaseStream);
358 public override int GetHashCode () {
359 return _stream.GetHashCode ();
362 public Stream BaseStream {
363 get { return _stream; }