@@ -11,130 +11,130 @@
  * You must not remove this notice, or any other, from this software.
  *
  *
- * ***************************************************************************/
-
-#if !SILVERLIGHT && !WIN8 && !WP75
-using System.IO.Compression;
-#endif
-
-using System;
+ * ***************************************************************************/
+
+#if !SILVERLIGHT && !WIN8 && !WP75
+using System.IO.Compression;
+#endif
+
+using System;
 using System.Diagnostics;
 using System.IO;
-using System.Runtime.InteropServices;
-using IronRuby.Builtins;
-using IronRuby.Runtime;
-using Microsoft.Scripting.Runtime;
-using Microsoft.Scripting.Utils;
+using System.Runtime.InteropServices;
+using IronRuby.Builtins;
+using IronRuby.Runtime;
+using Microsoft.Scripting.Runtime;
+using Microsoft.Scripting.Utils;
 using zlib = ComponentAce.Compression.Libs.ZLib;
-
-namespace IronRuby.StandardLibrary.Zlib {
-
-    [RubyModule("Zlib")]
-    public static class Zlib {
-
-        #region Constants
-
-        [RubyConstant]
-        public const int NO_FLUSH = (int)zlib.FlushStrategy.Z_NO_FLUSH;
-
-        [RubyConstant]
-        public const int SYNC_FLUSH = (int)zlib.FlushStrategy.Z_SYNC_FLUSH;
-
-        [RubyConstant]
-        public const int FULL_FLUSH = (int)zlib.FlushStrategy.Z_FULL_FLUSH;
-
-        [RubyConstant]
-        public const int FINISH = (int)zlib.FlushStrategy.Z_FINISH;
-
-        [RubyConstant]
-        public static string ZLIB_VERSION = "1.2.3";
-
-        [RubyConstant]
-        public static string VERSION = "0.6.0";
-
-        [RubyConstant]
-        public const int MAX_WBITS = zlib.ZLibUtil.MAX_WBITS;
-
-        [RubyConstant]
-        public const int BINARY = (int)zlib.BlockType.Z_BINARY;
-
-        [RubyConstant]
-        public const int ASCII = (int)zlib.BlockType.Z_ASCII;
-
-        [RubyConstant]
-        public const int UNKNOWN = (int)zlib.BlockType.Z_UNKNOWN;
-
-        [RubyConstant]
-        public const int NO_COMPRESSION = 0;
-
-        [RubyConstant]
-        public const int BEST_SPEED = 1;
-
-        [RubyConstant]
-        public const int BEST_COMPRESSION = 9;
-
-        [RubyConstant]
-        public const int DEFAULT_COMPRESSION = zlib.Deflate.Z_DEFAULT_COMPRESSION;
-
-        [RubyConstant]
-        public const int FILTERED = (int)zlib.CompressionStrategy.Z_FILTERED;
-
-        [RubyConstant]
-        public const int HUFFMAN_ONLY = (int)zlib.CompressionStrategy.Z_HUFFMAN_ONLY;
-
-        [RubyConstant]
-        public const int DEFAULT_STRATEGY = (int)zlib.CompressionStrategy.Z_DEFAULT_STRATEGY;
-
-        [RubyConstant]
-        public const int DEF_MEM_LEVEL = zlib.Deflate.DEF_MEM_LEVEL;
-
-        internal const int DEFAULTALLOC = 1024;
-        private const int Z_OK = (int)zlib.ZLibResultCode.Z_OK;
-        private const int Z_STREAM_END = (int)zlib.ZLibResultCode.Z_STREAM_END;
-        private const int Z_BUF_ERROR = (int)zlib.ZLibResultCode.Z_BUF_ERROR;
-        private const int Z_STREAM_ERROR = (int)zlib.ZLibResultCode.Z_STREAM_ERROR;
-        
-        #endregion
-
-        #region CRC32
-
-        [RubyMethod("crc_table", RubyMethodAttributes.PublicSingleton)]
-        public static RubyArray/*!*/ GetCrcTable(RubyModule/*!*/ self) {
-            var result = new RubyArray(crcTable.Length);
-            for (int i = 0; i < crcTable.Length; i++) {
-                result.Add(Protocols.Normalize(crcTable[i]));
-            }
-
-            return result;
-        }
-
-        [RubyMethod("crc32", RubyMethodAttributes.PublicSingleton)]
-        public static int GetCrc(RubyModule/*!*/ self) {
-            return 0;
-        }
-
-        [RubyMethod("crc32", RubyMethodAttributes.PublicSingleton)]
-        public static object GetCrc(RubyModule/*!*/ self, [Optional, DefaultProtocol]MutableString str, [Optional]int initialCrc) {
-            byte[] bytes;
-            if (str == null) {
-                bytes = new byte[0];
-            } else {
-                bytes = str.ToByteArray();
-            }
-            uint result = UpdateCrc(unchecked((uint)initialCrc), bytes, 0, bytes.Length);
-            return Protocols.Normalize(result);
-        }
-
-        // See RFC1950 for details. http://www.faqs.org/rfcs/rfc1950.html
-        internal static uint UpdateCrc(uint crc, byte[] buffer, int offset, int length) {
-            crc ^= 0xffffffffU;
-            while (--length >= 0) {
-                crc = crcTable[(crc ^ buffer[offset++]) & 0xFF] ^ (crc >> 8);
-            }
-            crc ^= 0xffffffffU;
-            return crc;
-        }
-
+
+namespace IronRuby.StandardLibrary.Zlib {
+
+    [RubyModule("Zlib")]
+    public static class Zlib {
+
+        #region Constants
+
+        [RubyConstant]
+        public const int NO_FLUSH = (int)zlib.FlushStrategy.Z_NO_FLUSH;
+
+        [RubyConstant]
+        public const int SYNC_FLUSH = (int)zlib.FlushStrategy.Z_SYNC_FLUSH;
+
+        [RubyConstant]
+        public const int FULL_FLUSH = (int)zlib.FlushStrategy.Z_FULL_FLUSH;
+
+        [RubyConstant]
+        public const int FINISH = (int)zlib.FlushStrategy.Z_FINISH;
+
+        [RubyConstant]
+        public static string ZLIB_VERSION = "1.2.3";
+
+        [RubyConstant]
+        public static string VERSION = "0.6.0";
+
+        [RubyConstant]
+        public const int MAX_WBITS = zlib.ZLibUtil.MAX_WBITS;
+
+        [RubyConstant]
+        public const int BINARY = (int)zlib.BlockType.Z_BINARY;
+
+        [RubyConstant]
+        public const int ASCII = (int)zlib.BlockType.Z_ASCII;
+
+        [RubyConstant]
+        public const int UNKNOWN = (int)zlib.BlockType.Z_UNKNOWN;
+
+        [RubyConstant]
+        public const int NO_COMPRESSION = 0;
+
+        [RubyConstant]
+        public const int BEST_SPEED = 1;
+
+        [RubyConstant]
+        public const int BEST_COMPRESSION = 9;
+
+        [RubyConstant]
+        public const int DEFAULT_COMPRESSION = zlib.Deflate.Z_DEFAULT_COMPRESSION;
+
+        [RubyConstant]
+        public const int FILTERED = (int)zlib.CompressionStrategy.Z_FILTERED;
+
+        [RubyConstant]
+        public const int HUFFMAN_ONLY = (int)zlib.CompressionStrategy.Z_HUFFMAN_ONLY;
+
+        [RubyConstant]
+        public const int DEFAULT_STRATEGY = (int)zlib.CompressionStrategy.Z_DEFAULT_STRATEGY;
+
+        [RubyConstant]
+        public const int DEF_MEM_LEVEL = zlib.Deflate.DEF_MEM_LEVEL;
+
+        internal const int DEFAULTALLOC = 1024;
+        private const int Z_OK = (int)zlib.ZLibResultCode.Z_OK;
+        private const int Z_STREAM_END = (int)zlib.ZLibResultCode.Z_STREAM_END;
+        private const int Z_BUF_ERROR = (int)zlib.ZLibResultCode.Z_BUF_ERROR;
+        private const int Z_STREAM_ERROR = (int)zlib.ZLibResultCode.Z_STREAM_ERROR;
+
+        #endregion
+
+        #region CRC32
+
+        [RubyMethod("crc_table", RubyMethodAttributes.PublicSingleton)]
+        public static RubyArray/*!*/ GetCrcTable(RubyModule/*!*/ self) {
+            var result = new RubyArray(crcTable.Length);
+            for (int i = 0; i < crcTable.Length; i++) {
+                result.Add(Protocols.Normalize(crcTable[i]));
+            }
+
+            return result;
+        }
+
+        [RubyMethod("crc32", RubyMethodAttributes.PublicSingleton)]
+        public static int GetCrc(RubyModule/*!*/ self) {
+            return 0;
+        }
+
+        [RubyMethod("crc32", RubyMethodAttributes.PublicSingleton)]
+        public static object GetCrc(RubyModule/*!*/ self, [Optional, DefaultProtocol]MutableString str, [Optional]int initialCrc) {
+            byte[] bytes;
+            if (str == null) {
+                bytes = new byte[0];
+            } else {
+                bytes = str.ToByteArray();
+            }
+            uint result = UpdateCrc(unchecked((uint)initialCrc), bytes, 0, bytes.Length);
+            return Protocols.Normalize(result);
+        }
+
+        // See RFC1950 for details. http://www.faqs.org/rfcs/rfc1950.html
+        internal static uint UpdateCrc(uint crc, byte[] buffer, int offset, int length) {
+            crc ^= 0xffffffffU;
+            while (--length >= 0) {
+                crc = crcTable[(crc ^ buffer[offset++]) & 0xFF] ^ (crc >> 8);
+            }
+            crc ^= 0xffffffffU;
+            return crc;
+        }
+
         private static readonly uint[] crcTable = new uint[] {  
             0x00000000u, 0x77073096u, 0xee0e612cu, 0x990951bau, 0x076dc419u,
             0x706af48fu, 0xe963a535u, 0x9e6495a3u, 0x0edb8832u, 0x79dcb8a4u,
@@ -188,147 +188,147 @@ public static class Zlib {
             0xcdd70693u, 0x54de5729u, 0x23d967bfu, 0xb3667a2eu, 0xc4614ab8u,
             0x5d681b02u, 0x2a6f2b94u, 0xb40bbe37u, 0xc30c8ea1u, 0x5a05df1bu,
             0x2d02ef8du
-        };
-
-        #endregion
-
-        #region Adler32
-
-        [RubyMethod("adler32", RubyMethodAttributes.PublicSingleton)]
-        public static object Adler32(RubyModule/*!*/ self, [Optional]MutableString str, [DefaultParameterValue(1)]int baseValue) {
-            if (MutableString.IsNullOrEmpty(str)) {
-                return baseValue;
-            }
-
-            byte[] buffer = str.ToByteArray();
-            return Protocols.Normalize(zlib.Adler32.GetAdler32Checksum(baseValue, buffer, 0, buffer.Length));
-        }
-
-        #endregion
-
-        #region ZStream class
-
-        [RubyClass("ZStream")]
-        public abstract class ZStream : RubyObject {
-            private zlib.ZStream _stream;
-
-            internal const bool compress = true;
-            internal const bool decompress = false;
-
-            protected ZStream(RubyClass/*!*/ cls, zlib.ZStream/*!*/ stream) 
-                : base(cls) {
-                Debug.Assert(stream != null);
-                _stream = stream;
-            }
-
-            protected zlib.ZStream GetStream() {
-                if (_stream == null) {
-                    throw new Error("stream is not ready");
-                }
-
-                return _stream;
-            }
-
-            internal static int Process(zlib.ZStream/*!*/ zst, MutableString str, zlib.FlushStrategy flush, bool compress, 
-                out MutableString/*!*/ result, ref MutableString trailingUncompressedData) {
-
-                result = MutableString.CreateBinary();
-
-                // add previously compressed data to the output:
-                if (zst.next_out != null) {
-                    result.Append(zst.next_out, 0, zst.next_out_index);
-                }
-
-                int err;
-                int bufferStart = zst.next_out_index;
-                err = Process(zst, str, flush, compress, ref trailingUncompressedData);
-                result.Append(zst.next_out, bufferStart, zst.next_out_index - bufferStart);
-
-                if (err == Z_STREAM_END && (flush == zlib.FlushStrategy.Z_FINISH || str == null)) {
-                    err = compress ? zst.deflateEnd() : zst.inflateEnd();
-                }
-
-                zst.next_out = null;
-                zst.next_out_index = 0;
-                zst.avail_out = 0;
-
-                return err;
-            }
-
-            internal static int Process(zlib.ZStream/*!*/ zst, MutableString str, zlib.FlushStrategy flush, bool compress,
-                ref MutableString trailingUncompressedData) {
-
-                if (str == null) {
-                    str = MutableString.FrozenEmpty;
-                    flush = zlib.FlushStrategy.Z_FINISH;
-                } else if (str.Length == 0 && flush == NO_FLUSH) {
-                    return Z_OK;
-                }
-
-                // data still available from previous input:
-                if (zst.avail_in > 0) {
-                    int err = Process(zst, flush, compress, ref trailingUncompressedData);
-
-                    // double flush:
-                    if (compress && flush != zlib.FlushStrategy.Z_FINISH && err == (int)zlib.ZLibResultCode.Z_DATA_ERROR) {
-                        return Z_OK;
-                    }
-
-                    // append new input to the current input:
-                    if (err != Z_OK && err != Z_STREAM_END) {
-                        byte[] currentInput = zst.next_in;
-                        byte[] newInput = str.ToByteArray();
-
-                        int minLength = zst.next_in_index + zst.avail_in + newInput.Length;
-                        if (currentInput.Length < minLength) {
-                            Array.Resize(ref currentInput, Math.Max(currentInput.Length * 2, minLength));
-                        }
-
-                        Buffer.BlockCopy(newInput, 0, currentInput, zst.next_in_index + zst.avail_in, newInput.Length);
-                        zst.next_in = currentInput;
-                        zst.avail_in += newInput.Length;
-
-                        return err;
-                    }
-                }
-
-                if (str != null) {
-                    byte[] input = str.ToByteArray();
-                    zst.next_in = input;
-                    zst.next_in_index = 0;
-                    zst.avail_in = input.Length;
-                } else {
-                    zst.avail_in = 0;
-                }
-
-                return Process(zst, flush, compress, ref trailingUncompressedData);
-            }
-
-            private static int Process(zlib.ZStream/*!*/ zst, zlib.FlushStrategy flush, bool compress,
-                ref MutableString trailingUncompressedData) {
-
-                if (zst.next_out == null) {
-                    zst.next_out = new byte[DEFAULTALLOC];
-                    zst.next_out_index = 0;
-                    zst.avail_out = zst.next_out.Length;
-                }
-
-                int result = compress ? zst.deflate(flush) : zst.inflate(flush);
-
-                while (result == Z_OK && zst.avail_out == 0) {
-                    byte[] output = zst.next_out;
-                    int oldLength = output.Length;
-
-                    Array.Resize(ref output, oldLength * 2);
-
-                    zst.next_out = output;
-                    zst.avail_out = oldLength;
-                    result = compress ? zst.deflate(flush) : zst.inflate(flush);
-                }
-
-                if (!compress && (result == Z_STREAM_END || result == Z_STREAM_ERROR && !zst.IsInitialized)) {
-                    // MRI hack: any data left in the stream are saved into a separate buffer and returned when "finish" is called
-                    // This is weird behavior, one would expect the rest of the stream is either ignored or copied to the output buffer.
+        };
+
+        #endregion
+
+        #region Adler32
+
+        [RubyMethod("adler32", RubyMethodAttributes.PublicSingleton)]
+        public static object Adler32(RubyModule/*!*/ self, [Optional]MutableString str, [DefaultParameterValue(1)]int baseValue) {
+            if (MutableString.IsNullOrEmpty(str)) {
+                return baseValue;
+            }
+
+            byte[] buffer = str.ToByteArray();
+            return Protocols.Normalize(zlib.Adler32.GetAdler32Checksum(baseValue, buffer, 0, buffer.Length));
+        }
+
+        #endregion
+
+        #region ZStream class
+
+        [RubyClass("ZStream")]
+        public abstract class ZStream : RubyObject {
+            private zlib.ZStream _stream;
+
+            internal const bool compress = true;
+            internal const bool decompress = false;
+
+            protected ZStream(RubyClass/*!*/ cls, zlib.ZStream/*!*/ stream)
+                : base(cls) {
+                Debug.Assert(stream != null);
+                _stream = stream;
+            }
+
+            protected zlib.ZStream GetStream() {
+                if (_stream == null) {
+                    throw new Error("stream is not ready");
+                }
+
+                return _stream;
+            }
+
+            internal static int Process(zlib.ZStream/*!*/ zst, MutableString str, zlib.FlushStrategy flush, bool compress,
+                out MutableString/*!*/ result, ref MutableString trailingUncompressedData) {
+
+                result = MutableString.CreateBinary();
+
+                // add previously compressed data to the output:
+                if (zst.next_out != null) {
+                    result.Append(zst.next_out, 0, zst.next_out_index);
+                }
+
+                int err;
+                int bufferStart = zst.next_out_index;
+                err = Process(zst, str, flush, compress, ref trailingUncompressedData);
+                result.Append(zst.next_out, bufferStart, zst.next_out_index - bufferStart);
+
+                if (err == Z_STREAM_END && (flush == zlib.FlushStrategy.Z_FINISH || str == null)) {
+                    err = compress ? zst.deflateEnd() : zst.inflateEnd();
+                }
+
+                zst.next_out = null;
+                zst.next_out_index = 0;
+                zst.avail_out = 0;
+
+                return err;
+            }
+
+            internal static int Process(zlib.ZStream/*!*/ zst, MutableString str, zlib.FlushStrategy flush, bool compress,
+                ref MutableString trailingUncompressedData) {
+
+                if (str == null) {
+                    str = MutableString.FrozenEmpty;
+                    flush = zlib.FlushStrategy.Z_FINISH;
+                } else if (str.Length == 0 && flush == NO_FLUSH) {
+                    return Z_OK;
+                }
+
+                // data still available from previous input:
+                if (zst.avail_in > 0) {
+                    int err = Process(zst, flush, compress, ref trailingUncompressedData);
+
+                    // double flush:
+                    if (compress && flush != zlib.FlushStrategy.Z_FINISH && err == (int)zlib.ZLibResultCode.Z_DATA_ERROR) {
+                        return Z_OK;
+                    }
+
+                    // append new input to the current input:
+                    if (err != Z_OK && err != Z_STREAM_END) {
+                        byte[] currentInput = zst.next_in;
+                        byte[] newInput = str.ToByteArray();
+
+                        int minLength = zst.next_in_index + zst.avail_in + newInput.Length;
+                        if (currentInput.Length < minLength) {
+                            Array.Resize(ref currentInput, Math.Max(currentInput.Length * 2, minLength));
+                        }
+
+                        Buffer.BlockCopy(newInput, 0, currentInput, zst.next_in_index + zst.avail_in, newInput.Length);
+                        zst.next_in = currentInput;
+                        zst.avail_in += newInput.Length;
+
+                        return err;
+                    }
+                }
+
+                if (str != null) {
+                    byte[] input = str.ToByteArray();
+                    zst.next_in = input;
+                    zst.next_in_index = 0;
+                    zst.avail_in = input.Length;
+                } else {
+                    zst.avail_in = 0;
+                }
+
+                return Process(zst, flush, compress, ref trailingUncompressedData);
+            }
+
+            private static int Process(zlib.ZStream/*!*/ zst, zlib.FlushStrategy flush, bool compress,
+                ref MutableString trailingUncompressedData) {
+
+                if (zst.next_out == null) {
+                    zst.next_out = new byte[DEFAULTALLOC];
+                    zst.next_out_index = 0;
+                    zst.avail_out = zst.next_out.Length;
+                }
+
+                int result = compress ? zst.deflate(flush) : zst.inflate(flush);
+
+                while (result == Z_OK && zst.avail_out == 0) {
+                    byte[] output = zst.next_out;
+                    int oldLength = output.Length;
+
+                    Array.Resize(ref output, oldLength * 2);
+
+                    zst.next_out = output;
+                    zst.avail_out = oldLength;
+                    result = compress ? zst.deflate(flush) : zst.inflate(flush);
+                }
+
+                if (!compress && (result == Z_STREAM_END || result == Z_STREAM_ERROR && !zst.IsInitialized)) {
+                    // MRI hack: any data left in the stream are saved into a separate buffer and returned when "finish" is called
+                    // This is weird behavior, one would expect the rest of the stream is either ignored or copied to the output buffer.
 #if COPY_UNCOMPRESSED_DATA_TO_OUTPUT_BUFFER
                     Debug.Assert(zst.next_in_index + zst.avail_in <= zst.next_in.Length);
                     Debug.Assert(zst.next_out_index + zst.avail_out <= zst.next_out.Length);
@@ -347,480 +347,480 @@ protected ZStream(RubyClass/*!*/ cls, zlib.ZStream/*!*/ stream)
                     zst.avail_out = Math.Max(zst.avail_out - zst.avail_in, 0);
                     zst.next_out_index += zst.avail_in;
                     zst.avail_in = 0;
-#else
-                    if (trailingUncompressedData == null) {
-                        trailingUncompressedData = MutableString.CreateBinary();
-                    }
-
-                    trailingUncompressedData.Append(zst.next_in, zst.next_in_index, zst.avail_in);
-
-                    // MRI subtracts till 0 is reached:
-                    zst.avail_out = Math.Max(zst.avail_out - zst.avail_in, 0);
-                    zst.avail_in = 0;
-#endif
-                    result = Z_STREAM_END;
-                } 
-
-                return result;
-            }
-
-            internal abstract MutableString/*!*/ Finish();
-            internal abstract void Close();
-
-            [RubyMethod("adler")]
-            public static object Adler(ZStream/*!*/ self) {
-                return Protocols.Normalize(self.GetStream().adler);
-            }
-
-            [RubyMethod("avail_in")]
-            public static int AvailIn(ZStream/*!*/ self) {
-                return self.GetStream().avail_in;
-            }
-
-            [RubyMethod("avail_out")]
-            public static int GetAvailOut(ZStream/*!*/ self) {
-                return self.GetStream().avail_out;
-            }
-
-            [RubyMethod("avail_out=")]
-            public static int SetAvailOut(ZStream/*!*/ self, int size) {
-                long newBufferSize;
-                var zst = self.GetStream();
-                if (size < 0 || (newBufferSize = zst.next_out_index + size) > Int32.MaxValue) {
-                    throw RubyExceptions.CreateArgumentError("negative string size (or size too big)");
-                }
-
-                int old = zst.avail_out;
-
-                // Make sure we have enough space in the buffer.
-                // We could keep the buffer larger but since users are calling 
-                // this API explicitly they probably want to resize the buffer.
-                var output = zst.next_out;
-                Array.Resize(ref output, (int)newBufferSize);
-                zst.next_out = output;
-                zst.avail_out = size;
-                return old;
-            }
-
-            [RubyMethod("finish")]
-            public static MutableString/*!*/ Finish(ZStream/*!*/ self) {
-                return self.Finish();
-            }
-
-            [RubyMethod("close")]
-            public static void Close(ZStream/*!*/ self) {
-                if (self._stream != null) {
-                    self.Close();
-                    self._stream = null;
-                }
-            }
-
-            [RubyMethod("stream_end?")]
-            [RubyMethod("finished?")]
-            [RubyMethod("closed?")]
-            public static bool IsClosed(ZStream/*!*/ self) {
-                var zst = self._stream;
-                return zst == null || !zst.IsInitialized;
-            }
-
-            [RubyMethod("data_type")]
-            public static int DataType(ZStream/*!*/ self) {
-                return (int)self.GetStream().Data_type;
-            }
-
-            [RubyMethod("flush_next_in")]
-            public static MutableString/*!*/ FlushNextIn(ZStream/*!*/ self) {
-                throw new NotImplementedError();
-            }
-
-            [RubyMethod("flush_next_out")]
-            public static MutableString/*!*/ FlushNextOut(ZStream/*!*/ self) {
-                throw new NotImplementedError();
-            }
-
-            [RubyMethod("reset")]
-            public static void Reset(ZStream/*!*/ self) {
-                var zst = self.GetStream();
-                if (zst.IsInitialized) {
-                    int err = zst.reset();
-                    Debug.Assert(err == Z_OK);
-                }
-            }
-
-            [RubyMethod("total_in")]
-            public static object TotalIn(ZStream/*!*/ self) {
-                return Protocols.Normalize(self.GetStream().total_in);
-            }
-
-            [RubyMethod("total_out")]
-            public static object TotalOut(ZStream/*!*/ self) {
-                return Protocols.Normalize(self.GetStream().total_out);
-            }
-        }
-
-        #endregion
-
-        #region Deflate class
-
-        [RubyClass("Deflate")]
-        public class Deflate : ZStream {
-            public Deflate(
-                RubyClass/*!*/ cls,
-                [DefaultParameterValue(DEFAULT_COMPRESSION)]int level,
-                [DefaultParameterValue(MAX_WBITS)]int windowBits,
-                [DefaultParameterValue(DEF_MEM_LEVEL)]int memlevel,
-                [DefaultParameterValue(DEFAULT_STRATEGY)]int strategy)
-                : base(cls, CreateDeflateStream(level, windowBits, memlevel, strategy)) {
-            }
-
-            private static zlib.ZStream CreateDeflateStream(int level) {
-                return CreateDeflateStream(level, MAX_WBITS, DEF_MEM_LEVEL, DEFAULT_STRATEGY);
-            }
-
-            private static zlib.ZStream CreateDeflateStream(int level, int windowBits, int memLevel, int strategy) {
-                var stream = new zlib.ZStream();
-                int result = stream.deflateInit(level, windowBits, memLevel, (zlib.CompressionStrategy)strategy);
-                if (result != Z_OK) {
-                    throw MakeError(result, null);
-                }
-
-                return stream;
-            }
-
-            [RubyMethod("<<")]
-            public static Deflate/*!*/ AppendData(Deflate/*!*/ self, [DefaultProtocol]MutableString str) {
-                var zst = self.GetStream();
-
-                MutableString trailingUncompressedData = null;
-                int result = Process(zst, str, zlib.FlushStrategy.Z_NO_FLUSH, compress, ref trailingUncompressedData);
-
-                if (result != Z_OK) {
-                    throw MakeError(result, zst.msg);
-                }
-
-                return self;
-            }
-
-            [RubyMethod("deflate")]
-            public static MutableString/*!*/ Compress(Deflate/*!*/ self, [DefaultProtocol]MutableString str, [DefaultParameterValue(NO_FLUSH)]int flush) {
-                MutableString compressed;
-                MutableString trailingUncompressedData = null;
-
-                var zst = self.GetStream();
-                int result = Process(zst, str, (zlib.FlushStrategy)flush, compress, out compressed, ref trailingUncompressedData);
-
-                if (result != Z_OK) {
-                    throw MakeError(result, zst.msg);
-                }
-
-                return compressed;
-            }
-
-            internal override MutableString/*!*/ Finish() {
-                return GetStream().IsInitialized ? Compress(this, null, FINISH) : MutableString.CreateEmpty();
-            }
-
-            internal override void Close() {
-                GetStream().deflateEnd();
-            }
-
-            [RubyMethod("flush")]
-            public static MutableString/*!*/ Flush(Deflate/*!*/ self, [DefaultParameterValue(SYNC_FLUSH)]int flush) {
-                if (flush == NO_FLUSH) {
-                    return MutableString.CreateEmpty();
-                }
-
-                return Compress(self, MutableString.FrozenEmpty, flush);
-            }
-
-            [RubyMethod("params")]
-            public static void SetParams(
-                Deflate/*!*/ self, 
-                [DefaultParameterValue(DEFAULT_COMPRESSION)]int level, 
-                [DefaultParameterValue(DEFAULT_STRATEGY)]int strategy) {
-
-                var zst = self.GetStream();
-                int err = zst.deflateParams(level, (zlib.CompressionStrategy)strategy);
-                if (err != Z_OK) {
-                    throw MakeError(err, zst.msg);
-                }
-            }
-
-            [RubyMethod("set_dictionary")]
-            public static void SetParams(Deflate/*!*/ self, [NotNull]MutableString/*!*/ dictionary) {
-                byte[] buffer = dictionary.ToByteArray();
-                var zst = self.GetStream();
-                int err = zst.deflateSetDictionary(buffer, buffer.Length);
-                if (err != Z_OK) {
-                    throw MakeError(err, zst.msg);
-                }
-            }
-
-            [RubyMethod("deflate", RubyMethodAttributes.PublicSingleton)]
-            public static MutableString/*!*/ DeflateString(RubyClass/*!*/ self, 
-                [DefaultProtocol, NotNull]MutableString/*!*/ str, 
-                [DefaultParameterValue(DEFAULT_COMPRESSION)]int level) {
-
-                zlib.ZStream zst = CreateDeflateStream(level);
-                MutableString compressed;
-                MutableString trailingUncompressedData = null;
-
-                int result = Process(zst, str, zlib.FlushStrategy.Z_FINISH, compress, out compressed, ref trailingUncompressedData);
-                if (result != Z_OK) {
-                    throw MakeError(result, zst.msg);
-                }
-
-                return compressed;
-            }
-        }
-
-        #endregion
-
-        #region Inflate class
-
-        [RubyClass("Inflate")]
-        public class Inflate : ZStream {
-            private MutableString trailingUncompressedData;
-
-            public Inflate(RubyClass/*!*/ cls, [DefaultParameterValue(MAX_WBITS)]int windowBits)
-                : base(cls, CreateInflateStream(windowBits)) {
-            }
-
-            private static zlib.ZStream CreateInflateStream() {
-                return CreateInflateStream(MAX_WBITS);
-            }
-
-            private static zlib.ZStream CreateInflateStream(int windowBits) {
-                var zst = new zlib.ZStream();
-                int result = zst.inflateInit(windowBits);
-                if (result != Z_OK) {
-                    throw MakeError(result, zst.msg);
-                }
-
-                return zst;
-            }
-
-            [RubyMethod("<<")]
-            public static Inflate/*!*/ AppendData(Inflate/*!*/ self, [DefaultProtocol]MutableString str) {
-                var zst = self.GetStream();
-                int result = Process(zst, str, zlib.FlushStrategy.Z_NO_FLUSH, decompress, ref self.trailingUncompressedData);
-                
-                if (result != Z_OK && result != Z_STREAM_END) {
-                    throw MakeError(result, zst.msg);
-                }
-
-                return self;
-            }
-
-            [RubyMethod("inflate")]
-            public static MutableString/*!*/ InflateString(Inflate/*!*/ self, [DefaultProtocol]MutableString str) {
-                MutableString uncompressed;
-
-                var zst = self.GetStream();
-                int result = Process(zst, str, zlib.FlushStrategy.Z_SYNC_FLUSH, decompress, out uncompressed, ref self.trailingUncompressedData);
-                if (result != Z_OK && result != Z_STREAM_END) {
-                    throw MakeError(result, zst.msg);
-                }
-
-                return uncompressed;
-            }
-
-            internal override MutableString/*!*/ Finish() {
-                MutableString result;
-                if (GetStream().IsInitialized) {
-                    result = InflateString(this, null);
-                } else {
-                    result = MutableString.CreateBinary();
-                }
-
-                if (trailingUncompressedData != null) {
-                    result.Append(trailingUncompressedData);
-                    trailingUncompressedData = null;
-                }
-
-                return result;
-            }
-
-            internal override void Close() {
-                trailingUncompressedData = null;
-                GetStream().inflateEnd();
-            }
-
-            [RubyMethod("flush")]
-            public static MutableString/*!*/ Flush(Inflate/*!*/ self) {
-                return InflateString(self, null);
-            }
-
-            [RubyMethod("set_dictionary")]
-            public static MutableString/*!*/ SetDictionary(Inflate/*!*/ self, [NotNull]MutableString/*!*/ dictionary) {
-                byte[] buffer = dictionary.ToByteArray();
-                var zst = self.GetStream();
-                int err = zst.inflateSetDictionary(buffer, buffer.Length);
-                if (err != Z_OK) {
-                    throw MakeError(err, zst.msg);
-                }
-
-                return dictionary;
-            }
-
-            [RubyMethod("inflate", RubyMethodAttributes.PublicSingleton)]
-            public static MutableString/*!*/ InflateString(RubyClass/*!*/ self, [DefaultProtocol, NotNull]MutableString/*!*/ str) {
-                return InflateString(str);
-            }
-
-            internal static MutableString/*!*/ InflateString(MutableString/*!*/ str) {
-                zlib.ZStream zst = CreateInflateStream();
-
-                // uncompressed data are ignored:
-                MutableString trailingUncompressedData = null;
-                MutableString uncompressed;
-
-                int result = Process(zst, str, zlib.FlushStrategy.Z_SYNC_FLUSH, decompress, out uncompressed, ref trailingUncompressedData);
-                if (result != Z_OK && result != Z_STREAM_END) {
-                    throw MakeError(result, zst.msg);
-                }
-
-                return uncompressed;
-            }
-        }
-
-        #endregion
-
-#if !SILVERLIGHT && !WIN8 && !WP75
-        #region GzipFile class
-
-        // TODO: implement spec:
-        // http://www.gzip.org/zlib/rfc-gzip.html#specification
-
-        [RubyClass("GzipFile", BuildConfig="!SILVERLIGHT && !WIN8 && !WP75")]
-        public abstract class GZipFile : RubyObject, IDisposable {
-             private GZipStream _stream;
-            private const int BufferSize = 2048;
-
-            internal GZipFile(RubyClass/*!*/ cls, object io, CompressionMode mode) 
-                : base(cls) {
- 
-                bool canSeek = false;
-                if (io is Stream) {
-                    canSeek = ((Stream)io).CanSeek;
-                } else if (io is RubyObject) {
-                    canSeek = ((RubyObject)io).ImmediateClass.GetMethod("pos") != null || ((RubyObject)io).ImmediateClass.GetMethod("tell") != null;
+#else
+                    if (trailingUncompressedData == null) {
+                        trailingUncompressedData = MutableString.CreateBinary();
+                    }
+
+                    trailingUncompressedData.Append(zst.next_in, zst.next_in_index, zst.avail_in);
+
+                    // MRI subtracts till 0 is reached:
+                    zst.avail_out = Math.Max(zst.avail_out - zst.avail_in, 0);
+                    zst.avail_in = 0;
+#endif
+                    result = Z_STREAM_END;
                 }
-
-                var underlyingStream = new IOWrapper(
-                    cls.Context, 
-                    io, 
-                    canRead: mode == CompressionMode.Decompress, 
-                    canWrite: mode == CompressionMode.Compress,
-                    canSeek: canSeek,
-                    canFlush: true,
-                    canClose: true,
-                    bufferSize: BufferSize);
-
-                _stream = new GZipStream(underlyingStream, mode, leaveOpen: true);
-            }
-
-            internal IOWrapper/*!*/ GetWrapper() {
-                RequireOpen();
-                return (IOWrapper)_stream.BaseStream; 
-            }
-
-            private void RequireOpen() {
-                if (_stream == null) {
-                    throw new Error("closed gzip stream");
-                }
-            }
-
-            internal GZipStream/*!*/ GetStream() {
-                RequireOpen();
-                return _stream;
-            }
-
-            void IDisposable.Dispose() {
-                Close(closeUnderlyingObject: true);
-            }
-
-            internal void Close(bool closeUnderlyingObject) {
-                if (_stream != null) {
-                    var wrapper = GetWrapper();
-
-                    // doesn't close base stream due to leaveOpen == true:
-                    _stream.Close();
-                    
-                    if (closeUnderlyingObject) {
-                        wrapper.Close();
-                    } else {
-                        wrapper.Flush();
-                    }
-
-                    _stream = null;
-                }
-            }
-
-            internal bool IsClosed() {
-                return _stream == null;
-            }
-
-            [RubyMethod("wrap", RubyMethodAttributes.PublicSingleton)]
-            public static object Wrap(BinaryOpStorage/*!*/ newStorage, UnaryOpStorage/*!*/ closeStorage, 
-                BlockParam block, RubyClass/*!*/ self, object io) {
-
-                var newSite = newStorage.GetCallSite("new");
-                GZipFile gzipFile = (GZipFile)newSite.Target(newSite, self, io);
-                return gzipFile.Do(block);
-            }
-
-            protected object Do(BlockParam block) {
-                if (block == null) {
-                    return this;
-                }
-
-                try {
-                    object blockResult;
-                    block.Yield(this, out blockResult);
-                    return blockResult;
-                } finally {
-                    this.Close(closeUnderlyingObject: true);
-                }
-            }
-
-            [RubyMethod("closed?")]
-            public static bool IsClosed(GZipFile/*!*/ self) {
-                return self.IsClosed();
-            }
-
-            [RubyMethod("close")]
-            public static object Close(GZipFile/*!*/ self) {
-                object io = self.GetWrapper().UnderlyingObject;
-                self.Close(closeUnderlyingObject: true);
-                return io;
-            }
-
-            [RubyMethod("finish")]
-            public static object/*!*/ Finish(GZipFile/*!*/ self) {
-                object io = self.GetWrapper().UnderlyingObject;
-                self.Close(closeUnderlyingObject: false);
-                return io;
-            }
-
-            [RubyMethod("comment")]
-            public static MutableString Comment(GZipFile/*!*/ self) {
-                throw new NotImplementedError();
-            }
-
-            // crc() 
-            // level() 
-            // mtime() 
-
-            [RubyMethod("orig_name")]
-            [RubyMethod("original_name")]
-            public static MutableString OriginalName(GZipFile/*!*/ self) {
-                throw new NotImplementedError();
-            }
-
-            // os_code() 
-            // sync() 
-            // sync = flag
+
+                return result;
+            }
+
+            internal abstract MutableString/*!*/ Finish();
+            internal abstract void Close();
+
+            [RubyMethod("adler")]
+            public static object Adler(ZStream/*!*/ self) {
+                return Protocols.Normalize(self.GetStream().adler);
+            }
+
+            [RubyMethod("avail_in")]
+            public static int AvailIn(ZStream/*!*/ self) {
+                return self.GetStream().avail_in;
+            }
+
+            [RubyMethod("avail_out")]
+            public static int GetAvailOut(ZStream/*!*/ self) {
+                return self.GetStream().avail_out;
+            }
+
+            [RubyMethod("avail_out=")]
+            public static int SetAvailOut(ZStream/*!*/ self, int size) {
+                long newBufferSize;
+                var zst = self.GetStream();
+                if (size < 0 || (newBufferSize = zst.next_out_index + size) > Int32.MaxValue) {
+                    throw RubyExceptions.CreateArgumentError("negative string size (or size too big)");
+                }
+
+                int old = zst.avail_out;
+
+                // Make sure we have enough space in the buffer.
+                // We could keep the buffer larger but since users are calling 
+                // this API explicitly they probably want to resize the buffer.
+                var output = zst.next_out;
+                Array.Resize(ref output, (int)newBufferSize);
+                zst.next_out = output;
+                zst.avail_out = size;
+                return old;
+            }
+
+            [RubyMethod("finish")]
+            public static MutableString/*!*/ Finish(ZStream/*!*/ self) {
+                return self.Finish();
+            }
+
+            [RubyMethod("close")]
+            public static void Close(ZStream/*!*/ self) {
+                if (self._stream != null) {
+                    self.Close();
+                    self._stream = null;
+                }
+            }
+
+            [RubyMethod("stream_end?")]
+            [RubyMethod("finished?")]
+            [RubyMethod("closed?")]
+            public static bool IsClosed(ZStream/*!*/ self) {
+                var zst = self._stream;
+                return zst == null || !zst.IsInitialized;
+            }
+
+            [RubyMethod("data_type")]
+            public static int DataType(ZStream/*!*/ self) {
+                return (int)self.GetStream().Data_type;
+            }
+
+            [RubyMethod("flush_next_in")]
+            public static MutableString/*!*/ FlushNextIn(ZStream/*!*/ self) {
+                throw new NotImplementedError();
+            }
+
+            [RubyMethod("flush_next_out")]
+            public static MutableString/*!*/ FlushNextOut(ZStream/*!*/ self) {
+                throw new NotImplementedError();
+            }
+
+            [RubyMethod("reset")]
+            public static void Reset(ZStream/*!*/ self) {
+                var zst = self.GetStream();
+                if (zst.IsInitialized) {
+                    int err = zst.reset();
+                    Debug.Assert(err == Z_OK);
+                }
+            }
+
+            [RubyMethod("total_in")]
+            public static object TotalIn(ZStream/*!*/ self) {
+                return Protocols.Normalize(self.GetStream().total_in);
+            }
+
+            [RubyMethod("total_out")]
+            public static object TotalOut(ZStream/*!*/ self) {
+                return Protocols.Normalize(self.GetStream().total_out);
+            }
+        }
+
+        #endregion
+
+        #region Deflate class
+
+        [RubyClass("Deflate")]
+        public class Deflate : ZStream {
+            public Deflate(
+                RubyClass/*!*/ cls,
+                [DefaultParameterValue(DEFAULT_COMPRESSION)]int level,
+                [DefaultParameterValue(MAX_WBITS)]int windowBits,
+                [DefaultParameterValue(DEF_MEM_LEVEL)]int memlevel,
+                [DefaultParameterValue(DEFAULT_STRATEGY)]int strategy)
+                : base(cls, CreateDeflateStream(level, windowBits, memlevel, strategy)) {
+            }
+
+            private static zlib.ZStream CreateDeflateStream(int level) {
+                return CreateDeflateStream(level, MAX_WBITS, DEF_MEM_LEVEL, DEFAULT_STRATEGY);
+            }
+
+            private static zlib.ZStream CreateDeflateStream(int level, int windowBits, int memLevel, int strategy) {
+                var stream = new zlib.ZStream();
+                int result = stream.deflateInit(level, windowBits, memLevel, (zlib.CompressionStrategy)strategy);
+                if (result != Z_OK) {
+                    throw MakeError(result, null);
+                }
+
+                return stream;
+            }
+
+            [RubyMethod("<<")]
+            public static Deflate/*!*/ AppendData(Deflate/*!*/ self, [DefaultProtocol]MutableString str) {
+                var zst = self.GetStream();
+
+                MutableString trailingUncompressedData = null;
+                int result = Process(zst, str, zlib.FlushStrategy.Z_NO_FLUSH, compress, ref trailingUncompressedData);
+
+                if (result != Z_OK) {
+                    throw MakeError(result, zst.msg);
+                }
+
+                return self;
+            }
+
+            [RubyMethod("deflate")]
+            public static MutableString/*!*/ Compress(Deflate/*!*/ self, [DefaultProtocol]MutableString str, [DefaultParameterValue(NO_FLUSH)]int flush) {
+                MutableString compressed;
+                MutableString trailingUncompressedData = null;
+
+                var zst = self.GetStream();
+                int result = Process(zst, str, (zlib.FlushStrategy)flush, compress, out compressed, ref trailingUncompressedData);
+
+                if (result != Z_OK) {
+                    throw MakeError(result, zst.msg);
+                }
+
+                return compressed;
+            }
+
+            internal override MutableString/*!*/ Finish() {
+                return GetStream().IsInitialized ? Compress(this, null, FINISH) : MutableString.CreateEmpty();
+            }
+
+            internal override void Close() {
+                GetStream().deflateEnd();
+            }
+
+            [RubyMethod("flush")]
+            public static MutableString/*!*/ Flush(Deflate/*!*/ self, [DefaultParameterValue(SYNC_FLUSH)]int flush) {
+                if (flush == NO_FLUSH) {
+                    return MutableString.CreateEmpty();
+                }
+
+                return Compress(self, MutableString.FrozenEmpty, flush);
+            }
+
+            [RubyMethod("params")]
+            public static void SetParams(
+                Deflate/*!*/ self,
+                [DefaultParameterValue(DEFAULT_COMPRESSION)]int level,
+                [DefaultParameterValue(DEFAULT_STRATEGY)]int strategy) {
+
+                var zst = self.GetStream();
+                int err = zst.deflateParams(level, (zlib.CompressionStrategy)strategy);
+                if (err != Z_OK) {
+                    throw MakeError(err, zst.msg);
+                }
+            }
+
+            [RubyMethod("set_dictionary")]
+            public static void SetParams(Deflate/*!*/ self, [NotNull]MutableString/*!*/ dictionary) {
+                byte[] buffer = dictionary.ToByteArray();
+                var zst = self.GetStream();
+                int err = zst.deflateSetDictionary(buffer, buffer.Length);
+                if (err != Z_OK) {
+                    throw MakeError(err, zst.msg);
+                }
+            }
+
+            [RubyMethod("deflate", RubyMethodAttributes.PublicSingleton)]
+            public static MutableString/*!*/ DeflateString(RubyClass/*!*/ self,
+                [DefaultProtocol, NotNull]MutableString/*!*/ str,
+                [DefaultParameterValue(DEFAULT_COMPRESSION)]int level) {
+
+                zlib.ZStream zst = CreateDeflateStream(level);
+                MutableString compressed;
+                MutableString trailingUncompressedData = null;
+
+                int result = Process(zst, str, zlib.FlushStrategy.Z_FINISH, compress, out compressed, ref trailingUncompressedData);
+                if (result != Z_OK) {
+                    throw MakeError(result, zst.msg);
+                }
+
+                return compressed;
+            }
+        }
+
+        #endregion
+
+        #region Inflate class
+
+        [RubyClass("Inflate")]
+        public class Inflate : ZStream {
+            private MutableString trailingUncompressedData;
+
+            public Inflate(RubyClass/*!*/ cls, [DefaultParameterValue(MAX_WBITS)]int windowBits)
+                : base(cls, CreateInflateStream(windowBits)) {
+            }
+
+            private static zlib.ZStream CreateInflateStream() {
+                return CreateInflateStream(MAX_WBITS);
+            }
+
+            private static zlib.ZStream CreateInflateStream(int windowBits) {
+                var zst = new zlib.ZStream();
+                int result = zst.inflateInit(windowBits);
+                if (result != Z_OK) {
+                    throw MakeError(result, zst.msg);
+                }
+
+                return zst;
+            }
+
+            [RubyMethod("<<")]
+            public static Inflate/*!*/ AppendData(Inflate/*!*/ self, [DefaultProtocol]MutableString str) {
+                var zst = self.GetStream();
+                int result = Process(zst, str, zlib.FlushStrategy.Z_NO_FLUSH, decompress, ref self.trailingUncompressedData);
+
+                if (result != Z_OK && result != Z_STREAM_END) {
+                    throw MakeError(result, zst.msg);
+                }
+
+                return self;
+            }
+
+            [RubyMethod("inflate")]
+            public static MutableString/*!*/ InflateString(Inflate/*!*/ self, [DefaultProtocol]MutableString str) {
+                MutableString uncompressed;
+
+                var zst = self.GetStream();
+                int result = Process(zst, str, zlib.FlushStrategy.Z_SYNC_FLUSH, decompress, out uncompressed, ref self.trailingUncompressedData);
+                if (result != Z_OK && result != Z_STREAM_END) {
+                    throw MakeError(result, zst.msg);
+                }
+
+                return uncompressed;
+            }
+
+            internal override MutableString/*!*/ Finish() {
+                MutableString result;
+                if (GetStream().IsInitialized) {
+                    result = InflateString(this, null);
+                } else {
+                    result = MutableString.CreateBinary();
+                }
+
+                if (trailingUncompressedData != null) {
+                    result.Append(trailingUncompressedData);
+                    trailingUncompressedData = null;
+                }
+
+                return result;
+            }
+
+            internal override void Close() {
+                trailingUncompressedData = null;
+                GetStream().inflateEnd();
+            }
+
+            [RubyMethod("flush")]
+            public static MutableString/*!*/ Flush(Inflate/*!*/ self) {
+                return InflateString(self, null);
+            }
+
+            [RubyMethod("set_dictionary")]
+            public static MutableString/*!*/ SetDictionary(Inflate/*!*/ self, [NotNull]MutableString/*!*/ dictionary) {
+                byte[] buffer = dictionary.ToByteArray();
+                var zst = self.GetStream();
+                int err = zst.inflateSetDictionary(buffer, buffer.Length);
+                if (err != Z_OK) {
+                    throw MakeError(err, zst.msg);
+                }
+
+                return dictionary;
+            }
+
+            [RubyMethod("inflate", RubyMethodAttributes.PublicSingleton)]
+            public static MutableString/*!*/ InflateString(RubyClass/*!*/ self, [DefaultProtocol, NotNull]MutableString/*!*/ str) {
+                return InflateString(str);
+            }
+
+            internal static MutableString/*!*/ InflateString(MutableString/*!*/ str) {
+                zlib.ZStream zst = CreateInflateStream();
+
+                // uncompressed data are ignored:
+                MutableString trailingUncompressedData = null;
+                MutableString uncompressed;
+
+                int result = Process(zst, str, zlib.FlushStrategy.Z_SYNC_FLUSH, decompress, out uncompressed, ref trailingUncompressedData);
+                if (result != Z_OK && result != Z_STREAM_END) {
+                    throw MakeError(result, zst.msg);
+                }
+
+                return uncompressed;
+            }
+        }
+
+        #endregion
+
+#if !SILVERLIGHT && !WIN8 && !WP75
+        #region GzipFile class
+
+        // TODO: implement spec:
+        // http://www.gzip.org/zlib/rfc-gzip.html#specification
+
+        [RubyClass("GzipFile", BuildConfig = "!SILVERLIGHT && !WIN8 && !WP75")]
+        public abstract class GZipFile : RubyObject, IDisposable {
+            private GZipStream _stream;
+            private const int BufferSize = 2048;
+
+            internal GZipFile(RubyClass/*!*/ cls, object io, CompressionMode mode)
+                : base(cls) {
+
+                bool canSeek = false;
+                if (io is Stream) {
+                    canSeek = ((Stream)io).CanSeek;
+                } else if (io is RubyObject) {
+                    canSeek = ((RubyObject)io).ImmediateClass.GetMethod("pos") != null || ((RubyObject)io).ImmediateClass.GetMethod("tell") != null;
+                }
+
+                var underlyingStream = new IOWrapper(
+                    cls.Context,
+                    io,
+                    canRead: mode == CompressionMode.Decompress,
+                    canWrite: mode == CompressionMode.Compress,
+                    canSeek: canSeek,
+                    canFlush: true,
+                    canClose: true,
+                    bufferSize: BufferSize);
+
+                _stream = new GZipStream(underlyingStream, mode, leaveOpen: true);
+            }
+
+            internal IOWrapper/*!*/ GetWrapper() {
+                RequireOpen();
+                return (IOWrapper)_stream.BaseStream;
+            }
+
+            private void RequireOpen() {
+                if (_stream == null) {
+                    throw new Error("closed gzip stream");
+                }
+            }
+
+            internal GZipStream/*!*/ GetStream() {
+                RequireOpen();
+                return _stream;
+            }
+
+            void IDisposable.Dispose() {
+                Close(closeUnderlyingObject: true);
+            }
+
+            internal void Close(bool closeUnderlyingObject) {
+                if (_stream != null) {
+                    var wrapper = GetWrapper();
+
+                    // doesn't close base stream due to leaveOpen == true:
+                    _stream.Close();
+
+                    if (closeUnderlyingObject) {
+                        wrapper.Close();
+                    } else {
+                        wrapper.Flush();
+                    }
+
+                    _stream = null;
+                }
+            }
+
+            internal bool IsClosed() {
+                return _stream == null;
+            }
+
+            [RubyMethod("wrap", RubyMethodAttributes.PublicSingleton)]
+            public static object Wrap(BinaryOpStorage/*!*/ newStorage, UnaryOpStorage/*!*/ closeStorage,
+                BlockParam block, RubyClass/*!*/ self, object io) {
+
+                var newSite = newStorage.GetCallSite("new");
+                GZipFile gzipFile = (GZipFile)newSite.Target(newSite, self, io);
+                return gzipFile.Do(block);
+            }
+
+            protected object Do(BlockParam block) {
+                if (block == null) {
+                    return this;
+                }
+
+                try {
+                    object blockResult;
+                    block.Yield(this, out blockResult);
+                    return blockResult;
+                } finally {
+                    this.Close(closeUnderlyingObject: true);
+                }
+            }
+
+            [RubyMethod("closed?")]
+            public static bool IsClosed(GZipFile/*!*/ self) {
+                return self.IsClosed();
+            }
+
+            [RubyMethod("close")]
+            public static object Close(GZipFile/*!*/ self) {
+                object io = self.GetWrapper().UnderlyingObject;
+                self.Close(closeUnderlyingObject: true);
+                return io;
+            }
+
+            [RubyMethod("finish")]
+            public static object/*!*/ Finish(GZipFile/*!*/ self) {
+                object io = self.GetWrapper().UnderlyingObject;
+                self.Close(closeUnderlyingObject: false);
+                return io;
+            }
+
+            [RubyMethod("comment")]
+            public static MutableString Comment(GZipFile/*!*/ self) {
+                throw new NotImplementedError();
+            }
+
+            // crc() 
+            // level() 
+            // mtime() 
+
+            [RubyMethod("orig_name")]
+            [RubyMethod("original_name")]
+            public static MutableString OriginalName(GZipFile/*!*/ self) {
+                throw new NotImplementedError();
+            }
+
+            // os_code() 
+            // sync() 
+            // sync = flag
             // to_io
 
             [RubyMethod("pos")]
@@ -832,229 +832,235 @@ internal GZipFile(RubyClass/*!*/ cls, object io, CompressionMode mode)
             public static bool Eof(GZipReader/*!*/ self) {
                 return self.GetWrapper().Eof;
             }
-
-            [RubyException("Error"), Serializable]
-            public class Error : SystemException {
-                public Error() : this(null, null) { }
-                public Error(string message) : this(message, null) { }
-                public Error(string message, Exception inner) : base(message ?? "Error", inner) { }
-
-#if FEATURE_SERIALIZATION
-                protected Error(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
-                    : base(info, context) { }
-#endif
-            }
-        }
-
-        #endregion
-
-        #region GzipReader class
-
-        // TODO: Includes(typeof(Enumerable)
-        [RubyClass("GzipReader", BuildConfig="!SILVERLIGHT && !WIN8 && !WP75")]
+
+            [RubyException("Error"), Serializable]
+            public class Error : SystemException {
+                public Error() : this(null, null) { }
+                public Error(string message) : this(message, null) { }
+                public Error(string message, Exception inner) : base(message ?? "Error", inner) { }
+
+#if FEATURE_SERIALIZATION
+                protected Error(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
+                    : base(info, context) { }
+#endif
+            }
+        }
+
+        #endregion
+
+        #region GzipReader class
+
+        // TODO: Includes(typeof(Enumerable)
+        [RubyClass("GzipReader", BuildConfig = "!SILVERLIGHT && !WIN8 && !WP75")]
         public class GZipReader : GZipFile {
             private RubyEncoding _encoding = null;
 
-            private GZipReader(RubyClass/*!*/ cls, object io, Hash options)
+            private GZipReader(RubyClass/*!*/ cls, object io, Hash options)
                 : base(cls, io, CompressionMode.Decompress) {
-                    if (options != null) {
-                        // TODO: _encoding = options[:external_encoding];
-                    }
-            }
-
+                if (options != null) {
+                    foreach (var entry in options) {
+                        switch (cls.Context.Operations.ConvertTo<RubySymbol>(entry.Key).String.ToString()) {
+                            case "external_encoding":
+                                _encoding = cls.Context.Operations.ConvertTo<RubyEncoding>(entry.Value);
+                                break;
+                        }
+                    }
+                }
+            }
+
             [RubyConstructor]
-            public static GZipReader/*!*/ Create(RubyClass/*!*/ self, object io, [Optional, DefaultParameterValue(null)]Hash options) {
-                return new GZipReader(self, io, options);
-            }
-
-            [RubyMethod("open", RubyMethodAttributes.PublicSingleton)]
-            public static object Open(BlockParam block, RubyClass/*!*/ self, [DefaultProtocol, NotNull]MutableString/*!*/ path) {
-                var strPath = self.Context.DecodePath(path);
-                var file = new RubyFile(self.Context, strPath, IOMode.ReadOnly);
-                var gzipReader = Create(self, file);
-                return gzipReader.Do(block);
-            }
-
-            [RubyMethod("read")]
-            public static MutableString Read(GZipReader/*!*/ self, [DefaultProtocol, Optional]int? bytes) {
-                if (bytes.HasValue && bytes.Value < 0) {
-                    throw RubyExceptions.CreateArgumentError("negative length -1 given");
-                }
-
-                var stream = self.GetStream();
-                MutableString result = MutableString.CreateBinary(self._encoding ?? RubyEncoding.Binary);
-                if (bytes.HasValue) {
-                    int bytesRead = result.Append(stream, bytes.Value);
-                    if (bytesRead == 0 && bytes.Value != 0) {
-                        return null;
-                    }
-                } else {
-                    result.Append(stream);
-                }
-
-                return result;
-            }
-        }
-
-        #endregion
-
-        #region GzipWriter class
-         
-        [RubyClass("GzipWriter", BuildConfig="!SILVERLIGHT && !WIN8 && !WP75")]
-        // TODO: [Includes(typeof(PrintOps), Copy = true)]
-        public class GzipWriter : GZipFile {
+            public static GZipReader/*!*/ Create(RubyClass/*!*/ self, object io, [Optional, DefaultParameterValue(null)]Hash options) {
+                return new GZipReader(self, io, options);
+            }
+
+            [RubyMethod("open", RubyMethodAttributes.PublicSingleton)]
+            public static object Open(BlockParam block, RubyClass/*!*/ self, [DefaultProtocol, NotNull]MutableString/*!*/ path) {
+                var strPath = self.Context.DecodePath(path);
+                var file = new RubyFile(self.Context, strPath, IOMode.ReadOnly);
+                var gzipReader = Create(self, file);
+                return gzipReader.Do(block);
+            }
+
+            [RubyMethod("read")]
+            public static MutableString Read(GZipReader/*!*/ self, [DefaultProtocol, Optional]int? bytes) {
+                if (bytes.HasValue && bytes.Value < 0) {
+                    throw RubyExceptions.CreateArgumentError("negative length -1 given");
+                }
+
+                var stream = self.GetStream();
+                MutableString result = MutableString.CreateBinary(self._encoding ?? RubyEncoding.Binary);
+                if (bytes.HasValue) {
+                    int bytesRead = result.Append(stream, bytes.Value);
+                    if (bytesRead == 0 && bytes.Value != 0) {
+                        return null;
+                    }
+                } else {
+                    result.Append(stream);
+                }
+
+                return result;
+            }
+        }
+
+        #endregion
+
+        #region GzipWriter class
+
+        [RubyClass("GzipWriter", BuildConfig = "!SILVERLIGHT && !WIN8 && !WP75")]
+        // TODO: [Includes(typeof(PrintOps), Copy = true)]
+        public class GzipWriter : GZipFile {
             private GzipWriter(RubyClass/*!*/ cls, object io)
-                : base(cls, io, CompressionMode.Compress) {
-            }
-
-            [RubyConstructor]
-            public static GzipWriter/*!*/ Create(
-                RubyClass/*!*/ self,
-                object io,
-                [Optional, DefaultParameterValue(0)]int level,
-                [Optional, DefaultParameterValue(DEFAULT_STRATEGY)]int strategy) {
-
-                // TODO: level is settable in .NET 4.5:
-                return new GzipWriter(self, io);
-            }
-
-            [RubyMethod("open", RubyMethodAttributes.PublicSingleton)]
-            public static object Open(BlockParam block, RubyClass/*!*/ self,
-                [DefaultProtocol, NotNull]MutableString/*!*/ path,
-                [DefaultParameterValue(0)]int level,
-                [DefaultParameterValue(DEFAULT_STRATEGY)]int strategy) {
-
-                var strPath = self.Context.DecodePath(path);
-                var file = new RubyFile(self.Context, strPath, IOMode.WriteOnly | IOMode.Truncate | IOMode.CreateIfNotExists);
-                var gzipWriter = Create(self, file, level, strategy);
-                return gzipWriter.Do(block);
-            }
-
-            [RubyMethod("flush")]
-            public static GzipWriter/*!*/ Flush(GzipWriter/*!*/ self, [DefaultParameterValue(SYNC_FLUSH)]int flush) {
-                return self;
-            }
-
-            [RubyMethod("write")]
-            public static int Write(ConversionStorage<MutableString>/*!*/ tosConversion, GzipWriter/*!*/ self, object obj) {
-                return Write(self, Protocols.ConvertToString(tosConversion, obj));
-            }
-
-            [RubyMethod("write")]
-            public static int Write(GzipWriter/*!*/ self, [NotNull]MutableString/*!*/ val) {
-                var stream = self.GetStream();
-
-                // TODO: this can be optimized (add MutableString.WriteTo(Stream))
-                var buffer = val.ToByteArray();
-                stream.Write(buffer, 0, buffer.Length);
-                return buffer.Length;
-            } 
-
-            // printops:
-
-            [RubyMethod("<<")]
-            public static GzipWriter/*!*/ Output(ConversionStorage<MutableString>/*!*/ tosConversion, GzipWriter/*!*/ self, object value) {
-                Write(tosConversion, self, value);
-                return self;
-            }
-        }
-  
-        #endregion
-#endif
-        #region Exceptions
-
-        private static Exception/*!*/ MakeError(int result, string message) {
-            switch ((zlib.ZLibResultCode)result) {
-                case zlib.ZLibResultCode.Z_NEED_DICT:
-                    return new NeedDict();
-
-                case zlib.ZLibResultCode.Z_MEM_ERROR:
-                    return new MemError(message);
-
-                case zlib.ZLibResultCode.Z_DATA_ERROR:
-                    return new DataError(message);
-
-                case zlib.ZLibResultCode.Z_BUF_ERROR:
-                    return new BufError();
-
-                case zlib.ZLibResultCode.Z_STREAM_ERROR:
-                default:
-                    return new StreamError(message);
-            }
-        }
-
-        [RubyException("Error"), Serializable]
-        public class Error : SystemException {
-            public Error() : this(null, null) { }
-            public Error(string message) : this(message, null) { }
-            public Error(string message, Exception inner) : base(message ?? "Error", inner) { }
-
-#if FEATURE_SERIALIZATION
-            protected Error(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
-                : base(info, context) { }
-#endif
-        }
-
-        [RubyException("DataError"), Serializable]
-        public class DataError : Error {
-            public DataError() : this(null, null) { }
-            public DataError(string message) : this(message, null) { }
-            public DataError(string message, Exception inner) : base(message ?? "DataError", inner) { }
-
-#if FEATURE_SERIALIZATION
-            protected DataError(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
-                : base(info, context) { }
-#endif
-        }
-
-        [RubyException("BufError"), Serializable]
-        public class BufError : Error {
-            public BufError() : this(null, null) { }
-            public BufError(string message) : this(message, null) { }
-            public BufError(string message, Exception inner) : base(message ?? "buffer error", inner) { }
-
-#if FEATURE_SERIALIZATION
-            protected BufError(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
-                : base(info, context) { }
-#endif
-        }
-
-        [RubyException("MemError"), Serializable]
-        public class MemError : Error {
-            public MemError() : this(null, null) { }
-            public MemError(string message) : this(message, null) { }
-            public MemError(string message, Exception inner) : base(message ?? "MemError", inner) { }
-
-#if FEATURE_SERIALIZATION
-            protected MemError(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
-                : base(info, context) { }
-#endif
-        }
-
-        [RubyException("NeedDict"), Serializable]
-        public class NeedDict : Error {
-            public NeedDict() : this(null, null) { }
-            public NeedDict(string message) : this(message, null) { }
-            public NeedDict(string message, Exception inner) : base(message ?? "need dictionary", inner) { }
-
-#if FEATURE_SERIALIZATION
-            protected NeedDict(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
-                : base(info, context) { }
-#endif
-        }
-
-        [RubyException("StreamError"), Serializable]
-        public class StreamError : Error {
-            public StreamError() : this(null, null) { }
-            public StreamError(string message) : this(message, null) { }
-            public StreamError(string message, Exception inner) : base(message ?? "StreamError", inner) { }
-
-#if FEATURE_SERIALIZATION
-            protected StreamError(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
-                : base(info, context) { }
-#endif
-        }
-
-        #endregion
-    }
-}
+                : base(cls, io, CompressionMode.Compress) {
+            }
+
+            [RubyConstructor]
+            public static GzipWriter/*!*/ Create(
+                RubyClass/*!*/ self,
+                object io,
+                [Optional, DefaultParameterValue(0)]int level,
+                [Optional, DefaultParameterValue(DEFAULT_STRATEGY)]int strategy) {
+
+                // TODO: level is settable in .NET 4.5:
+                return new GzipWriter(self, io);
+            }
+
+            [RubyMethod("open", RubyMethodAttributes.PublicSingleton)]
+            public static object Open(BlockParam block, RubyClass/*!*/ self,
+                [DefaultProtocol, NotNull]MutableString/*!*/ path,
+                [DefaultParameterValue(0)]int level,
+                [DefaultParameterValue(DEFAULT_STRATEGY)]int strategy) {
+
+                var strPath = self.Context.DecodePath(path);
+                var file = new RubyFile(self.Context, strPath, IOMode.WriteOnly | IOMode.Truncate | IOMode.CreateIfNotExists);
+                var gzipWriter = Create(self, file, level, strategy);
+                return gzipWriter.Do(block);
+            }
+
+            [RubyMethod("flush")]
+            public static GzipWriter/*!*/ Flush(GzipWriter/*!*/ self, [DefaultParameterValue(SYNC_FLUSH)]int flush) {
+                return self;
+            }
+
+            [RubyMethod("write")]
+            public static int Write(ConversionStorage<MutableString>/*!*/ tosConversion, GzipWriter/*!*/ self, object obj) {
+                return Write(self, Protocols.ConvertToString(tosConversion, obj));
+            }
+
+            [RubyMethod("write")]
+            public static int Write(GzipWriter/*!*/ self, [NotNull]MutableString/*!*/ val) {
+                var stream = self.GetStream();
+
+                // TODO: this can be optimized (add MutableString.WriteTo(Stream))
+                var buffer = val.ToByteArray();
+                stream.Write(buffer, 0, buffer.Length);
+                return buffer.Length;
+            }
+
+            // printops:
+
+            [RubyMethod("<<")]
+            public static GzipWriter/*!*/ Output(ConversionStorage<MutableString>/*!*/ tosConversion, GzipWriter/*!*/ self, object value) {
+                Write(tosConversion, self, value);
+                return self;
+            }
+        }
+
+        #endregion
+#endif
+        #region Exceptions
+
+        private static Exception/*!*/ MakeError(int result, string message) {
+            switch ((zlib.ZLibResultCode)result) {
+                case zlib.ZLibResultCode.Z_NEED_DICT:
+                    return new NeedDict();
+
+                case zlib.ZLibResultCode.Z_MEM_ERROR:
+                    return new MemError(message);
+
+                case zlib.ZLibResultCode.Z_DATA_ERROR:
+                    return new DataError(message);
+
+                case zlib.ZLibResultCode.Z_BUF_ERROR:
+                    return new BufError();
+
+                case zlib.ZLibResultCode.Z_STREAM_ERROR:
+                default:
+                    return new StreamError(message);
+            }
+        }
+
+        [RubyException("Error"), Serializable]
+        public class Error : SystemException {
+            public Error() : this(null, null) { }
+            public Error(string message) : this(message, null) { }
+            public Error(string message, Exception inner) : base(message ?? "Error", inner) { }
+
+#if FEATURE_SERIALIZATION
+            protected Error(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
+                : base(info, context) { }
+#endif
+        }
+
+        [RubyException("DataError"), Serializable]
+        public class DataError : Error {
+            public DataError() : this(null, null) { }
+            public DataError(string message) : this(message, null) { }
+            public DataError(string message, Exception inner) : base(message ?? "DataError", inner) { }
+
+#if FEATURE_SERIALIZATION
+            protected DataError(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
+                : base(info, context) { }
+#endif
+        }
+
+        [RubyException("BufError"), Serializable]
+        public class BufError : Error {
+            public BufError() : this(null, null) { }
+            public BufError(string message) : this(message, null) { }
+            public BufError(string message, Exception inner) : base(message ?? "buffer error", inner) { }
+
+#if FEATURE_SERIALIZATION
+            protected BufError(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
+                : base(info, context) { }
+#endif
+        }
+
+        [RubyException("MemError"), Serializable]
+        public class MemError : Error {
+            public MemError() : this(null, null) { }
+            public MemError(string message) : this(message, null) { }
+            public MemError(string message, Exception inner) : base(message ?? "MemError", inner) { }
+
+#if FEATURE_SERIALIZATION
+            protected MemError(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
+                : base(info, context) { }
+#endif
+        }
+
+        [RubyException("NeedDict"), Serializable]
+        public class NeedDict : Error {
+            public NeedDict() : this(null, null) { }
+            public NeedDict(string message) : this(message, null) { }
+            public NeedDict(string message, Exception inner) : base(message ?? "need dictionary", inner) { }
+
+#if FEATURE_SERIALIZATION
+            protected NeedDict(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
+                : base(info, context) { }
+#endif
+        }
+
+        [RubyException("StreamError"), Serializable]
+        public class StreamError : Error {
+            public StreamError() : this(null, null) { }
+            public StreamError(string message) : this(message, null) { }
+            public StreamError(string message, Exception inner) : base(message ?? "StreamError", inner) { }
+
+#if FEATURE_SERIALIZATION
+            protected StreamError(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
+                : base(info, context) { }
+#endif
+        }
+
+        #endregion
+    }
+}
