zlib.cs :  » Script » IronRuby » IronRuby » StandardLibrary » Zlib » C# / CSharp Open Source

Home
C# / CSharp Open Source
1.2.6.4 mono .net core
2.2.6.4 mono core
3.Aspect Oriented Frameworks
4.Bloggers
5.Build Systems
6.Business Application
7.Charting Reporting Tools
8.Chat Servers
9.Code Coverage Tools
10.Content Management Systems CMS
11.CRM ERP
12.Database
13.Development
14.Email
15.Forum
16.Game
17.GIS
18.GUI
19.IDEs
20.Installers Generators
21.Inversion of Control Dependency Injection
22.Issue Tracking
23.Logging Tools
24.Message
25.Mobile
26.Network Clients
27.Network Servers
28.Office
29.PDF
30.Persistence Frameworks
31.Portals
32.Profilers
33.Project Management
34.RSS RDF
35.Rule Engines
36.Script
37.Search Engines
38.Sound Audio
39.Source Control
40.SQL Clients
41.Template Engines
42.Testing
43.UML
44.Web Frameworks
45.Web Service
46.Web Testing
47.Wiki Engines
48.Windows Presentation Foundation
49.Workflows
50.XML Parsers
C# / C Sharp
C# / C Sharp by API
C# / CSharp Tutorial
C# / CSharp Open Source » Script » IronRuby 
IronRuby » IronRuby » StandardLibrary » Zlib » zlib.cs
/* ****************************************************************************
 *
 * Copyright (c) Microsoft Corporation. 
 *
 * This source code is subject to terms and conditions of the Microsoft Public License. A 
 * copy of the license can be found in the License.html file at the root of this distribution. If 
 * you cannot locate the  Microsoft Public License, please send an email to 
 * ironruby@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
 * by the terms of the Microsoft Public License.
 *
 * You must not remove this notice, or any other, from this software.
 *
 *
 * ***************************************************************************/

#if !SILVERLIGHT
using System.IO.Compression;
#endif

using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.CompilerServices;
using IronRuby.Builtins;
using IronRuby.Runtime;
using Microsoft.Scripting.Runtime;
using Microsoft.Scripting.Generation;
using System.Diagnostics;
using System.Text;
using System.Runtime.InteropServices;

namespace IronRuby.StandardLibrary.Zlib{

    [RubyModule("Zlib")]
    public static class Zlib {

        #region Constants

        [RubyConstant("NO_FLUSH")]
        public const int NO_FLUSH = 0;

        [RubyConstant("SYNC_FLUSH")]
        public const int SYNC_FLUSH = 2;

        [RubyConstant("FULL_FLUSH")]
        public const int FULL_FLUSH = 3;

        [RubyConstant("FINISH")]
        public const int FINISH = 4;

        [RubyConstant("ZLIB_VERSION")]
        public static string ZLIB_VERSION = "1.2.3";

        [RubyConstant("VERSION")]
        public static string VERSION = "0.6.0";

        [RubyConstant("MAXBITS")]
        public const int MAXBITS = 15;

        [RubyConstant("MAXLCODES")]
        public const int MAXLCODES = 286;

        [RubyConstant("MAXDCODES")]
        public const int MAXDCODES = 30;

        [RubyConstant("MAXCODES")]
        public const int MAXCODES = (MAXLCODES + MAXDCODES);

        [RubyConstant("FIXLCODES")]
        public const int FIXLCODES = 288;

        [RubyConstant("MAX_WBITS")]
        public const int MAX_WBITS = 15;

        [RubyConstant("Z_DEFLATED")]
        public const int Z_DEFLATED = 8;

        [RubyConstant("BINARY")]
        public const int BINARY = 0;

        [RubyConstant("ASCII")]
        public const int ASCII = 1;

        [RubyConstant("UNKNOWN")]
        public const int UNKNOWN = 2;

        [RubyConstant("NO_COMPRESSION")]
        public const int NO_COMPRESSION = 0;

        [RubyConstant("BEST_SPEED")]
        public const int BEST_SPEED = 1;

        [RubyConstant("BEST_COMPRESSION")]
        public const int BEST_COMPRESSION = 9;

        [RubyConstant("DEFAULT_COMPRESSION")]
        public const int DEFAULT_COMPRESSION = -1;

        [RubyConstant("FILTERED")]
        public const int FILTERED = 1;

        [RubyConstant("HUFFMAN_ONLY")]
        public const int HUFFMAN_ONLY = 2;

        [RubyConstant("DEFAULT_STRATEGY")]
        public const int DEFAULT_STRATEGY = 0;
     
        #endregion

#if !SILVERLIGHT
        [RubyMethod("crc32", RubyMethodAttributes.PublicSingleton, BuildConfig = "!SILVERLIGHT")]
        public static int GetCrc(RubyModule/*!*/ self) {
            return 0;
        }

        [RubyMethod("crc32", RubyMethodAttributes.PublicSingleton, BuildConfig = "!SILVERLIGHT")]
        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 = Deflate.ZDeflateStream.UpdateCrc(unchecked((uint)initialCrc), bytes, 0, bytes.Length);
            return Protocols.Normalize(result);
        }
#endif

        #region ZStream class

        [RubyClass("ZStream")]
        public class ZStream {
            protected readonly List<byte>/*!*/ _inputBuffer;
            protected readonly List<byte>/*!*/ _outputBuffer;
            protected int _outPos = -1;
            protected int _inPos = -1;
            protected byte _bitBucket = 0;
            protected byte _bitCount = 0;
            protected bool _closed = false;

            public ZStream() {
                _outPos = -1;
                _inPos = -1;
                _bitBucket = 0;
                _bitCount = 0;
                _inputBuffer = new List<byte>();
                _outputBuffer = new List<byte>();
            }

            #region instance methods
            public bool Close() {
                _closed = true;
                return _closed;
            }
            #endregion

