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.
32 using System.Runtime.InteropServices;
33 using System.Runtime.Remoting.Messaging;
38 namespace System.IO.Compression
40 public class DeflateStream : Stream
42 readonly Stream _baseStream;
43 readonly InflaterInputStream _reader;
44 readonly DeflaterOutputStream _writer;
46 readonly bool _leaveOpen;
49 delegate int ReadMethod (byte [] array, int offset, int count);
50 delegate void WriteMethod (byte [] array, int offset, int count);
52 internal DeflateStream (Stream compressedStream, CompressionMode mode, bool leaveOpen, bool gzip) {
53 if (compressedStream == null)
54 throw new ArgumentNullException ("compressedStream");
57 case CompressionMode.Compress:
58 if (!compressedStream.CanWrite)
59 throw new ArgumentException ("The base stream is not writeable.");
60 OutputStream outStream = new OutputStreamImpl(compressedStream);
61 _writer = gzip ? new GZIPOutputStream (outStream) : new DeflaterOutputStream (outStream, new Deflater (Deflater.DEFAULT_COMPRESSION, true));
63 case CompressionMode.Decompress:
64 if (!compressedStream.CanRead)
65 throw new ArgumentException ("The base stream is not readable.");
66 InputStream inStream = new InputStreamImpl (compressedStream);
67 _reader = gzip ? new GZIPInputStream (inStream) : new InflaterInputStream (inStream, new Inflater (true));
70 throw new ArgumentException ("mode");
73 _baseStream = compressedStream;
74 _leaveOpen = leaveOpen;
78 public DeflateStream (Stream compressedStream, CompressionMode mode)
80 this (compressedStream, mode, false, false) { }
82 public DeflateStream (Stream compressedStream, CompressionMode mode, bool leaveOpen)
84 this (compressedStream, mode, leaveOpen, false) { }
86 protected override void Dispose (bool disposing) {
88 base.Dispose (disposing);
94 base.Dispose (disposing);
103 private int ReadInternal (byte [] array, int offset, int count) {
104 int r = _reader.read (TypeUtils.ToSByteArray (array), offset, count);
105 return r < 0 ? 0 : r;
108 public override int Read (byte [] dest, int dest_offset, int count) {
110 throw new ObjectDisposedException ("DeflateStream");
112 throw new ArgumentNullException ("Destination array is null.");
114 throw new InvalidOperationException ("Stream does not support reading.");
115 int len = dest.Length;
116 if (dest_offset < 0 || count < 0)
117 throw new ArgumentException ("Dest or count is negative.");
118 if (dest_offset > len)
119 throw new ArgumentException ("destination offset is beyond array size");
120 if ((dest_offset + count) > len)
121 throw new ArgumentException ("Reading would overrun buffer");
123 return ReadInternal (dest, dest_offset, count);
126 private void WriteInternal (byte [] array, int offset, int count) {
127 _writer.write (TypeUtils.ToSByteArray (array), offset, count);
130 public override void Write (byte [] src, int src_offset, int count) {
132 throw new ObjectDisposedException ("DeflateStream");
135 throw new ArgumentNullException ("src");
138 throw new ArgumentOutOfRangeException ("src_offset");
141 throw new ArgumentOutOfRangeException ("count");
144 throw new NotSupportedException ("Stream does not support writing");
146 WriteInternal (src, src_offset, count);
149 private void FlushInternal (bool finish) {
151 throw new ObjectDisposedException ("DeflateStream");
153 if (_writer != null) {
161 public override void Flush () {
162 FlushInternal (false);
165 public override long Seek (long offset, SeekOrigin origin) {
166 throw new System.NotSupportedException ();
169 public override void SetLength (long value) {
170 throw new System.NotSupportedException ();
173 public override IAsyncResult BeginRead (byte [] buffer, int offset, int count,
174 AsyncCallback cback, object state) {
176 throw new ObjectDisposedException ("DeflateStream");
179 throw new NotSupportedException ("This stream does not support reading");
182 throw new ArgumentNullException ("buffer");
185 throw new ArgumentOutOfRangeException ("count", "Must be >= 0");
188 throw new ArgumentOutOfRangeException ("offset", "Must be >= 0");
190 if (count + offset > buffer.Length)
191 throw new ArgumentException ("Buffer too small. count/offset wrong.");
193 ReadMethod r = new ReadMethod (ReadInternal);
194 return r.BeginInvoke (buffer, offset, count, cback, state);
197 public override IAsyncResult BeginWrite (byte [] buffer, int offset, int count,
198 AsyncCallback cback, object state) {
200 throw new ObjectDisposedException ("DeflateStream");
203 throw new InvalidOperationException ("This stream does not support writing");
206 throw new ArgumentNullException ("buffer");
209 throw new ArgumentOutOfRangeException ("count", "Must be >= 0");
212 throw new ArgumentOutOfRangeException ("offset", "Must be >= 0");
214 if (count + offset > buffer.Length)
215 throw new ArgumentException ("Buffer too small. count/offset wrong.");
217 WriteMethod w = new WriteMethod (WriteInternal);
218 return w.BeginInvoke (buffer, offset, count, cback, state);
221 public override int EndRead (IAsyncResult async_result) {
222 if (async_result == null)
223 throw new ArgumentNullException ("async_result");
225 AsyncResult ares = async_result as AsyncResult;
227 throw new ArgumentException ("Invalid IAsyncResult", "async_result");
229 ReadMethod r = ares.AsyncDelegate as ReadMethod;
231 throw new ArgumentException ("Invalid IAsyncResult", "async_result");
233 return r.EndInvoke (async_result);
236 public override void EndWrite (IAsyncResult async_result) {
237 if (async_result == null)
238 throw new ArgumentNullException ("async_result");
240 AsyncResult ares = async_result as AsyncResult;
242 throw new ArgumentException ("Invalid IAsyncResult", "async_result");
244 WriteMethod w = ares.AsyncDelegate as WriteMethod;
246 throw new ArgumentException ("Invalid IAsyncResult", "async_result");
248 w.EndInvoke (async_result);
251 public Stream BaseStream {
256 public override bool CanRead {
258 return _open && _reader != null;
261 public override bool CanSeek {
266 public override bool CanWrite {
268 return _open && _writer != null;
271 public override long Length {
273 throw new NotSupportedException ();
276 public override long Position {
278 throw new NotSupportedException ();
281 throw new NotSupportedException ();
285 #region InputStreamImpl
287 sealed class InputStreamImpl : InputStream
289 readonly Stream _stream;
291 public InputStreamImpl (Stream stream) {
295 public override void close () {
299 public override int read () {
300 return BaseStream.ReadByte ();
303 public override int read (sbyte [] b, int off, int len) {
304 int r = BaseStream.Read ((byte []) TypeUtils.ToByteArray (b), off, len);
305 return r == 0 ? -1 : r;
308 public override long skip (long n) {
309 return BaseStream.Seek (n, SeekOrigin.Current);
312 public override bool Equals (object obj) {
313 return (obj is InputStreamImpl) &&
314 BaseStream.Equals (((InputStreamImpl) obj).BaseStream);
317 public override int GetHashCode () {
318 return _stream.GetHashCode ();
321 public Stream BaseStream {
322 get { return _stream; }
328 #region OutputStreamImpl
330 sealed class OutputStreamImpl : OutputStream
332 readonly Stream _stream;
334 public OutputStreamImpl (Stream stream) {
338 public override void close () {
342 public override void flush () {
346 public override void write (int b) {
347 BaseStream.WriteByte ((byte) (b & 0xFF));
350 public override void write (sbyte [] b, int off, int len) {
351 BaseStream.Write ((byte []) TypeUtils.ToByteArray (b), off, len);
354 public override bool Equals (object obj) {
355 return (obj is OutputStreamImpl) &&
356 BaseStream.Equals (((OutputStreamImpl) obj).BaseStream);
359 public override int GetHashCode () {
360 return _stream.GetHashCode ();
363 public Stream BaseStream {
364 get { return _stream; }