ÿþFile: zlib.cs =================================================================== --- C:\svn\trunk\src\IronRuby.Libraries\Zlib\Zlib.cs (local) 4/30/2008 10:32 AM +++ zlib.cs (local) 5/1/2008 9:14 AM @@ -1,454 +1,416 @@ +?/* **************************************************************************** + * + * 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. + * + * + * ***************************************************************************/ + ?using System; using System.Collections.Generic; -using System.Collections; -using System.Text; -using Ruby; +using Microsoft.Scripting.Actions; +using Microsoft.Scripting.Runtime; + +using Ruby.Builtins; using Ruby.Runtime; -using Ruby.Builtins; -using Microsoft.Scripting.Runtime; -using Microsoft.Scripting.Actions; +namespace Ruby.StandardLibrary { -namespace Ruby.StandardLibrary -{ [RubyModule("Zlib")] - public static class Zlib - { + public static class Zlib { + + #region Constants + [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; + #endregion + + #region ZStream class + [RubyClass("ZStream")] - public class ZStream - { - public List<byte> input_buffer = new List<byte>(); - public List<byte> output_buffer = new List<byte>(); - public int out_pos = -1; - public int in_pos = -1; - public byte bit_bucket = 0; - public byte bit_count = 0; - public bool closed = false; + public class ZStream { + protected List<byte>/*!*/ _inputBuffer; + protected List<byte>/*!*/ _outputBuffer; + protected int _outPos = -1; + protected int _inPos = -1; + protected byte _bitBucket = 0; + protected byte _bitCount = 0; + protected bool _closed = false; - [RubyMethod("initialize")] - public static ZStream initialize(ZStream self) - { - self.out_pos = -1; - self.in_pos = -1; - self.bit_bucket = 0; - self.bit_count = 0; - self.input_buffer = new List<byte>(); - self.output_buffer = new List<byte>(); - return self; + 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) - { + public static int Adler(ZStream/*!*/ self) { throw new NotImplementedError(); } [RubyMethod("avail_in")] - public static int avail_in(ZStream self) - { - return self.input_buffer.Count - self.in_pos; + public static int AvailIn(ZStream/*!*/ self) { + return self._inputBuffer.Count - self._inPos; } [RubyMethod("avail_out")] - public static int avail_out(ZStream self) - { - return self.output_buffer.Count - self.out_pos; + public static int GetAvailOut(ZStream/*!*/ self) { + return self._outputBuffer.Count - self._outPos; } [RubyMethod("avail_out=")] - public static int avail_out_equals(ZStream self, int size) - { - self.output_buffer.Capacity = size; - - return self.output_buffer.Count; + 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) - { - self.closed = true; - return self.closed; + 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; + public static bool IsClosed(ZStream/*!*/ self) { + return self._closed; } [RubyMethod("data_type")] - public static void data_type(ZStream self) - { + public static void DataType(ZStream/*!*/ self) { throw new NotImplementedException(); } [RubyMethod("flush_next_in")] - public static List<byte> flush_next_in(ZStream self) - { - self.in_pos = self.input_buffer.Count; - return self.input_buffer; + public static List<byte> FlushNextIn(ZStream/*!*/ self) { + self._inPos = self._inputBuffer.Count; + return self._inputBuffer; } [RubyMethod("flush_next_out")] - public static List<byte> flush_next_out(ZStream self) - { - self.out_pos = self.output_buffer.Count; - return self.output_buffer; + public static List<byte> FlushNextOut(ZStream/*!*/ self) { + self._outPos = self._outputBuffer.Count; + return self._outputBuffer; } [RubyMethod("reset")] - public static void reset(ZStream self) - { - self.out_pos = -1; - self.in_pos = -1; - self.input_buffer = new List<byte>(); - self.output_buffer = new List<byte>(); + public static void Reset(ZStream/*!*/ self) { + self._outPos = -1; + self._inPos = -1; + self._inputBuffer = new List<byte>(); + self._outputBuffer = new List<byte>(); } [RubyMethod("total_in")] - public static int total_in(ZStream self) - { - return self.input_buffer.Count; + public static int TotalIn(ZStream/*!*/ self) { + return self._inputBuffer.Count; } [RubyMethod("total_out")] - public static int total_out(ZStream self) - { - return self.output_buffer.Count; + public static int TotalOut(ZStream/*!*/ self) { + return self._outputBuffer.Count; } - protected int get_bits(int need) - { - int val = bit_bucket; - while (bit_count < need) - { - val |= (int)(input_buffer[++in_pos] << bit_count); - bit_count += 8; + protected int GetBits(int need) { + int val = _bitBucket; + while (_bitCount < need) { + val |= (int)(_inputBuffer[++_inPos] << _bitCount); + _bitCount += 8; } - bit_bucket = (byte)(val >> need); - bit_count -= (byte)need; + _bitBucket = (byte)(val >> need); + _bitCount -= (byte)need; return (val & ((1 << need) - 1)); } + } + #endregion - } + #region Inflate class [RubyClass("Inflate")] - public class Inflate : ZStream - { - private int w_bits; - private bool rawdeflate; - private HuffmanTree fixed_length_codes = null; - private HuffmanTree fixed_distance_codes = null; - private HuffmanTree dynamic_length_codes = null; - private HuffmanTree dynamic_distance_codes = null; + public class Inflate : ZStream { + private int _wBits; + private bool _rawDeflate; + private HuffmanTree _fixedLengthCodes; + private HuffmanTree _fixedDistanceCodes; + private HuffmanTree _dynamicLengthCodes; + private HuffmanTree _dynamicDistanceCodes; - [RubyConstructor] - public static Inflate initialize() - { + public static Inflate/*!*/ Initialize() { return new Inflate(MAX_WBITS); } [RubyConstructor] - public static Inflate initialize(int window_bits) - { - return new Inflate(window_bits); + public static Inflate/*!*/ Initialize(int windowBits) { + return new Inflate(windowBits); } - public Inflate() - { - } + public Inflate() { } - public Inflate(int window_bits) - { - w_bits = window_bits; - if (w_bits < 0) - { - rawdeflate = true; - w_bits *= -1; + public Inflate(int windowBits) { + _wBits = windowBits; + if (_wBits < 0) { + _rawDeflate = true; + _wBits *= -1; } - } [RubyMethod("inflate")] - public static MutableString inflate(Inflate self, MutableString zstring) - { - foreach (byte b in zstring.ToByteArray()) - { - self.input_buffer.Add(b); + public static MutableString/*!*/ InflateStream(Inflate/*!*/ self, MutableString/*!*/ zstring) { + foreach (byte b in zstring.ToByteArray()) { + self._inputBuffer.Add(b); } - if (self.rawdeflate == false) - { - byte compression_method_and_flags = self.input_buffer[++(self.in_pos)]; - byte flags = self.input_buffer[++(self.in_pos)]; - if (((compression_method_and_flags << (byte)0x08) + flags) % (byte)31 != 0) throw new DataError("incorrect header check"); + 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); + byte compression_method = (byte)(compression_method_and_flags & (byte)0x0F); - if (compression_method != Z_DEFLATED) throw new DataError("unknown compression method"); + if (compression_method != Z_DEFLATED) throw new DataError("unknown compression method"); - byte compression_info = (byte)(compression_method_and_flags >> (byte)0x04); + byte compression_info = (byte)(compression_method_and_flags >> (byte)0x04); - if ((compression_info + 8) > self.w_bits) throw new DataError("invalid window size"); + if ((compression_info + 8) > self._wBits) throw new DataError("invalid window size"); - bool preset_dictionary_flag = ((flags & 0x20) >> 0x05 == 1); - byte compression_level = (byte)((flags & 0xC0) >> (byte)0x06); + bool preset_dictionary_flag = ((flags & 0x20) >> 0x05 == 1); + byte compression_level = (byte)((flags & 0xC0) >> (byte)0x06); - //TODO: Add Preset Dictionary Support - if (preset_dictionary_flag) self.in_pos += 4; - } + //TODO: Add Preset Dictionary Support + if (preset_dictionary_flag) self._inPos += 4; + } - bool last_block = false; + bool last_block = false; - while (!last_block) - { - last_block = (self.get_bits(1) == 1); - byte block_type = (byte)self.get_bits(2); - switch (block_type) - { - case 0: - self.no_compression(); - break; - case 1: - self.fixed_codes(); - break; - case 2: - self.dynamic_codes(); - break; - case 3: - throw new DataError("invalid block type"); - break; - } - } + 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); + return Inflate.Close(self); } - private void dynamic_codes() - { - byte[] order = {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; - int nlen = (int)get_bits(5) + 257; - int ndist = (int)get_bits(5) + 1; - int ncode = (int)get_bits(4) + 4; + 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>(); - dynamic_length_codes = new HuffmanTree(); - dynamic_distance_codes = new HuffmanTree(); + _dynamicLengthCodes = new HuffmanTree(); + _dynamicDistanceCodes = new HuffmanTree(); if (nlen > MAXLCODES || ndist > MAXDCODES) throw new DataError("too many lenght or distance codes"); int idx = 0; - while (idx < ncode) - { - SetOrExpand(lengths, order[idx], get_bits(3)); + while (idx < ncode) { + SetOrExpand(lengths, order[idx], GetBits(3)); idx++; } - while (idx < 19) - { + while (idx < 19) { SetOrExpand(lengths, order[idx], 0); idx++; } - int err = construct_tree(dynamic_length_codes, lengths, 18); + 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(dynamic_length_codes); - if (symbol < 16) - { - SetOrExpand(lengths,idx, symbol); + while (idx < (nlen + ndist)) { + int symbol = Decode(_dynamicLengthCodes); + if (symbol < 16) { + SetOrExpand(lengths, idx, symbol); idx++; - } - else - { + } else { int len = 0; - if (symbol == 16) - { + if (symbol == 16) { if (idx == 0) throw new DataError("repeat lenghts with no first length"); len = lengths[idx - 1]; - symbol = 3 + (int)get_bits(2); - } - else if (symbol == 17) - { - symbol = 3 + (int)get_bits(3); - } - else if (symbol == 18) - { - symbol = 11 + (int)get_bits(7); - } - else - { + 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"); + if ((idx + symbol) > (nlen + ndist)) throw new DataError("repeat more than specified lengths"); - while (symbol != 0) - { + while (symbol != 0) { SetOrExpand(lengths, idx, len); idx++; symbol--; } } - - } - err = construct_tree(dynamic_length_codes, lengths, nlen - 1); + err = ConstructTree(_dynamicLengthCodes, lengths, nlen - 1); - if (err < 0 || (err > 0 && (nlen - dynamic_length_codes.count[0] != 1))) throw new DataError("invalid literal/length code lengths"); + if (err < 0 || (err > 0 && (nlen - _dynamicLengthCodes.Count[0] != 1))) throw new DataError("invalid literal/length code lengths"); - for (int x = 0; x < nlen; x++) - { + for (int x = 0; x < nlen; x++) { lengths.RemoveAt(0); } - err = construct_tree(dynamic_distance_codes, lengths, ndist - 1); + err = ConstructTree(_dynamicDistanceCodes, lengths, ndist - 1); - if (err < 0 || (err > 0 && (ndist - dynamic_distance_codes.count[0] != 1))) throw new DataError("invalid distance code lengths"); + if (err < 0 || (err > 0 && (ndist - _dynamicDistanceCodes.Count[0] != 1))) throw new DataError("invalid distance code lengths"); - codes(dynamic_length_codes, dynamic_distance_codes); - + Codes(_dynamicLengthCodes, _dynamicDistanceCodes); } [RubyMethod("close")] - public static MutableString close(Inflate self) - { - return new MutableString(self.output_buffer.ToArray(), 0, self.output_buffer.Count); + public static MutableString/*!*/ Close(Inflate/*!*/ self) { + return new MutableString(self._outputBuffer.ToArray(), 0, self._outputBuffer.Count); } - private void no_compression() - { - bit_bucket = 0; - bit_count = 0; - - if (in_pos + 4 > input_buffer.Count) throw new DataError("not enough input to read length code"); - - uint length = (uint)(input_buffer[++in_pos] | (input_buffer[++in_pos] << 8)); + private void NoCompression() { + _bitBucket = 0; + _bitCount = 0; - if ((~length & 0xff) != input_buffer[++in_pos] || (((~length >> 8) & 0xff) != input_buffer[++in_pos])) throw new DataError("invalid stored block lengths"); + if (_inPos + 4 > _inputBuffer.Count) throw new DataError("not enough input to read length code"); - if (in_pos + length > input_buffer.Count) throw new DataError("ran out of input"); + uint length = (uint)(_inputBuffer[++_inPos] | (_inputBuffer[++_inPos] << 8)); - while (length > 0) - { - output_buffer.Add(input_buffer[++in_pos]); + if ((~length & 0xff) != _inputBuffer[++_inPos] || (((~length >> 8) & 0xff) != _inputBuffer[++_inPos])) throw new DataError("invalid stored block lengths"); + + if (_inPos + length > _inputBuffer.Count) throw new DataError("ran out of input"); + + while (length > 0) { + _outputBuffer.Add(_inputBuffer[++_inPos]); } - } - private void fixed_codes() - { - if (fixed_length_codes == null && fixed_distance_codes == null) generate_huffmans(); - codes(fixed_length_codes, fixed_distance_codes); + private void FixedCodes() { + if (_fixedLengthCodes == null && _fixedDistanceCodes == null) GenerateHuffmans(); + Codes(_fixedLengthCodes, _fixedDistanceCodes); } - private void generate_huffmans() - { + private void GenerateHuffmans() { List<int> lengths = new List<int>(); int x = 0; - for (; x < 144; x++) - { + for (; x < 144; x++) { lengths.Add(8); } - for (; x < 256; x++) - { + for (; x < 256; x++) { lengths.Add(9); } - for (; x < 280; x++) - { + for (; x < 280; x++) { lengths.Add(7); } - for (; x < 288; x++) - { + for (; x < 288; x++) { lengths.Add(8); } - fixed_length_codes = new HuffmanTree(); - construct_tree(fixed_length_codes, lengths, 287); + _fixedLengthCodes = new HuffmanTree(); + ConstructTree(_fixedLengthCodes, lengths, 287); lengths.Clear(); - for (int y = 0; y < 30; y++) - { + for (int y = 0; y < 30; y++) { lengths.Add(5); } - fixed_distance_codes = new HuffmanTree(); - construct_tree(fixed_distance_codes, lengths, 29); + _fixedDistanceCodes = new HuffmanTree(); + ConstructTree(_fixedDistanceCodes, lengths, 29); } - private int construct_tree(HuffmanTree tree, List<int> lengths, int n_symbols) - { + 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 x = 0; x <= MAXBITS; x++) { + SetOrExpand(tree.Count, x, 0); } - for (int y = 0; y <= n_symbols; y++) - { - (tree.count[lengths[y]])++; + for (int y = 0; y <= symbols; y++) { + (tree.Count[lengths[y]])++; } - if (tree.count[0] == n_symbols) return 0; + if (tree.Count[0] == symbols) return 0; int left = 1; - for (int y = 1; y <= MAXBITS; y++) - { + for (int y = 1; y <= MAXBITS; y++) { left <<= 1; - left -= tree.count[y]; + left -= tree.Count[y]; if (left < 0) return left; } offs.Add(0); offs.Add(0); - for (int len = 1; len <= MAXBITS - 1; len++) - { + for (int len = 1; len <= MAXBITS - 1; len++) { offs.Add(0); - offs[len + 1] = offs[len] + tree.count[len]; + offs[len + 1] = offs[len] + tree.Count[len]; } - for (int symbol = 0; symbol <= n_symbols; symbol++) - { - if (lengths[symbol] != 0) - { - SetOrExpand(tree.symbol, offs[lengths[symbol]] ,symbol); + for (int symbol = 0; symbol <= symbols; symbol++) { + if (lengths[symbol] != 0) { + SetOrExpand(tree.Symbol, offs[lengths[symbol]], symbol); offs[lengths[symbol]]++; } } @@ -456,29 +418,22 @@ return left; } - private void SetOrExpand(List<int> list, int index, int item) - { - if (list.Count-1 < index) - { + private void SetOrExpand(List<int>/*!*/ list, int index, int item) { + if (list.Count - 1 < index) { int add = index - (list.Count - 1); - while (add != 0) - { + while (add != 0) { list.Add(0); add--; } } list[index] = item; - } - private void SetOrExpand(List<byte> list, int index, byte item) - { - if (list.Count-1 < index) - { + private void SetOrExpand(List<byte>/*!*/ list, int index, byte item) { + if (list.Count - 1 < index) { int add = index - (list.Count - 1); - while (add != 0) - { + while (add != 0) { list.Add(0); add--; } @@ -487,32 +442,27 @@ list[index] = item; } - - private int codes(HuffmanTree length_codes, HuffmanTree distance_codes) - { - 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}; + 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(length_codes); + while (symbol != 256) { + symbol = Decode(lengthCodes); if (symbol < 0) return symbol; - if (symbol < 256) SetOrExpand(output_buffer, ++out_pos , (byte)symbol); - if (symbol > 256) - { + 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] + get_bits((byte)lext[symbol]); - symbol = decode(distance_codes); + int len = lens[symbol] + GetBits((byte)lext[symbol]); + symbol = Decode(distanceCodes); if (symbol < 0) return symbol; - int dist = dists[symbol] + get_bits((byte)dext[symbol]); - if (dist > output_buffer.Count) throw new DataError("distance is too far back in fixed or dynamic block"); - while (len > 0) - { - SetOrExpand(output_buffer, ++out_pos, output_buffer[out_pos - dist]); + 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--; } } @@ -521,16 +471,14 @@ return 0; } - private int decode(HuffmanTree tree) - { + private int Decode(HuffmanTree/*!*/ tree) { int code = 0; int first = 0; int index = 0; - for (int len = 1; len <= 15; len++) - { - code |= get_bits(1); - int count = tree.count[len]; - if(code < (first + count)) return tree.symbol[index + (code - first)]; + 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; @@ -541,78 +489,121 @@ } #region Dynamic Site - private static DynamicSite<object, MutableString, MutableString> InflateSite = DynamicSite<object, MutableString, MutableString>.Create( - RubySites.InstanceCallAction("inflate", Microsoft.Scripting.Ast.ArgumentKind.Simple) - ); + private static DynamicSite<object, MutableString, MutableString> InflateSite = DynamicSite<object, MutableString, MutableString>.Create( + RubySites.InstanceCallAction("inflate", Microsoft.Scripting.Ast.ArgumentKind.Simple) + ); #endregion [RubyMethod("inflate", RubyMethodAttributes.PublicSingleton)] - public static MutableString static_inflate(CodeContext context, RubyClass self, MutableString zstring) - { + public static MutableString InflateStream(CodeContext/*!*/ context, RubyClass/*!*/ self, MutableString zstring) { object obj = RubySites.Allocate(context, self); return InflateSite.Invoke(context, obj, zstring); } - [RubyClass("HuffmanTree")] - public class HuffmanTree - { - public List<int> count; - public List<int> symbol; + public class HuffmanTree { + private List<int>/*!*/ _count; + private List<int>/*!*/ _symbol; - public HuffmanTree() - { - count = new List<int>(); - symbol = new List<int>(); + public HuffmanTree() { + _count = new List<int>(); + _symbol = new List<int>(); } + public List<int> Count { + get { return _count; } + set { _count = value; } + } + + public List<int> Symbol { + get { return _symbol; } + set { _symbol = value; } + } } } + #endregion + + #region GzipFile class + [RubyClass("GzipFile")] - public class GzipFile - { - public List<byte> input_buffer = new List<byte>(); - public List<byte> output_buffer = new List<byte>(); - public int out_pos = -1; - public int in_pos = -1; + public class GZipFile { + protected List<byte>/*!*/ _inputBuffer; + protected List<byte>/*!*/ _outputBuffer; + protected int _outPos; + protected int _inPos; + public GZipFile() { + _inputBuffer = new List<byte>(); + _outputBuffer = new List<byte>(); + _outPos = -1; + _inPos = -1; + } + [RubyClass("Error")] - public class Error : RuntimeError - { - public Error(string message): base(message) - { + public class Error : RuntimeError { + public Error(string message) + : base(message) { } } + + // TODO: missing NoFooter, LengthError, CRCError constants } + #endregion + + #region GzipReader class + [RubyClass("GzipReader")] - public class GzipReader : GzipFile - { - public RubyIO io; - - public List<byte> xtra_field; - public MutableString original_name; - public MutableString comment; - public List<byte> contents; - public int header_crc; + public class GZipReader : GZipFile, IDisposable { + #region IDisposable Members + + private bool _disposed; + + protected virtual void Dispose(bool disposing) { + if (!_disposed) { + if (disposing) { + if (_io != null) { + _io.Dispose(); + _io = null; + } + } + _disposed = true; + } + } + + public void Dispose() { + Dispose(true); + GC.SuppressFinalize(this); + } + + ~GZipReader() { + Dispose(false); + } + + #endregion + + protected RubyIO/*!*/ _io; + protected List<byte>/*!*/ _xtraField; + protected List<byte>/*!*/ _contents; + protected MutableString/*!*/ _originalName; + protected MutableString/*!*/ _comment; + protected int _headerCrc; + [RubyMethod("xtra_field")] - public static List<byte> ExtraField(GzipReader self) - { - return self.xtra_field; + public static List<byte>/*!*/ ExtraField(GZipReader self) { + return self._xtraField; } [RubyMethod("original_name")] - public static MutableString OriginalName(GzipReader self) - { - return self.original_name; + public static MutableString/*!*/ OriginalName(GZipReader self) { + return self._originalName; } [RubyMethod("comment")] - public static MutableString Comment(GzipReader self) - { - return self.comment; + public static MutableString/*!*/ Comment(GZipReader self) { + return self._comment; } [RubyConstant("OSES")] @@ -632,130 +623,126 @@ "Acorn RISCOS", "unknown"}; - private bool isbitset(byte b, byte bit) - { - return ((b & (1<<bit)) == (1<<bit)); + private bool IsBitSet(byte b, byte bit) { + return ((b & (1 << bit)) == (1 << bit)); } [RubyConstructor] - public static GzipReader initialize(CodeContext context, RubyIO iop) - { - return new GzipReader(iop); + public static GZipReader/*!*/ Initialize(CodeContext/*!*/ context, RubyIO/*!*/ iop) { + return new GZipReader(iop); } - public GzipReader(RubyIO iop) : base() - { - + public GZipReader(RubyIO/*!*/ iop) + : base() { - io = iop; - int b = io.ReadByte(); - while (b != -1) - { - input_buffer.Add((byte)b); - b = io.ReadByte(); + // TODO: should all of this code be moved to open()? + _io = iop; + _disposed = false; + int b = _io.ReadByte(); + while (b != -1) { + _inputBuffer.Add((byte)b); + b = _io.ReadByte(); } - if (input_buffer[++in_pos] != (byte)0x1f || input_buffer[++in_pos] != (byte)0x8b) throw new Error("not in gzip format"); - if(input_buffer[++in_pos] != (byte)0x08) throw new Error("unknown compression method"); - byte flg = input_buffer[++in_pos]; - 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); - DateTime mtime = DateTime.Parse("Wed, 31 Dec 1969 23:00:00 GMT").AddSeconds(input_buffer[++in_pos] | input_buffer[++in_pos] << 8 | input_buffer[++in_pos] << 16 | input_buffer[++in_pos] << 24); - byte xfl = input_buffer[++in_pos]; - string os = GzipReader.OSES[input_buffer[++in_pos]]; - xtra_field = new List<byte>(); - if(fextra) - { - int xlen = input_buffer[++in_pos] | (input_buffer[++in_pos] << (byte)8); - for (int x = 0; x < xlen; ++x) - { - xtra_field.Add(input_buffer[++in_pos]); + if (_inputBuffer[++_inPos] != (byte)0x1f || _inputBuffer[++_inPos] != (byte)0x8b) throw new Error("not in gzip format"); + if (_inputBuffer[++_inPos] != (byte)0x08) throw new Error("unknown compression method"); + byte flg = _inputBuffer[++_inPos]; + 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); + DateTime mtime = DateTime.Parse("Wed, 31 Dec 1969 23:00:00 GMT").AddSeconds(_inputBuffer[++_inPos] | _inputBuffer[++_inPos] << 8 | _inputBuffer[++_inPos] << 16 | _inputBuffer[++_inPos] << 24); + byte xfl = _inputBuffer[++_inPos]; + string os = GZipReader.OSES[_inputBuffer[++_inPos]]; + _xtraField = new List<byte>(); + if (fextra) { + int xlen = _inputBuffer[++_inPos] | (_inputBuffer[++_inPos] << (byte)8); + for (int x = 0; x < xlen; ++x) { + _xtraField.Add(_inputBuffer[++_inPos]); } } - original_name = new MutableString(); - if (fname) - { - while (original_name.IndexOf('\0') == -1) - { - original_name.Append((char)input_buffer[++in_pos]); + _originalName = new MutableString(); + if (fname) { + while (_originalName.IndexOf('\0') == -1) { + _originalName.Append((char)_inputBuffer[++_inPos]); } - original_name.Remove(original_name.Length-1, 1); + _originalName.Remove(_originalName.Length - 1, 1); } - comment = new MutableString(); - if (fcomment) - { - while (comment.IndexOf('\0') == -1) - { - comment.Append((char)input_buffer[++in_pos]); + _comment = new MutableString(); + if (fcomment) { + while (_comment.IndexOf('\0') == -1) { + _comment.Append((char)_inputBuffer[++_inPos]); } - comment.Remove(original_name.Length-1, 1); + _comment.Remove(_originalName.Length - 1, 1); } - if (fhcrc) - { - header_crc = input_buffer[++in_pos] | (input_buffer[++in_pos] << 8); + if (fhcrc) { + _headerCrc = _inputBuffer[++_inPos] | (_inputBuffer[++_inPos] << 8); } - contents = new List<byte>(); - while (in_pos != input_buffer.Count - 1) - { - contents.Add(input_buffer[++in_pos]); + _contents = new List<byte>(); + while (_inPos != _inputBuffer.Count - 1) { + _contents.Add(_inputBuffer[++_inPos]); } } [RubyMethod("read")] - public static MutableString read(GzipReader self) - { + public static MutableString/*!*/ Read(GZipReader/*!*/ self) { Inflate z = new Inflate(-MAX_WBITS); - return Inflate.inflate(z, new MutableString(self.contents.ToArray(), 0, self.contents.Count)); + return Inflate.InflateStream(z, new MutableString(self._contents.ToArray(), 0, self._contents.Count)); } - [RubyMethod("open", RubyMethodAttributes.PublicInstance)] - public static GzipReader open(RubyIO iop) - { - GzipReader gz = new GzipReader(iop); - return gz; + [RubyMethod("open", RubyMethodAttributes.PrivateInstance)] + public static GZipReader/*!*/ Open(RubyIO/*!*/ iop) { + // 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 new GZipReader(iop); } - #region Dynamic Site - private static DynamicSite<object, RubyIO, GzipReader> GzipReaderSite = DynamicSite<object, RubyIO, GzipReader>.Create( - RubySites.InstanceCallAction("open", Microsoft.Scripting.Ast.ArgumentKind.Simple) - ); - #endregion + private static readonly DynamicSite<BlockParam, GZipReader, object> _OpenBlockSite = + CallSiteFactory.CreateSimpleCallSite<BlockParam, GZipReader, object>(RubyContext.RubyBinder); [RubyMethod("open", RubyMethodAttributes.PublicSingleton)] - public static GzipReader open(CodeContext context, RubyClass self, MutableString filename) - { - RubyIO io = RubyFileOps.CreateIO(context, filename); - - object obj = RubySites.Allocate(context, self); - return GzipReaderSite.Invoke(context, obj, io); + public static GZipReader/*!*/ Open(CodeContext/*!*/ context, RubyClass/*!*/ self, [NotNull]MutableString/*!*/ filename) { + return new GZipReader(RubyFileOps.CreateIO(context, filename)); } [RubyMethod("open", RubyMethodAttributes.PublicSingleton)] - public static GzipReader open(BlockParam block, CodeContext context, RubyClass self, MutableString filename) - { - return open(context, self, filename); + public static GZipReader Open(CodeContext/*!*/ context, RubyClass/*!*/ self, object filename) { + return Open(context, self, Protocols.CastToString(context, filename)); } + [RubyMethod("open", RubyMethodAttributes.PublicSingleton)] + public static void Open(CodeContext/*!*/ context, RubyClass/*!*/ self, BlockParam block, [NotNull]MutableString/*!*/ filename) { + using (GZipReader reader = Open(context, self, filename)) { + _OpenBlockSite.Invoke(context, block, reader); + } + return; + } + + [RubyMethod("open", RubyMethodAttributes.PublicSingleton)] + public static void Open(CodeContext/*!*/ context, RubyClass/*!*/ self, BlockParam block, object filename) { + Open(context, self, block, Protocols.CastToString(context, filename)); + } } + #endregion + #region DataError class + [RubyClass("DataError")] - public class DataError : RuntimeError - { + public class DataError : RuntimeError { public DataError(string error) - : base(error) - { + : base(error) { } } + + #endregion } } ===================================================================