            [RubyMethod("adler")]
            public static int Adler(ZStream/*!*/ self) {
                throw new NotImplementedError();
            }

            [RubyMethod("avail_in")]
            public static int AvailIn(ZStream/*!*/ self) {
                return self._inputBuffer.Count - self._inPos;
            }

            [RubyMethod("avail_out")]
            public static int GetAvailOut(ZStream/*!*/ self) {
                return self._outputBuffer.Count - self._outPos;
            }

            [RubyMethod("avail_out=")]
            public static int SetAvailOut(ZStream/*!*/ self, int size) {
                self._outputBuffer.Capacity = size;
                return self._outputBuffer.Count;
            }

            [RubyMethod("finish")]
            [RubyMethod("close")]
            public static bool Close(ZStream/*!*/ self) {
                return self.Close();
            }

            [RubyMethod("stream_end?")]
            [RubyMethod("finished?")]
            [RubyMethod("closed?")]
            public static bool IsClosed(ZStream/*!*/ self) {
                return self._closed;
            }

            [RubyMethod("data_type")]
            public static void DataType(ZStream/*!*/ self) {
                throw new NotImplementedException();
            }

            [RubyMethod("flush_next_in")]
            public static List<byte> FlushNextIn(ZStream/*!*/ self) {
                self._inPos = self._inputBuffer.Count;
                return self._inputBuffer;
            }

            [RubyMethod("flush_next_out")]
            public static List<byte> FlushNextOut(ZStream/*!*/ self) {
                self._outPos = self._outputBuffer.Count;
                return self._outputBuffer;
            }

            [RubyMethod("reset")]
            public static void Reset(ZStream/*!*/ self) {
                self._outPos = -1;
                self._inPos = -1;
                self._inputBuffer.Clear();
                self._outputBuffer.Clear();
            }

            [RubyMethod("total_in")]
            public static int TotalIn(ZStream/*!*/ self) {
                return self._inputBuffer.Count;
            }

            [RubyMethod("total_out")]
            public static int TotalOut(ZStream/*!*/ self) {
                return self._outputBuffer.Count;
            }

            protected int GetBits(int need) {
                int val = _bitBucket;
                while (_bitCount < need) {
                    val |= (int)(_inputBuffer[++_inPos] << _bitCount);
                    _bitCount += 8;
                }

                _bitBucket = (byte)(val >> need);
                _bitCount -= (byte)need;
                return (val & ((1 << need) - 1));
            }
        }

        #endregion

        #region Inflate class

        [RubyClass("Inflate")]
        public class Inflate : ZStream {
            private int _wBits;
            private bool _rawDeflate;
            private HuffmanTree _fixedLengthCodes;
            private HuffmanTree _fixedDistanceCodes;
            private HuffmanTree _dynamicLengthCodes;
            private HuffmanTree _dynamicDistanceCodes;

            public Inflate() 
                : this(MAX_WBITS) {
            }

            public Inflate(int windowBits) {
                _wBits = windowBits;
                if (_wBits < 0) {
                    _rawDeflate = true;
                    _wBits *= -1;
                }
            }

            #region Private Implementation Details

            private sealed class HuffmanTree {
                internal readonly List<int>/*!*/ Count;
                internal readonly List<int>/*!*/ Symbol;

                internal HuffmanTree() {
                    Count = new List<int>();
                    Symbol = new List<int>();
                }
            }

            private void DynamicCodes() {
                byte[] order = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
                int nlen = (int)GetBits(5) + 257;
                int ndist = (int)GetBits(5) + 1;
                int ncode = (int)GetBits(4) + 4;

                List<int> lengths = new List<int>();

                _dynamicLengthCodes = new HuffmanTree();
                _dynamicDistanceCodes = new HuffmanTree();

                if (nlen > MAXLCODES || ndist > MAXDCODES) {
                    throw new DataError("too many length or distance codes");
                }

                int idx = 0;

                while (idx < ncode) {
                    SetOrExpand(lengths, order[idx], GetBits(3));
                    idx++;
                }

                while (idx < 19) {
                    SetOrExpand(lengths, order[idx], 0);
                    idx++;
                }

                int err = ConstructTree(_dynamicLengthCodes, lengths, 18);
                if (err != 0) {
                    throw new DataError("code lengths codes incomplete");
                }

                idx = 0;

                while (idx < (nlen + ndist)) {
                    int symbol = Decode(_dynamicLengthCodes);
                    if (symbol < 16) {
                        SetOrExpand(lengths, idx, symbol);
                        idx++;
                    } else {
                        int len = 0;
                        if (symbol == 16) {
                            if (idx == 0) {
                                throw new DataError("repeat lengths with no first length");
                            }
                            len = lengths[idx - 1];
                            symbol = 3 + (int)GetBits(2);
                        } else if (symbol == 17) {
                            symbol = 3 + (int)GetBits(3);
                        } else if (symbol == 18) {
                            symbol = 11 + (int)GetBits(7);
                        } else {
                            throw new DataError("invalid repeat length code");
                        }

                        if ((idx + symbol) > (nlen + ndist)) {
                            throw new DataError("repeat more than specified lengths");
                        }

                        while (symbol != 0) {
                            SetOrExpand(lengths, idx, len);
                            idx++;
                            symbol--;
                        }
                    }
                }

                err = ConstructTree(_dynamicLengthCodes, lengths, nlen - 1);
                if (err < 0 || (err > 0 && (nlen - _dynamicLengthCodes.Count[0] != 1))) {
                    throw new DataError("invalid literal/length code lengths");
                }

                lengths.RemoveRange(0, nlen);

                err = ConstructTree(_dynamicDistanceCodes, lengths, ndist - 1);
                if (err < 0 || (err > 0 && (ndist - _dynamicDistanceCodes.Count[0] != 1))) {
                    throw new DataError("invalid distance code lengths");
                }

                Codes(_dynamicLengthCodes, _dynamicDistanceCodes);
            }

            private void NoCompression() {
                _bitBucket = 0;
                _bitCount = 0;

                if (_inPos + 4 > _inputBuffer.Count) {
                    throw new DataError("not enough input to read length code");
                }

                int length = (int)(_inputBuffer[++_inPos] | (_inputBuffer[++_inPos] << 8));
                int lengthComplement = (int)(_inputBuffer[++_inPos] | (_inputBuffer[++_inPos] << 8));
                if (unchecked((ushort)length) != unchecked((ushort)(~lengthComplement))) {
                    throw new DataError("invalid stored block lengths");
                }

                if (_inPos + length > _inputBuffer.Count) {
                    throw new DataError("ran out of input");
                }

                _outputBuffer.AddRange(_inputBuffer.GetRange(_inPos + 1, length));
                _inPos += length;
                _outPos += length;
            }

            private void FixedCodes() {
                if (_fixedLengthCodes == null && _fixedDistanceCodes == null) {
                    GenerateHuffmans();
                }
                Codes(_fixedLengthCodes, _fixedDistanceCodes);
            }

            private void GenerateHuffmans() {
                List<int> lengths = new List<int>(300);
                int x = 0;
                for (; x < 144; x++) {
                    lengths.Add(8);
                }
                for (; x < 256; x++) {
                    lengths.Add(9);
                }
                for (; x < 280; x++) {
                    lengths.Add(7);
                }
                for (; x < 288; x++) {
                    lengths.Add(8);
                }
                _fixedLengthCodes = new HuffmanTree();
                ConstructTree(_fixedLengthCodes, lengths, 287);

                lengths.Clear();

                for (int y = 0; y < 30; y++) {
                    lengths.Add(5);
                }

                _fixedDistanceCodes = new HuffmanTree();
                ConstructTree(_fixedDistanceCodes, lengths, 29);
            }

            private int ConstructTree(HuffmanTree/*!*/ tree, List<int>/*!*/ lengths, int symbols) {
                List<int> offs = new List<int>();

                for (int x = 0; x <= MAXBITS; x++) {
                    SetOrExpand(tree.Count, x, 0);
                }

                for (int y = 0; y <= symbols; y++) {
                    (tree.Count[lengths[y]])++;
                }

                if (tree.Count[0] == symbols) {
                    return 0;
                }

                int left = 1;
                for (int y = 1; y <= MAXBITS; y++) {
                    left <<= 1;
                    left -= tree.Count[y];
                    if (left < 0) {
                        return left;
                    }
                }

                offs.Add(0);
                offs.Add(0);

                for (int len = 1; len <= MAXBITS - 1; len++) {
                    offs.Add(0);
                    offs[len + 1] = offs[len] + tree.Count[len];
                }

                for (int symbol = 0; symbol <= symbols; symbol++) {
                    if (lengths[symbol] != 0) {
                        SetOrExpand(tree.Symbol, offs[lengths[symbol]], symbol);
                        offs[lengths[symbol]]++;
                    }
                }

                return left;
            }

            private void SetOrExpand<T>(List<T>/*!*/ list, int index, T item) {
                int minCount = index + 1;
                int expand = minCount - list.Count;
                while (expand > 0) {
                    list.Add(default(T));
                    expand--;
                }
                list[index] = item;
            }

            private int Codes(HuffmanTree/*!*/ lengthCodes, HuffmanTree/*!*/ distanceCodes) {
                int[] lens = { 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258 };
                int[] lext = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 };
                int[] dists = { 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577 };
                int[] dext = { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13 };

                int symbol = 0;
                while (symbol != 256) {
                    symbol = Decode(lengthCodes);
                    if (symbol < 0) {
                        return symbol;
                    }
                    if (symbol < 256) {
                        SetOrExpand(_outputBuffer, ++_outPos, (byte)symbol);
                    }
                    if (symbol > 256) {
                        symbol -= 257;
                        if (symbol >= 29) {
                            throw new DataError("invalid literal/length or distance code in fixed or dynamic block");
                        }
                        int len = lens[symbol] + GetBits((byte)lext[symbol]);
                        symbol = Decode(distanceCodes);
                        if (symbol < 0) {
                            return symbol;
                        }
                        int dist = dists[symbol] + GetBits((byte)dext[symbol]);
                        if (dist > _outputBuffer.Count) {
                            throw new DataError("distance is too far back in fixed or dynamic block");
                        }
                        while (len > 0) {
                            SetOrExpand(_outputBuffer, ++_outPos, _outputBuffer[_outPos - dist]);
                            len--;
                        }
                    }
                }

                return 0;
            }

            private int Decode(HuffmanTree/*!*/ tree) {
                int code = 0;
                int first = 0;
                int index = 0;
                for (int len = 1; len <= 15; len++) {
                    code |= GetBits(1);
                    int count = tree.Count[len];
                    if (code < (first + count)) {
                        return tree.Symbol[index + (code - first)];
                    }
                    index += count;
                    first += count;
                    first <<= 1;
                    code <<= 1;
                }

                return -9;
            }

            #endregion

            [RubyMethod("inflate")]
            public static MutableString/*!*/ InflateString(Inflate/*!*/ self, [DefaultProtocol, NotNull]MutableString/*!*/ zstring) {
                if (zstring.IsEmpty) {
                    throw new BufError("buffer error");
                }
                
                // TODO: hack
                if (zstring.GetByteCount() == 6 && zstring.GetByte(0) == (byte)'X' && zstring.GetByte(1) == 0x85 && 
                    zstring.GetByte(2) == 0 && zstring.GetByte(3) == 0 && zstring.GetByte(4) == 0 && zstring.GetByte(5) == 0) {
                    return MutableString.CreateEmpty();
                }

                self._inputBuffer.AddRange(zstring.ConvertToBytes());

                if (self._rawDeflate == false) {
                    byte compression_method_and_flags = self._inputBuffer[++(self._inPos)];
                    byte flags = self._inputBuffer[++(self._inPos)];
                    if (((compression_method_and_flags << (byte)0x08) + flags) % (byte)31 != 0) {
                        throw new DataError("incorrect header check");
                    }

                    byte compression_method = (byte)(compression_method_and_flags & (byte)0x0F);
                    if (compression_method != Z_DEFLATED) {
                        throw new DataError("unknown compression method");
                    }

                    byte compression_info = (byte)(compression_method_and_flags >> (byte)0x04);
                    if ((compression_info + 8) > self._wBits) {
                        throw new DataError("invalid window size");
                    }

                    bool preset_dictionary_flag = ((flags & 0x20) >> 0x05 == 1);
                    // TODO: ??? 
                    // byte compression_level = (byte)((flags & 0xC0) >> (byte)0x06);

                    //TODO: Add Preset Dictionary Support
                    if (preset_dictionary_flag) {
                        self._inPos += 4;
                    }
                }

                bool last_block = false;

                while (!last_block) {
                    last_block = (self.GetBits(1) == 1);
                    byte block_type = (byte)self.GetBits(2);
                    switch (block_type) {
                        case 0:
                            self.NoCompression();
                            break;
                        case 1:
                            self.FixedCodes();
                            break;
                        case 2:
                            self.DynamicCodes();
                            break;
                        case 3:
                            throw new DataError("invalid block type");
                    }
                }

                return Inflate.Close(self);
            }

            [RubyMethod("inflate", RubyMethodAttributes.PublicSingleton)]
            public static MutableString/*!*/ InflateString(RubyClass/*!*/ self, [DefaultProtocol, NotNull]MutableString/*!*/ zstring) {
                return InflateString(new Inflate(), zstring);
            }

            [RubyMethod("close")]
            public static MutableString/*!*/ Close(Inflate/*!*/ self) {
                return MutableString.CreateBinary(self._outputBuffer, RubyEncoding.Binary);
            }
        }

        #endregion

        #region GzipFile class

        [RubyClass("GzipFile")]
        public class GZipFile {
            protected IOWrapper/*!*/ _ioWrapper;
            protected List<byte>/*!*/ _inputBuffer;
            protected List<byte>/*!*/ _outputBuffer;
            protected int _outPos;
            protected int _inPos;
            protected bool _isClosed;
            protected MutableString _originalName;
            protected MutableString _comment;

            public GZipFile(IOWrapper/*!*/ ioWrapper) {
                Debug.Assert(ioWrapper != null);
                _ioWrapper = ioWrapper;
                _inputBuffer = new List<byte>();
                _outputBuffer = new List<byte>();
                _outPos = -1;
                _inPos = -1;
            }

            [RubyClass("Error")]
            public class Error : RuntimeError {
                public Error(string message)
                    : base(message) {
                }
            }

            // TODO: missing NoFooter, LengthError, CRCError constants

            [RubyMethod("wrap", RubyMethodAttributes.PublicSingleton)]
            public static object Wrap(BinaryOpStorage/*!*/ newStorage, UnaryOpStorage/*!*/ closedStorage, UnaryOpStorage/*!*/ closeStorage, 
                BlockParam block, RubyClass/*!*/ self, object io) {

                var newSite = newStorage.GetCallSite("new");
                GZipFile gzipFile = (GZipFile)newSite.Target(newSite, self, io);

                if (block == null) {
                    return gzipFile;
                }

                try {
                    object blockResult;
                    block.Yield(gzipFile, out blockResult);
                    return blockResult;
                } finally {
                    CloseFile(closedStorage, closeStorage, self, gzipFile);
                }
            }

            private static void CloseFile(UnaryOpStorage/*!*/ closedStorage, UnaryOpStorage/*!*/ closeStorage, RubyClass self, GZipFile gzipFile) {
                var closedSite = closedStorage.GetCallSite("closed?");
                bool isClosed = Protocols.IsTrue(closedSite.Target(closedSite, gzipFile));

                if (!isClosed) {
                    var closeSite = closeStorage.GetCallSite("close");
                    closeSite.Target(closeSite, gzipFile);
                }
            }

            internal static void Close(UnaryOpStorage/*!*/ closeStorage, GZipFile/*!*/ self, bool closeIO) {
                if (self._isClosed) {
                    throw new Error("closed gzip stream");
                }

                if (closeIO && self._ioWrapper.CanBeClosed) {
                    var site = closeStorage.GetCallSite("close");
                    site.Target(site, self._ioWrapper.UnderlyingObject);
                }

                self._isClosed = true;
            }


            [RubyMethod("closed?")]
            public static bool IsClosed(GZipFile/*!*/ self) {
                return self._isClosed;
            }

            [RubyMethod("comment")]
            public static MutableString Comment(GZipFile/*!*/ self) {
                if (self._isClosed) {
                    throw new Error("closed gzip stream");
                }

                return self._comment;
            }

            // crc() 
            // level() 
            // mtime() 

            [RubyMethod("orig_name")]
            [RubyMethod("original_name")]
            public static MutableString OriginalName(GZipFile/*!*/ self) {
                if (self._isClosed) {
                    throw new Error("closed gzip stream");
                }

                return self._originalName;
            }

            // os_code() 
            // sync() 
            // sync = flag
            // to_io
        }

        #endregion

        #region GzipReader class

        /* [RubyClass("GzipReader"), Includes(typeof(Enumerable))] */
        [RubyClass("GzipReader")]
        public class GZipReader : GZipFile {

            protected MutableString _xtraField;
            protected MutableString/*!*/ _contents;
            protected ushort _headerCrc;

            [RubyMethod("xtra_field")]
            public static MutableString ExtraField(GZipReader/*!*/ self) {
                return self._xtraField;
            }

            [RubyConstant("OSES")]
            public static string[] OSES = {
                "FAT filesystem", 
          "Amiga", 
          "VMS (or OpenVMS)", 
          "Unix", 
          "VM/CMS", 
          "Atari TOS", 
          "HPFS fileystem (OS/2, NT)", 
          "Macintosh", 
          "Z-System",
          "CP/M",
          "TOPS-20",
          "NTFS filesystem (NT)",
          "QDOS",
          "Acorn RISCOS",
          "unknown"
            };

            private bool IsBitSet(byte b, byte bit) {
                return ((b & (1 << bit)) == (1 << bit));
            }

            [RubyConstructor]
            public static GZipReader/*!*/ Create(RespondToStorage/*!*/ respondToStorage, RubyClass/*!*/ self, object io) {
                IOWrapper stream = null;
                if (io != null) {
                    stream = RubyIOOps.CreateIOWrapper(respondToStorage, io, FileAccess.Read);
                }
                if (stream == null || !stream.CanRead) {
                    throw RubyExceptions.CreateMethodMissing(self.Context, io, "read");
                }

                using (BinaryReader reader = new BinaryReader(stream)) {
                    return new GZipReader(stream, reader);
                }
            }

            private static ushort ReadUInt16LE(BinaryReader/*!*/ reader) {
                return (ushort)(
                    (ushort)(reader.ReadByte()) |
                    (((ushort)(reader.ReadByte())) << 8)
                    );
            }

            private static uint ReadUInt32LE(BinaryReader/*!*/ reader) {
                return (uint)(
                    (uint)(reader.ReadByte()) |
                    (((uint)(reader.ReadByte())) << 8) |
                    (((uint)(reader.ReadByte())) << 16) |
                    (((uint)(reader.ReadByte())) << 24)
                    );
            }

            private static MutableString/*!*/ ReadStringZ(BinaryReader/*!*/ reader) {
                List<byte> result = new List<byte>();
                byte c;
                while ((c = reader.ReadByte()) != 0) {
                    result.Add(c);
                }
                return MutableString.CreateBinary(result, RubyEncoding.Binary);
            }

            private static MutableString/*!*/ ReadToEnd(BinaryReader/*!*/ reader) {
                List<byte> result = new List<byte>();
                try {
                    while (true) {
                        result.Add(reader.ReadByte());
                    }
                } catch (EndOfStreamException) {
                }
                return MutableString.CreateBinary(result, RubyEncoding.Binary);
            }

            private GZipReader(IOWrapper/*!*/ ioWrapper, BinaryReader/*!*/ reader)
                : base(ioWrapper) {

                // TODO: should all of this code be moved to open()?
                if (ReadUInt16LE(reader) != 0x8b1f) {
                    throw new Error("not in gzip format");
                }
                if (reader.ReadByte() != 0x08) {
                    throw new Error("unknown compression method");
                }

#pragma warning disable 168,219 // TODO: mcs: unused locals
                byte flg = reader.ReadByte();
                bool ftext = IsBitSet(flg, 0);
                bool fhcrc = IsBitSet(flg, 1);
                bool fextra = IsBitSet(flg, 2);
                bool fname = IsBitSet(flg, 3);
                bool fcomment = IsBitSet(flg, 4);

                uint secondsSince1970 = ReadUInt32LE(reader);
                DateTime mtime = RubyTime.Epoch.AddSeconds((double)secondsSince1970);
                byte xfl = reader.ReadByte();
                string os = GZipReader.OSES[reader.ReadByte()];
                if (fextra) {
                    int xlen = ReadUInt16LE(reader);
                    _xtraField = MutableString.CreateBinary(reader.ReadBytes(xlen));
                }
#pragma warning restore 168,219

                if (fname) {
                    _originalName = ReadStringZ(reader);
                } else {
                    _originalName = MutableString.CreateBinary();
                }

                if (fcomment) {
                    _comment = ReadStringZ(reader);
                } else {
                    _comment = MutableString.CreateBinary();
                }

                if (fhcrc) {
                    _headerCrc = ReadUInt16LE(reader);
                }

                _contents = ReadToEnd(reader);
            }

            [RubyMethod("read")]
            public static MutableString/*!*/ Read(GZipReader/*!*/ self) {
                Inflate z = new Inflate(-MAX_WBITS);
                return Inflate.InflateString(z, self._contents);
            }

            [RubyMethod("open", RubyMethodAttributes.PrivateInstance)]
            public static GZipReader/*!*/ Open(GZipReader/*!*/ self) {
                // TODO: Open as an private instance method probably doesn't create a new GzipReader, right?
                // it probably returns nothing and is used internally to do all initialization
                return self;
            }

            [RubyMethod("open", RubyMethodAttributes.PublicSingleton)]
            public static GZipReader/*!*/ Open(RespondToStorage/*!*/ respondToStorage, RubyClass/*!*/ self, [DefaultProtocol, NotNull]MutableString/*!*/ path) {
                return Create(respondToStorage, self, new RubyFile(self.Context, path.ConvertToString(), IOMode.ReadOnly));
            }

            [RubyMethod("open", RubyMethodAttributes.PublicSingleton)]
            public static object Open(RespondToStorage/*!*/ respondToStorage, [NotNull]BlockParam/*!*/ block, RubyClass/*!*/ self, [DefaultProtocol, NotNull]MutableString/*!*/ path) {
                GZipReader reader = Open(respondToStorage, self, path);
                object blockResult;
                block.Yield(reader, out blockResult);
                return blockResult;
            }

            // pos() 

            [RubyMethod("close")]
            public static object/*!*/ Close(UnaryOpStorage/*!*/ closeStorage, RubyContext/*!*/ context, GZipReader/*!*/ self) {
                GZipFile.Close(closeStorage, self, true);
                return self._ioWrapper.UnderlyingObject;
            }

            [RubyMethod("finish")]
            public static object/*!*/ Finish(UnaryOpStorage/*!*/ closeStorage, RubyContext/*!*/ context, GZipReader/*!*/ self) {
                GZipFile.Close(closeStorage, self, false);
                return self._ioWrapper.UnderlyingObject;
            }
        }

        #endregion

        #region Exceptions

        [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 !SILVERLIGHT
            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 !SILVERLIGHT
            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 ?? "BufError", inner) { }

#if !SILVERLIGHT
            protected BufError(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 !SILVERLIGHT
            protected StreamError(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
                : base(info, context) { }
#endif
        }

        #endregion

        #region Deflate class
#if !SILVERLIGHT
        [RubyClass("Deflate", BuildConfig="!SILVERLIGHT")]
        public class Deflate : ZStream {
            /// <summary>
            /// Adds a 2 byte header, and a 4 byte adler checksum footer.
            /// </summary>
            internal class ZDeflateStream : DeflateStream {
                private long _size;
                private uint _crc;
                private bool _leaveOpen;
                private Stream _output;

                public ZDeflateStream(Stream output, bool leaveOpen)
                    : base(output, CompressionMode.Compress, true) {
                    _output = output;
                    _leaveOpen = leaveOpen;

                    // System.IO.Compression.DeflateStream uses a window size of 8K and FLEVEL is 2 (default algorithm).
                    byte[] header = { 0x58, 0x85 };
                    _output.Write(header, 0, header.Length);
                }

                public override IAsyncResult BeginWrite(byte[] array, int offset, int count, AsyncCallback asyncCallback, object asyncState) {
                    IAsyncResult result = base.BeginWrite(array, offset, count, asyncCallback, asyncState);
                    _size += count;
                    _crc = UpdateCrc(_crc, array, offset, count);
                    return result;
                }

                public override void Write(byte[] array, int offset, int count) {
                    base.Write(array, offset, count);
                    _size += count;
                    _crc = UpdateCrc(_crc, array, offset, count);
                }

                protected override void Dispose(bool disposing) {
                    base.Dispose(disposing);
                    if (disposing && _output != null) {
                        _output.WriteByte((byte)(_crc & 0xff));
                        _output.WriteByte((byte)((_crc >> 8) & 0xff));
                        _output.WriteByte((byte)((_crc >> 16) & 0xff));
                        _output.WriteByte((byte)((_crc >> 24) & 0xff));
                        if (!_leaveOpen) _output.Close();
                        _output = null;
                    }
                }

                // 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,
                    0xe0d5e91eu, 0x97d2d988u, 0x09b64c2bu, 0x7eb17cbdu, 0xe7b82d07u,
                    0x90bf1d91u, 0x1db71064u, 0x6ab020f2u, 0xf3b97148u, 0x84be41deu,
                    0x1adad47du, 0x6ddde4ebu, 0xf4d4b551u, 0x83d385c7u, 0x136c9856u,
                    0x646ba8c0u, 0xfd62f97au, 0x8a65c9ecu, 0x14015c4fu, 0x63066cd9u,
                    0xfa0f3d63u, 0x8d080df5u, 0x3b6e20c8u, 0x4c69105eu, 0xd56041e4u,
                    0xa2677172u, 0x3c03e4d1u, 0x4b04d447u, 0xd20d85fdu, 0xa50ab56bu,
                    0x35b5a8fau, 0x42b2986cu, 0xdbbbc9d6u, 0xacbcf940u, 0x32d86ce3u,
                    0x45df5c75u, 0xdcd60dcfu, 0xabd13d59u, 0x26d930acu, 0x51de003au,
                    0xc8d75180u, 0xbfd06116u, 0x21b4f4b5u, 0x56b3c423u, 0xcfba9599u,
                    0xb8bda50fu, 0x2802b89eu, 0x5f058808u, 0xc60cd9b2u, 0xb10be924u,
                    0x2f6f7c87u, 0x58684c11u, 0xc1611dabu, 0xb6662d3du, 0x76dc4190u,
                    0x01db7106u, 0x98d220bcu, 0xefd5102au, 0x71b18589u, 0x06b6b51fu,
                    0x9fbfe4a5u, 0xe8b8d433u, 0x7807c9a2u, 0x0f00f934u, 0x9609a88eu,
                    0xe10e9818u, 0x7f6a0dbbu, 0x086d3d2du, 0x91646c97u, 0xe6635c01u,
                    0x6b6b51f4u, 0x1c6c6162u, 0x856530d8u, 0xf262004eu, 0x6c0695edu,
                    0x1b01a57bu, 0x8208f4c1u, 0xf50fc457u, 0x65b0d9c6u, 0x12b7e950u,
                    0x8bbeb8eau, 0xfcb9887cu, 0x62dd1ddfu, 0x15da2d49u, 0x8cd37cf3u,
                    0xfbd44c65u, 0x4db26158u, 0x3ab551ceu, 0xa3bc0074u, 0xd4bb30e2u,
                    0x4adfa541u, 0x3dd895d7u, 0xa4d1c46du, 0xd3d6f4fbu, 0x4369e96au,
                    0x346ed9fcu, 0xad678846u, 0xda60b8d0u, 0x44042d73u, 0x33031de5u,
                    0xaa0a4c5fu, 0xdd0d7cc9u, 0x5005713cu, 0x270241aau, 0xbe0b1010u,
                    0xc90c2086u, 0x5768b525u, 0x206f85b3u, 0xb966d409u, 0xce61e49fu,
                    0x5edef90eu, 0x29d9c998u, 0xb0d09822u, 0xc7d7a8b4u, 0x59b33d17u,
                    0x2eb40d81u, 0xb7bd5c3bu, 0xc0ba6cadu, 0xedb88320u, 0x9abfb3b6u,
                    0x03b6e20cu, 0x74b1d29au, 0xead54739u, 0x9dd277afu, 0x04db2615u,
                    0x73dc1683u, 0xe3630b12u, 0x94643b84u, 0x0d6d6a3eu, 0x7a6a5aa8u,
                    0xe40ecf0bu, 0x9309ff9du, 0x0a00ae27u, 0x7d079eb1u, 0xf00f9344u,
                    0x8708a3d2u, 0x1e01f268u, 0x6906c2feu, 0xf762575du, 0x806567cbu,
                    0x196c3671u, 0x6e6b06e7u, 0xfed41b76u, 0x89d32be0u, 0x10da7a5au,
                    0x67dd4accu, 0xf9b9df6fu, 0x8ebeeff9u, 0x17b7be43u, 0x60b08ed5u,
                    0xd6d6a3e8u, 0xa1d1937eu, 0x38d8c2c4u, 0x4fdff252u, 0xd1bb67f1u,
                    0xa6bc5767u, 0x3fb506ddu, 0x48b2364bu, 0xd80d2bdau, 0xaf0a1b4cu,
                    0x36034af6u, 0x41047a60u, 0xdf60efc3u, 0xa867df55u, 0x316e8eefu,
                    0x4669be79u, 0xcb61b38cu, 0xbc66831au, 0x256fd2a0u, 0x5268e236u,
                    0xcc0c7795u, 0xbb0b4703u, 0x220216b9u, 0x5505262fu, 0xc5ba3bbeu,
                    0xb2bd0b28u, 0x2bb45a92u, 0x5cb36a04u, 0xc2d7ffa7u, 0xb5d0cf31u,
                    0x2cd99e8bu, 0x5bdeae1du, 0x9b64c2b0u, 0xec63f226u, 0x756aa39cu,
                    0x026d930au, 0x9c0906a9u, 0xeb0e363fu, 0x72076785u, 0x05005713u,
                    0x95bf4a82u, 0xe2b87a14u, 0x7bb12baeu, 0x0cb61b38u, 0x92d28e9bu,
                    0xe5d5be0du, 0x7cdcefb7u, 0x0bdbdf21u, 0x86d3d2d4u, 0xf1d4e242u,
                    0x68ddb3f8u, 0x1fda836eu, 0x81be16cdu, 0xf6b9265bu, 0x6fb077e1u,
                    0x18b74777u, 0x88085ae6u, 0xff0f6a70u, 0x66063bcau, 0x11010b5cu,
                    0x8f659effu, 0xf862ae69u, 0x616bffd3u, 0x166ccf45u, 0xa00ae278u,
                    0xd70dd2eeu, 0x4e048354u, 0x3903b3c2u, 0xa7672661u, 0xd06016f7u,
                    0x4969474du, 0x3e6e77dbu, 0xaed16a4au, 0xd9d65adcu, 0x40df0b66u,
                    0x37d83bf0u, 0xa9bcae53u, 0xdebb9ec5u, 0x47b2cf7fu, 0x30b5ffe9u,
                    0xbdbdf21cu, 0xcabac28au, 0x53b39330u, 0x24b4a3a6u, 0xbad03605u,
                    0xcdd70693u, 0x54de5729u, 0x23d967bfu, 0xb3667a2eu, 0xc4614ab8u,
                    0x5d681b02u, 0x2a6f2b94u, 0xb40bbe37u, 0xc30c8ea1u, 0x5a05df1bu,
                    0x2d02ef8du
                };
            }

            public Deflate()
                : this(-1, -1, -1, -1) {
            }

            public Deflate(int level)
                : this(level, -1, -1, -1) {
            }

            public Deflate(int level, int windowBits)
                : this(level, windowBits, -1, -1) {
            }

            public Deflate(int level, int windowBits, int memlevel)
                : this(level, windowBits, memlevel, -1) {
            }

            public Deflate(int level, int windowBits, int memlevel, int strategy) {
                // TODO: use parameters
            }

            [RubyMethod("deflate")]
            public static MutableString/*!*/ DeflateString(Deflate/*!*/ self, [DefaultProtocol, NotNull]MutableString/*!*/ str, int flush) {
                if (flush != FINISH) {
                    throw new NotImplementedError("flush can only be FINISH");
                }

                MutableStringStream inputStream = new MutableStringStream(str);
                MutableStringStream outputStream = new MutableStringStream();
                ZDeflateStream compressedZipStream = new ZDeflateStream(outputStream, false);

                int remainingInputSize = str.Length;
                byte[] inputDataBlock = new byte[Math.Min(0x1000, remainingInputSize)];
                while (remainingInputSize > 0) {
                    int count = inputStream.Read(inputDataBlock, 0, inputDataBlock.Length);
                    compressedZipStream.Write(inputDataBlock, 0, count);
                    remainingInputSize -= count;
                }
                compressedZipStream.Close();
                return outputStream.String;
            }

            [RubyMethod("deflate", RubyMethodAttributes.PublicSingleton)]
            public static MutableString/*!*/ DeflateString(RubyClass/*!*/ self, [DefaultProtocol, NotNull]MutableString/*!*/ str) {
                return DeflateString(new Deflate(), str, FINISH);
            }
        }
#endif
        #endregion

        #region GzipWriter class
#if !SILVERLIGHT
        [RubyClass("GzipWriter", BuildConfig="!SILVERLIGHT")]
        public class GzipWriter : GZipFile {
            private readonly GZipStream/*!*/ _gzipStream;

            // TODO:
#pragma warning disable 414 // mcs: unused field
            [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")]
            private int _level, _strategy;
#pragma warning restore 414

            private GzipWriter(RespondToStorage/*!*/ respondToStorage, RubyContext/*!*/ context, IOWrapper/*!*/ ioWrapper, int level, int strategy) 
                : base(ioWrapper) {
                _level = level;
                _strategy = strategy;
                _gzipStream = new GZipStream(ioWrapper, CompressionMode.Compress, true);
            }

            [RubyConstructor]
            public static GzipWriter/*!*/ Create(
                RespondToStorage/*!*/ respondToStorage,
                RubyClass/*!*/ self,
                object io,
                [DefaultParameterValue(0)]int level,
                [DefaultParameterValue(DEFAULT_STRATEGY)]int strategy) {

                IOWrapper ioWrapper = RubyIOOps.CreateIOWrapper(respondToStorage, io, FileAccess.Write);
                if (ioWrapper == null || !ioWrapper.CanWrite) {
                    throw RubyExceptions.CreateMethodMissing(self.Context, io, "write");
                }
                
                return new GzipWriter(respondToStorage, self.Context, ioWrapper, level, strategy);
            }

            // Zlib::GzipWriter.open(filename, level=nil, strategy=nil) { |gz| ... }

            [RubyMethod("<<")]
            public static GzipWriter Output(ConversionStorage<MutableString>/*!*/ tosConversion, RubyContext/*!*/ context, GzipWriter/*!*/ self, [DefaultProtocol, NotNull]MutableString/*!*/ str) {
                Write(tosConversion, context, self, str);
                return self;
            }

            [RubyMethod("close")]
            public static object/*!*/ Close(UnaryOpStorage/*!*/ closeStorage, RubyContext/*!*/ context, GzipWriter/*!*/ self) {
                if (self._isClosed) {
                    throw new Error("closed gzip stream");
                }
                self._gzipStream.Close();
                self._ioWrapper.Flush();
                GZipFile.Close(closeStorage, self, true);
         return self._ioWrapper.UnderlyingObject;
            }

            [RubyMethod("finish")]
            public static object/*!*/ Finish(UnaryOpStorage/*!*/ closeStorage, RubyContext/*!*/ context, GzipWriter/*!*/ self) {
                self._gzipStream.Close();
                self._ioWrapper.Flush(closeStorage, context);
                GZipFile.Close(closeStorage, self, false);
                return self._ioWrapper.UnderlyingObject;
            }

            [RubyMethod("comment=")]
            public static MutableString/*!*/ Comment(GzipWriter/*!*/ self, [NotNull]MutableString/*!*/ comment) {
                if (self._isClosed) {
                    throw new Error("closed gzip stream");
                }
                self._comment = comment;

                return comment;
            }

            [RubyMethod("flush")]
            public static GzipWriter Flush(UnaryOpStorage/*!*/ flushStorage, RubyContext/*!*/ context, GzipWriter/*!*/ self, object flush) {
                if (flush != null) {
                    throw RubyExceptions.CreateUnexpectedTypeError(context, flush, "Fixnum");
                }

                return Flush(flushStorage, context, self, SYNC_FLUSH);
            }

            [RubyMethod("flush")]
            public static GzipWriter Flush(UnaryOpStorage/*!*/ flushStorage, RubyContext/*!*/ context, GzipWriter/*!*/ self, [DefaultParameterValue(SYNC_FLUSH)]int flush) {
                switch (flush) {
                    case NO_FLUSH:
                    case SYNC_FLUSH:
                    case FULL_FLUSH:
                    case FINISH:
                        self._gzipStream.Flush();
                        self._ioWrapper.Flush(flushStorage, context);
                        break;

                    default:
                        throw new StreamError("stream error");
                }
                return self;
            }

            // mtime=(p1) 

            [RubyMethod("open", RubyMethodAttributes.PublicSingleton)]
            public static object Open(
                RespondToStorage/*!*/ respondToStorage, 
                UnaryOpStorage/*!*/ closeStorage, 
                BlockParam block, 
                RubyClass/*!*/ self, 
                [NotNull]MutableString filename, 
                [DefaultParameterValue(0)]int level, 
                [DefaultParameterValue(DEFAULT_STRATEGY)]int strategy) {

                RubyFile file = new RubyFile(self.Context, filename.ConvertToString(), IOMode.CreateIfNotExists | IOMode.Truncate | IOMode.WriteOnly | IOMode.PreserveEndOfLines);
                GzipWriter gzipFile = Create(respondToStorage, self, file, level, strategy);

                if (block == null) {
                    return gzipFile;
                }

                try {
                    object blockResult;
                    block.Yield(gzipFile, out blockResult);
                    return blockResult;
                } finally {
                    Close(closeStorage, self.Context, gzipFile);
                }
            }

            [RubyMethod("open", RubyMethodAttributes.PublicSingleton)]
            public static object Open(
                RespondToStorage/*!*/ respondToStorage,
                UnaryOpStorage/*!*/ closeStorage,
                BlockParam block,
                RubyClass/*!*/ self,
                [NotNull]MutableString filename,
                object level,
                object strategy) {

                if (level != null) {
                    throw RubyExceptions.CreateUnexpectedTypeError(self.Context, level, "Fixnum");
                }
                if (strategy != null) {
                    throw RubyExceptions.CreateUnexpectedTypeError(self.Context, strategy, "Fixnum");
                }

                return Open(respondToStorage, closeStorage, block, self, filename, 0, 0);
            }

            [RubyMethod("orig_name=")]
            public static MutableString/*!*/ OriginalName(GzipWriter/*!*/ self, [NotNull]MutableString/*!*/ originalName) {
                if (self._isClosed) {
                    throw new Error("closed gzip stream");
                }

                self._originalName = originalName;

                return originalName;
            }

            // pos() 
            // print(...) 
            // printf(...) 
            // putc(p1) 
            // puts(...) 
            // tell() 
            [RubyMethod("write")]
            public static int Write(ConversionStorage<MutableString>/*!*/ tosConversion, RubyContext/*!*/ context, GzipWriter/*!*/ self, [DefaultProtocol, NotNull]MutableString/*!*/ str) {
                byte[] bytes = str.ToByteArray();
                self._gzipStream.Write(bytes, 0, bytes.Length);
                return bytes.Length;
            }
        }
#endif
        #endregion
    }
}
www.java2v.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.