dotgnu-pnet-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Dotgnu-pnet-commits] pnetlib/SharpZipLib/Zip/Compression Deflater.cs, N


From: Rhys Weatherley <address@hidden>
Subject: [Dotgnu-pnet-commits] pnetlib/SharpZipLib/Zip/Compression Deflater.cs, NONE, 1.1 DeflaterConstants.cs, NONE, 1.1 DeflaterEngine.cs, NONE, 1.1 DeflaterHuffman.cs, NONE, 1.1 DeflaterPending.cs, NONE, 1.1 Inflater.cs, NONE, 1.1 InflaterDynHeader.cs, NONE, 1.1 InflaterHuffmanTree.cs, NONE, 1.1 PendingBuffer.cs, NONE, 1.1
Date: Wed, 08 Oct 2003 07:37:07 +0000

Update of /cvsroot/dotgnu-pnet/pnetlib/SharpZipLib/Zip/Compression
In directory subversions:/tmp/cvs-serv5756/SharpZipLib/Zip/Compression

Added Files:
        Deflater.cs DeflaterConstants.cs DeflaterEngine.cs 
        DeflaterHuffman.cs DeflaterPending.cs Inflater.cs 
        InflaterDynHeader.cs InflaterHuffmanTree.cs PendingBuffer.cs 
Log Message:


Add the "SharpZipLib" directory to pnetlib, which is a port of
SharpDevelop's compression handling library.


--- NEW FILE: InflaterHuffmanTree.cs ---
// InflaterHuffmanTree.cs
// Copyright (C) 2001 Mike Krueger
//
// This file was translated from java, it was part of the GNU Classpath
// Copyright (C) 2001 Free Software Foundation, Inc.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
//
// Linking this library statically or dynamically with other modules is
// making a combined work based on this library.  Thus, the terms and
// conditions of the GNU General Public License cover the whole
// combination.
// 
// As a special exception, the copyright holders of this library give you
// permission to link this library with independent modules to produce an
// executable, regardless of the license terms of these independent
// modules, and to copy and distribute the resulting executable under
// terms of your choice, provided that you also meet, for each linked
// independent module, the terms and conditions of the license of that
// module.  An independent module is a module which is not derived from
// or based on this library.  If you modify this library, you may extend
// this exception to your version of the library, but you are not
// obligated to do so.  If you do not wish to do so, delete this
// exception statement from your version.

using System;

using ICSharpCode.SharpZipLib.Zip.Compression.Streams;

namespace ICSharpCode.SharpZipLib.Zip.Compression 
{
        
        public class InflaterHuffmanTree 
        {
                private static int MAX_BITLEN = 15;
                private short[] tree;
                
                public static InflaterHuffmanTree defLitLenTree, defDistTree;
                
                static InflaterHuffmanTree()
                {
                        try 
                        {
                                byte[] codeLengths = new byte[288];
                                int i = 0;
                                while (i < 144) 
                                {
                                        codeLengths[i++] = 8;
                                }
                                while (i < 256) 
                                {
                                        codeLengths[i++] = 9;
                                }
                                while (i < 280) 
                                {
                                        codeLengths[i++] = 7;
                                }
                                while (i < 288) 
                                {
                                        codeLengths[i++] = 8;
                                }
                                defLitLenTree = new 
InflaterHuffmanTree(codeLengths);
                                
                                codeLengths = new byte[32];
                                i = 0;
                                while (i < 32) 
                                {
                                        codeLengths[i++] = 5;
                                }
                                defDistTree = new 
InflaterHuffmanTree(codeLengths);
                        } 
                        catch (Exception) 
                        {
                                throw new 
ApplicationException("InflaterHuffmanTree: static tree length illegal");
                        }
                }
                
                /// <summary>
                /// Constructs a Huffman tree from the array of code lengths.
                /// </summary>
                /// <param name = "codeLengths">
                /// the array of code lengths
                /// </param>
                public InflaterHuffmanTree(byte[] codeLengths)
                {
                        BuildTree(codeLengths);
                }
                
                private void BuildTree(byte[] codeLengths)
                {
                        int[] blCount  = new int[MAX_BITLEN + 1];
                        int[] nextCode = new int[MAX_BITLEN + 1];
                        
                        for (int i = 0; i < codeLengths.Length; i++) 
                        {
                                int bits = codeLengths[i];
                                if (bits > 0)
                                        blCount[bits]++;
                        }
                        
                        int code = 0;
                        int treeSize = 512;
                        for (int bits = 1; bits <= MAX_BITLEN; bits++) 
                        {
                                nextCode[bits] = code;
                                code += blCount[bits] << (16 - bits);
                                if (bits >= 10) 
                                {
                                        /* We need an extra table for bit 
lengths >= 10. */
                                        int start = nextCode[bits] & 0x1ff80;
                                        int end   = code & 0x1ff80;
                                        treeSize += (end - start) >> (16 - 
bits);
                                }
                        }
                        if (code != 65536) 
                        {
                                throw new Exception("Code lengths don't add up 
properly.");
                        }
                        /* Now create and fill the extra tables from longest to 
shortest
                        * bit len.  This way the sub trees will be aligned.
                        */
                        tree = new short[treeSize];
                        int treePtr = 512;
                        for (int bits = MAX_BITLEN; bits >= 10; bits--) 
                        {
                                int end   = code & 0x1ff80;
                                code -= blCount[bits] << (16 - bits);
                                int start = code & 0x1ff80;
                                for (int i = start; i < end; i += 1 << 7) 
                                {
                                        tree[DeflaterHuffman.BitReverse(i)] = 
(short) ((-treePtr << 4) | bits);
                                        treePtr += 1 << (bits-9);
                                }
                        }
                        
                        for (int i = 0; i < codeLengths.Length; i++) 
                        {
                                int bits = codeLengths[i];
                                if (bits == 0) 
                                {
                                        continue;
                                }
                                code = nextCode[bits];
                                int revcode = DeflaterHuffman.BitReverse(code);
                                if (bits <= 9) 
                                {
                                        do 
                                        {
                                                tree[revcode] = (short) ((i << 
4) | bits);
                                                revcode += 1 << bits;
                                        } while (revcode < 512);
                                } 
                                else 
                                {
                                        int subTree = tree[revcode & 511];
                                        int treeLen = 1 << (subTree & 15);
                                        subTree = -(subTree >> 4);
                                        do 
                                        {
                                                tree[subTree | (revcode >> 9)] 
= (short) ((i << 4) | bits);
                                                revcode += 1 << bits;
                                        } while (revcode < treeLen);
                                }
                                nextCode[bits] = code + (1 << (16 - bits));
                        }
                        
                }
                
                /// <summary>
                /// Reads the next symbol from input.  The symbol is encoded 
using the
                /// huffman tree.
                /// </summary>
                /// <param name="input">
                /// input the input source.
                /// </param>
                /// <returns>
                /// the next symbol, or -1 if not enough input is available.
                /// </returns>
                public int GetSymbol(StreamManipulator input)
                {
                        int lookahead, symbol;
                        if ((lookahead = input.PeekBits(9)) >= 0) 
                        {
                                if ((symbol = tree[lookahead]) >= 0) 
                                {
                                        input.DropBits(symbol & 15);
                                        return symbol >> 4;
                                }
                                int subtree = -(symbol >> 4);
                                int bitlen = symbol & 15;
                                if ((lookahead = input.PeekBits(bitlen)) >= 0) 
                                {
                                        symbol = tree[subtree | (lookahead >> 
9)];
                                        input.DropBits(symbol & 15);
                                        return symbol >> 4;
                                } 
                                else 
                                {
                                        int bits = input.AvailableBits;
                                        lookahead = input.PeekBits(bits);
                                        symbol = tree[subtree | (lookahead >> 
9)];
                                        if ((symbol & 15) <= bits) 
                                        {
                                                input.DropBits(symbol & 15);
                                                return symbol >> 4;
                                        } 
                                        else 
                                        {
                                                return -1;
                                        }
                                }
                        } 
                        else 
                        {
                                int bits = input.AvailableBits;
                                lookahead = input.PeekBits(bits);
                                symbol = tree[lookahead];
                                if (symbol >= 0 && (symbol & 15) <= bits) 
                                {
                                        input.DropBits(symbol & 15);
                                        return symbol >> 4;
                                } 
                                else 
                                {
                                        return -1;
                                }
                        }
                }
        }
}


--- NEW FILE: DeflaterPending.cs ---
// DeflaterPending.cs
// Copyright (C) 2001 Mike Krueger
//
// This file was translated from java, it was part of the GNU Classpath
// Copyright (C) 2001 Free Software Foundation, Inc.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
//
// Linking this library statically or dynamically with other modules is
// making a combined work based on this library.  Thus, the terms and
// conditions of the GNU General Public License cover the whole
// combination.
// 
// As a special exception, the copyright holders of this library give you
// permission to link this library with independent modules to produce an
// executable, regardless of the license terms of these independent
// modules, and to copy and distribute the resulting executable under
// terms of your choice, provided that you also meet, for each linked
// independent module, the terms and conditions of the license of that
// module.  An independent module is a module which is not derived from
// or based on this library.  If you modify this library, you may extend
// this exception to your version of the library, but you are not
// obligated to do so.  If you do not wish to do so, delete this
// exception statement from your version.

namespace ICSharpCode.SharpZipLib.Zip.Compression 
{
        
        /// <summary>
        /// This class stores the pending output of the Deflater.
        /// 
        /// author of the original java version : Jochen Hoenicke
        /// </summary>
        public class DeflaterPending : PendingBuffer
        {
                public DeflaterPending() : 
base(DeflaterConstants.PENDING_BUF_SIZE)
                {
                }
        }
}

--- NEW FILE: PendingBuffer.cs ---
// PendingBuffer.cs
// Copyright (C) 2001 Mike Krueger
//
// This file was translated from java, it was part of the GNU Classpath
// Copyright (C) 2001 Free Software Foundation, Inc.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
//
// Linking this library statically or dynamically with other modules is
// making a combined work based on this library.  Thus, the terms and
// conditions of the GNU General Public License cover the whole
// combination.
// 
// As a special exception, the copyright holders of this library give you
// permission to link this library with independent modules to produce an
// executable, regardless of the license terms of these independent
// modules, and to copy and distribute the resulting executable under
// terms of your choice, provided that you also meet, for each linked
// independent module, the terms and conditions of the license of that
// module.  An independent module is a module which is not derived from
// or based on this library.  If you modify this library, you may extend
// this exception to your version of the library, but you are not
// obligated to do so.  If you do not wish to do so, delete this
// exception statement from your version.

using System;

namespace ICSharpCode.SharpZipLib.Zip.Compression 
{
        
        /// <summary>
        /// This class is general purpose class for writing data to a buffer.
        /// 
        /// It allows you to write bits as well as bytes
        /// Based on DeflaterPending.java
        /// 
        /// author of the original java version : Jochen Hoenicke
        /// </summary>
        public class PendingBuffer
        {
                protected byte[] buf;
                int    start;
                int    end;
                
                uint    bits;
                int    bitCount;
                
                public PendingBuffer() : this( 4096 )
                {
                        
                }
                
                public PendingBuffer(int bufsize)
                {
                        buf = new byte[bufsize];
                }
                
                public void Reset() 
                {
                        start = end = bitCount = 0;
                }
                
                public void WriteByte(int b)
                {
                        if (DeflaterConstants.DEBUGGING && start != 0)
                                throw new Exception();
                        buf[end++] = (byte) b;
                }
                
                public void WriteShort(int s)
                {
                        if (DeflaterConstants.DEBUGGING && start != 0) 
                        {
                                throw new Exception();
                        }
                        buf[end++] = (byte) s;
                        buf[end++] = (byte) (s >> 8);
                }
                
                public void WriteInt(int s)
                {
                        if (DeflaterConstants.DEBUGGING && start != 0) 
                        {
                                throw new Exception();
                        }
                        buf[end++] = (byte) s;
                        buf[end++] = (byte) (s >> 8);
                        buf[end++] = (byte) (s >> 16);
                        buf[end++] = (byte) (s >> 24);
                }
                
                public void WriteBlock(byte[] block, int offset, int len)
                {
                        if (DeflaterConstants.DEBUGGING && start != 0) 
                        {
                                throw new Exception();
                        }
                        System.Array.Copy(block, offset, buf, end, len);
                        end += len;
                }
                
                public int BitCount 
                {
                        get 
                        {
                                return bitCount;
                        }
                }
                
                public void AlignToByte() 
                {
                        if (DeflaterConstants.DEBUGGING && start != 0) 
                        {
                                throw new Exception();
                        }
                        if (bitCount > 0) 
                        {
                                buf[end++] = (byte) bits;
                                if (bitCount > 8) 
                                {
                                        buf[end++] = (byte) (bits >> 8);
                                }
                        }
                        bits = 0;
                        bitCount = 0;
                }
                
                public void WriteBits(int b, int count)
                {
                        if (DeflaterConstants.DEBUGGING && start != 0) 
                        {
                                throw new Exception();
                        }
                        //                      if 
(DeflaterConstants.DEBUGGING) {
                        //                              
//Console.WriteLine("writeBits("+b+","+count+")");
                        //                      }
                        bits |= (uint)(b << bitCount);
                        bitCount += count;
                        if (bitCount >= 16) 
                        {
                                buf[end++] = (byte) bits;
                                buf[end++] = (byte) (bits >> 8);
                                bits >>= 16;
                                bitCount -= 16;
                        }
                }
                
                public void WriteShortMSB(int s) 
                {
                        if (DeflaterConstants.DEBUGGING && start != 0) 
                        {
                                throw new Exception();
                        }
                        buf[end++] = (byte) (s >> 8);
                        buf[end++] = (byte) s;
                }
                
                public bool IsFlushed 
                {
                        get 
                        {
                                return end == 0;
                        }
                }
                
                /// <summary>
                /// Flushes the pending buffer into the given output array.  If 
the
                /// output array is to small, only a partial flush is done.
                /// </summary>
                /// <param name="output">
                /// the output array;
                /// </param>
                /// <param name="offset">
                /// the offset into output array;
                /// </param>
                /// <param name="length">               
                /// length the maximum number of bytes to store;
                /// </param>
                /// <exception name="ArgumentOutOfRangeException">
                /// IndexOutOfBoundsException if offset or length are invalid.
                /// </exception>
                public int Flush(byte[] output, int offset, int length) 
                {
                        if (bitCount >= 8) 
                        {
                                buf[end++] = (byte) bits;
                                bits >>= 8;
                                bitCount -= 8;
                        }
                        if (length > end - start) 
                        {
                                length = end - start;
                                System.Array.Copy(buf, start, output, offset, 
length);
                                start = 0;
                                end = 0;
                        } 
                        else 
                        {
                                System.Array.Copy(buf, start, output, offset, 
length);
                                start += length;
                        }
                        return length;
                }
                
                public byte[] ToByteArray()
                {
                        byte[] ret = new byte[ end - start ];
                        System.Array.Copy(buf, start, ret, 0, ret.Length);
                        start = 0;
                        end = 0;
                        return ret;
                }
        }
}       

--- NEW FILE: Inflater.cs ---
// Inflater.cs
// Copyright (C) 2001 Mike Krueger
//
// This file was translated from java, it was part of the GNU Classpath
// Copyright (C) 2001 Free Software Foundation, Inc.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
//
// Linking this library statically or dynamically with other modules is
// making a combined work based on this library.  Thus, the terms and
// conditions of the GNU General Public License cover the whole
// combination.
// 
// As a special exception, the copyright holders of this library give you
// permission to link this library with independent modules to produce an
// executable, regardless of the license terms of these independent
// modules, and to copy and distribute the resulting executable under
// terms of your choice, provided that you also meet, for each linked
// independent module, the terms and conditions of the license of that
// module.  An independent module is a module which is not derived from
// or based on this library.  If you modify this library, you may extend
// this exception to your version of the library, but you are not
// obligated to do so.  If you do not wish to do so, delete this
// exception statement from your version.

using System;

using ICSharpCode.SharpZipLib.Checksums;
using ICSharpCode.SharpZipLib.Zip.Compression.Streams;

namespace ICSharpCode.SharpZipLib.Zip.Compression 
{
        
        /// <summary>
        /// Inflater is used to decompress data that has been compressed 
according
        /// to the "deflate" standard described in rfc1950.
        ///
        /// The usage is as following.  First you have to set some input with
        /// <code>setInput()</code>, then inflate() it.  If inflate doesn't
        /// inflate any bytes there may be three reasons:
        /// <ul>
        /// <li>needsInput() returns true because the input buffer is empty.
        /// You have to provide more input with <code>setInput()</code>.
        /// NOTE: needsInput() also returns true when, the stream is finished.
        /// </li>
        /// <li>needsDictionary() returns true, you have to provide a preset
        ///    dictionary with <code>setDictionary()</code>.</li>
        /// <li>finished() returns true, the inflater has finished.</li>
        /// </ul>
        /// Once the first output byte is produced, a dictionary will not be
        /// needed at a later stage.
        ///
        /// author of the original java version : John Leuner, Jochen Hoenicke
        /// </summary>
        public class Inflater
        {
                /// <summary>
                /// Copy lengths for literal codes 257..285
                /// </summary>
                private static int[] CPLENS = {
                                                                                
  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
                                                                          };
                
                /// <summary>
                /// Extra bits for literal codes 257..285
                /// </summary>
                private static int[] CPLEXT = {
                                                                                
  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
                                                                          };
                
                /// <summary>
                /// Copy offsets for distance codes 0..29
                /// </summary>
                private static int[] CPDIST = {
                                                                                
  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
                                                                          };
                
                /// <summary>
                /// Extra bits for distance codes
                /// </summary>
                private static int[] CPDEXT = {
                                                                                
  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
                                                                          };
                
                /// <summary>
                /// This are the state in which the inflater can be.
                /// </summary>
                private const int DECODE_HEADER           = 0;
                private const int DECODE_DICT             = 1;
                private const int DECODE_BLOCKS           = 2;
                private const int DECODE_STORED_LEN1      = 3;
                private const int DECODE_STORED_LEN2      = 4;
                private const int DECODE_STORED           = 5;
                private const int DECODE_DYN_HEADER       = 6;
                private const int DECODE_HUFFMAN          = 7;
                private const int DECODE_HUFFMAN_LENBITS  = 8;
                private const int DECODE_HUFFMAN_DIST     = 9;
                private const int DECODE_HUFFMAN_DISTBITS = 10;
                private const int DECODE_CHKSUM           = 11;
                private const int FINISHED                = 12;
                
                /// <summary>
                /// This variable contains the current state.
                /// </summary>
                private int mode;
                
                /// <summary>
                /// The adler checksum of the dictionary or of the decompressed
                /// stream, as it is written in the header resp. footer of the
                /// compressed stream. 
                /// Only valid if mode is DECODE_DICT or DECODE_CHKSUM.
                /// </summary>
                private int readAdler;
                
                /// <summary>
                /// The number of bits needed to complete the current state.  
This
                /// is valid, if mode is DECODE_DICT, DECODE_CHKSUM,
                /// DECODE_HUFFMAN_LENBITS or DECODE_HUFFMAN_DISTBITS.
                /// </summary>
                private int neededBits;
                private int repLength, repDist;
                private int uncomprLen;
                
                /// <summary>
                /// True, if the last block flag was set in the last block of 
the
                /// inflated stream.  This means that the stream ends after the
                /// current block.
                /// </summary>
                private bool isLastBlock;
                
                /// <summary>
                /// The total number of inflated bytes.
                /// </summary>
                private int totalOut;
                
                /// <summary>
                /// The total number of bytes set with setInput().  This is not 
the
                /// value returned by getTotalIn(), since this also includes the
                /// unprocessed input.
                /// </summary>
                private int totalIn;
                
                /// <summary>
                /// This variable stores the nowrap flag that was given to the 
constructor.
                /// True means, that the inflated stream doesn't contain a 
header nor the
                /// checksum in the footer.
                /// </summary>
                private bool nowrap;
                
                private StreamManipulator input;
                private OutputWindow outputWindow;
                private InflaterDynHeader dynHeader;
                private InflaterHuffmanTree litlenTree, distTree;
                private Adler32 adler;
                
                /// <summary>
                /// Creates a new inflater.
                /// </summary>
                public Inflater() : this(false)
                {
                }
                
                /// <summary>
                /// Creates a new inflater.
                /// </summary>
                /// <param name="nowrap">
                /// true if no header and checksum field appears in the
                /// stream.  This is used for GZIPed input.  For compatibility 
with
                /// Sun JDK you should provide one byte of input more than 
needed in
                /// this case.
                /// </param>
                public Inflater(bool nowrap)
                {
                        this.nowrap = nowrap;
                        this.adler = new Adler32();
                        input = new StreamManipulator();
                        outputWindow = new OutputWindow();
                        mode = nowrap ? DECODE_BLOCKS : DECODE_HEADER;
                }
                
                /// <summary>
                /// Resets the inflater so that a new stream can be 
decompressed.  All
                /// pending input and output will be discarded.
                /// </summary>
                public void Reset()
                {
                        mode = nowrap ? DECODE_BLOCKS : DECODE_HEADER;
                        totalIn = totalOut = 0;
                        input.Reset();
                        outputWindow.Reset();
                        dynHeader = null;
                        litlenTree = null;
                        distTree = null;
                        isLastBlock = false;
                        adler.Reset();
                }
                
                /// <summary>
                /// Decodes the deflate header.
                /// </summary>
                /// <returns>
                /// false if more input is needed.
                /// </returns>
                /// <exception cref="System.FormatException">
                /// if header is invalid.
                /// </exception>
                private bool DecodeHeader()
                {
                        int header = input.PeekBits(16);
                        if (header < 0) 
                        {
                                return false;
                        }
                        input.DropBits(16);
                        /* The header is written in "wrong" byte order */
                        header = ((header << 8) | (header >> 8)) & 0xffff;
                        if (header % 31 != 0) 
                        {
                                throw new FormatException("Header checksum 
illegal");
                        }
                        
                        if ((header & 0x0f00) != (Deflater.DEFLATED << 8)) 
                        {
                                throw new FormatException("Compression Method 
unknown");
                        }
                        
                        /* Maximum size of the backwards window in bits.
                        * We currently ignore this, but we could use it to make 
the
                        * inflater window more space efficient. On the other 
hand the
                        * full window (15 bits) is needed most times, anyway.
                        int max_wbits = ((header & 0x7000) >> 12) + 8;
                        */
                        
                        if ((header & 0x0020) == 0) 
                        { // Dictionary flag?
                                mode = DECODE_BLOCKS;
                        } 
                        else 
                        {
                                mode = DECODE_DICT;
                                neededBits = 32;
                        }
                        return true;
                }
                
                /// <summary>
                /// Decodes the dictionary checksum after the deflate header.
                /// </summary>
                /// <returns>
                /// false if more input is needed.
                /// </returns>
                private bool DecodeDict()
                {
                        while (neededBits > 0) 
                        {
                                int dictByte = input.PeekBits(8);
                                if (dictByte < 0) 
                                {
                                        return false;
                                }
                                input.DropBits(8);
                                readAdler = (readAdler << 8) | dictByte;
                                neededBits -= 8;
                        }
                        return false;
                }
                
                /// <summary>
                /// Decodes the huffman encoded symbols in the input stream.
                /// </summary>
                /// <returns>
                /// false if more input is needed, true if output window is
                /// full or the current block ends.
                /// </returns>
                /// <exception cref="System.FormatException">
                /// if deflated stream is invalid.
                /// </exception>
                private bool DecodeHuffman()
                {
                        int free = outputWindow.GetFreeSpace();
                        while (free >= 258) 
                        {
                                int symbol;
                                switch (mode) 
                                {
                                        case DECODE_HUFFMAN:
                                                /* This is the inner loop so it 
is optimized a bit */
                                                while (((symbol = 
litlenTree.GetSymbol(input)) & ~0xff) == 0) 
                                                {
                                                        
outputWindow.Write(symbol);
                                                        if (--free < 258) 
                                                        {
                                                                return true;
                                                        }
                                                }
                                                if (symbol < 257) 
                                                {
                                                        if (symbol < 0) 
                                                        {
                                                                return false;
                                                        } 
                                                        else 
                                                        {
                                                                /* symbol == 
256: end of block */
                                                                distTree = null;
                                                                litlenTree = 
null;
                                                                mode = 
DECODE_BLOCKS;
                                                                return true;
                                                        }
                                                }
                                                
                                                try 
                                                {
                                                        repLength = 
CPLENS[symbol - 257];
                                                        neededBits = 
CPLEXT[symbol - 257];
                                                } 
                                                catch (Exception) 
                                                {
                                                        throw new 
FormatException("Illegal rep length code");
                                                }
                                                goto case 
DECODE_HUFFMAN_LENBITS;/* fall through */
                                        case DECODE_HUFFMAN_LENBITS:
                                                if (neededBits > 0) 
                                                {
                                                        mode = 
DECODE_HUFFMAN_LENBITS;
                                                        int i = 
input.PeekBits(neededBits);
                                                        if (i < 0) 
                                                        {
                                                                return false;
                                                        }
                                                        
input.DropBits(neededBits);
                                                        repLength += i;
                                                }
                                                mode = DECODE_HUFFMAN_DIST;
                                                goto case 
DECODE_HUFFMAN_DIST;/* fall through */
                                        case DECODE_HUFFMAN_DIST:
                                                symbol = 
distTree.GetSymbol(input);
                                                if (symbol < 0) 
                                                {
                                                        return false;
                                                }
                                                try 
                                                {
                                                        repDist = 
CPDIST[symbol];
                                                        neededBits = 
CPDEXT[symbol];
                                                } 
                                                catch (Exception) 
                                                {
                                                        throw new 
FormatException("Illegal rep dist code");
                                                }
                                                
                                                goto case 
DECODE_HUFFMAN_DISTBITS;/* fall through */
                                        case DECODE_HUFFMAN_DISTBITS:
                                                if (neededBits > 0) 
                                                {
                                                        mode = 
DECODE_HUFFMAN_DISTBITS;
                                                        int i = 
input.PeekBits(neededBits);
                                                        if (i < 0) 
                                                        {
                                                                return false;
                                                        }
                                                        
input.DropBits(neededBits);
                                                        repDist += i;
                                                }
                                                outputWindow.Repeat(repLength, 
repDist);
                                                free -= repLength;
                                                mode = DECODE_HUFFMAN;
                                                break;
                                        default:
                                                throw new FormatException();
                                }
                        }
                        return true;
                }
                
                /// <summary>
                /// Decodes the adler checksum after the deflate stream.
                /// </summary>
                /// <returns>
                /// false if more input is needed.
                /// </returns>
                /// <exception cref="System.FormatException">
                /// DataFormatException, if checksum doesn't match.
                /// </exception>
                private bool DecodeChksum()
                {
                        while (neededBits > 0) 
                        {
                                int chkByte = input.PeekBits(8);
                                if (chkByte < 0) 
                                {
                                        return false;
                                }
                                input.DropBits(8);
                                readAdler = (readAdler << 8) | chkByte;
                                neededBits -= 8;
                        }
                        if ((int) adler.Value != readAdler) 
                        {
                                throw new FormatException("Adler chksum doesn't 
match: "
                                        + (int)adler.Value
                                        + " vs. " + readAdler);
                        }
                        mode = FINISHED;
                        return false;
                }
                
                /// <summary>
                /// Decodes the deflated stream.
                /// </summary>
                /// <returns>
                /// false if more input is needed, or if finished.
                /// </returns>
                /// <exception cref="System.FormatException">
                /// DataFormatException, if deflated stream is invalid.
                /// </exception>
                private bool Decode()
                {
                        switch (mode) 
                        {
                                case DECODE_HEADER:
                                        return DecodeHeader();
                                case DECODE_DICT:
                                        return DecodeDict();
                                case DECODE_CHKSUM:
                                        return DecodeChksum();
                                
                                case DECODE_BLOCKS:
                                        if (isLastBlock) 
                                        {
                                                if (nowrap) 
                                                {
                                                        mode = FINISHED;
                                                        return false;
                                                } 
                                                else 
                                                {
                                                        
input.SkipToByteBoundary();
                                                        neededBits = 32;
                                                        mode = DECODE_CHKSUM;
                                                        return true;
                                                }
                                        }
                                        
                                        int type = input.PeekBits(3);
                                        if (type < 0) 
                                        {
                                                return false;
                                        }
                                        input.DropBits(3);
                                        
                                        if ((type & 1) != 0) 
                                        {
                                                isLastBlock = true;
                                        }
                                switch (type >> 1) 
                                {
                                        case DeflaterConstants.STORED_BLOCK:
                                                input.SkipToByteBoundary();
                                                mode = DECODE_STORED_LEN1;
                                                break;
                                        case DeflaterConstants.STATIC_TREES:
                                                litlenTree = 
InflaterHuffmanTree.defLitLenTree;
                                                distTree = 
InflaterHuffmanTree.defDistTree;
                                                mode = DECODE_HUFFMAN;
                                                break;
                                        case DeflaterConstants.DYN_TREES:
                                                dynHeader = new 
InflaterDynHeader();
                                                mode = DECODE_DYN_HEADER;
                                                break;
                                        default:
                                                throw new 
FormatException("Unknown block type "+type);
                                }
                                        return true;
                                
                                case DECODE_STORED_LEN1: 
                                {
                                        if ((uncomprLen = input.PeekBits(16)) < 
0) 
                                        {
                                                return false;
                                        }
                                        input.DropBits(16);
                                        mode = DECODE_STORED_LEN2;
                                }
                                        goto case DECODE_STORED_LEN2; /* fall 
through */
                                case DECODE_STORED_LEN2: 
                                {
                                        int nlen = input.PeekBits(16);
                                        if (nlen < 0) 
                                        {
                                                return false;
                                        }
                                        input.DropBits(16);
                                        if (nlen != (uncomprLen ^ 0xffff)) 
                                        {
                                                throw new 
FormatException("broken uncompressed block");
                                        }
                                        mode = DECODE_STORED;
                                }
                                        goto case DECODE_STORED;/* fall through 
*/
                                case DECODE_STORED: 
                                {
                                        int more = 
outputWindow.CopyStored(input, uncomprLen);
                                        uncomprLen -= more;
                                        if (uncomprLen == 0) 
                                        {
                                                mode = DECODE_BLOCKS;
                                                return true;
                                        }
                                        return !input.IsNeedingInput;
                                }
                                
                                case DECODE_DYN_HEADER:
                                        if (!dynHeader.Decode(input)) 
                                        {
                                                return false;
                                        }
                                        
                                        litlenTree = 
dynHeader.BuildLitLenTree();
                                        distTree = dynHeader.BuildDistTree();
                                        mode = DECODE_HUFFMAN;
                                        goto case DECODE_HUFFMAN; /* fall 
through */
                                case DECODE_HUFFMAN:
                                case DECODE_HUFFMAN_LENBITS:
                                case DECODE_HUFFMAN_DIST:
                                case DECODE_HUFFMAN_DISTBITS:
                                        return DecodeHuffman();
                                case FINISHED:
                                        return false;
                                default:
                                        throw new FormatException();
                        }
                }
                        
                /// <summary>
                /// Sets the preset dictionary.  This should only be called, if
                /// needsDictionary() returns true and it should set the same
                /// dictionary, that was used for deflating.  The getAdler()
                /// function returns the checksum of the dictionary needed.
                /// </summary>
                /// <param name="buffer">
                /// the dictionary.
                /// </param>
                /// <exception cref="System.InvalidOperationException">
                /// if no dictionary is needed.
                /// </exception>
                /// <exception cref="System.ArgumentException">
                /// if the dictionary checksum is wrong.
                /// </exception>
                public void SetDictionary(byte[] buffer)
                {
                        SetDictionary(buffer, 0, buffer.Length);
                }
                
                /// <summary>
                /// Sets the preset dictionary.  This should only be called, if
                /// needsDictionary() returns true and it should set the same
                /// dictionary, that was used for deflating.  The getAdler()
                /// function returns the checksum of the dictionary needed.
                /// </summary>
                /// <param name="buffer">
                /// the dictionary.
                /// </param>
                /// <param name="off">
                /// the offset into buffer where the dictionary starts.
                /// </param>
                /// <param name="len">
                /// the length of the dictionary.
                /// </param>
                /// <exception cref="System.InvalidOperationException">
                /// if no dictionary is needed.
                /// </exception>
                /// <exception cref="System.ArgumentException">
                /// if the dictionary checksum is wrong.
                /// </exception>
                /// <exception cref="System.ArgumentOutOfRangeException">
                /// if the off and/or len are wrong.
                /// </exception>
                public void SetDictionary(byte[] buffer, int off, int len)
                {
                        if (!IsNeedingDictionary) 
                        {
                                throw new InvalidOperationException();
                        }
                        
                        adler.Update(buffer, off, len);
                        if ((int) adler.Value != readAdler) 
                        {
                                throw new ArgumentException("Wrong adler 
checksum");
                        }
                        adler.Reset();
                        outputWindow.CopyDict(buffer, off, len);
                        mode = DECODE_BLOCKS;
                }
                
                /// <summary>
                /// Sets the input.  This should only be called, if needsInput()
                /// returns true.
                /// </summary>
                /// <param name="buf">
                /// the input.
                /// </param>
                /// <exception cref="System.InvalidOperationException">
                /// if no input is needed.
                /// </exception>
                public void SetInput(byte[] buf)
                {
                        SetInput(buf, 0, buf.Length);
                }
                
                /// <summary>
                /// Sets the input.  This should only be called, if needsInput()
                /// returns true.
                /// </summary>
                /// <param name="buf">
                /// the input.
                /// </param>
                /// <param name="off">
                /// the offset into buffer where the input starts.
                /// </param>
                /// <param name="len">
                /// the length of the input.
                /// </param>
                /// <exception cref="System.InvalidOperationException">
                /// if no input is needed.
                /// </exception>
                /// <exception cref="System.ArgumentOutOfRangeException">
                /// if the off and/or len are wrong.
                /// </exception>
                public void SetInput(byte[] buf, int off, int len)
                {
                        input.SetInput(buf, off, len);
                        totalIn += len;
                }
                
                /// <summary>
                /// Inflates the compressed stream to the output buffer.  If 
this
                /// returns 0, you should check, whether needsDictionary(),
                /// needsInput() or finished() returns true, to determine why no
                /// further output is produced.
                /// </summary>
                /// <param name = "buf">
                /// the output buffer.
                /// </param>
                /// <returns>
                /// the number of bytes written to the buffer, 0 if no further
                /// output can be produced.
                /// </returns>
                /// <exception cref="System.ArgumentOutOfRangeException">
                /// if buf has length 0.
                /// </exception>
                /// <exception cref="System.FormatException">
                /// if deflated stream is invalid.
                /// </exception>
                public int Inflate(byte[] buf)
                {
                        return Inflate(buf, 0, buf.Length);
                }
                
                /// <summary>
                /// Inflates the compressed stream to the output buffer.  If 
this
                /// returns 0, you should check, whether needsDictionary(),
                /// needsInput() or finished() returns true, to determine why no
                /// further output is produced.
                /// </summary>
                /// <param name = "buf">
                /// the output buffer.
                /// </param>
                /// <param name = "off">
                /// the offset into buffer where the output should start.
                /// </param>
                /// <param name = "len">
                /// the maximum length of the output.
                /// </param>
                /// <returns>
                /// the number of bytes written to the buffer, 0 if no further 
output can be produced.
                /// </returns>
                /// <exception cref="System.ArgumentOutOfRangeException">
                /// if len is &lt;= 0.
                /// </exception>
                /// <exception cref="System.ArgumentOutOfRangeException">
                /// if the off and/or len are wrong.
                /// </exception>
                /// <exception cref="System.FormatException">
                /// if deflated stream is invalid.
                /// </exception>
                public int Inflate(byte[] buf, int off, int len)
                {
                        if (len < 0) 
                        {
                                throw new ArgumentOutOfRangeException("len < 
0");
                        }
                        // Special case: len may be zero
                        if (len == 0) 
                        {
                                return 0;
                        }
                        /*                      // Check for correct buff, off, 
len triple
                                                if (off < 0 || off + len >= 
buf.Length) {
                                                        throw new 
ArgumentException("off/len outside buf bounds");
                                                }*/
                        int count = 0;
                        int more;
                        do 
                        {
                                if (mode != DECODE_CHKSUM) 
                                {
                                        /* Don't give away any output, if we 
are waiting for the
                                        * checksum in the input stream.
                                        *
                                        * With this trick we have always:
                                        *   needsInput() and not finished()
                                        *   implies more output can be produced.
                                        */
                                        more = outputWindow.CopyOutput(buf, 
off, len);
                                        adler.Update(buf, off, more);
                                        off += more;
                                        count += more;
                                        totalOut += more;
                                        len -= more;
                                        if (len == 0) 
                                        {
                                                return count;
                                        }
                                }
                        } while (Decode() || (outputWindow.GetAvailable() > 0 &&
                                mode != DECODE_CHKSUM));
                        return count;
                }
                
                /// <summary>
                /// Returns true, if the input buffer is empty.
                /// You should then call setInput(). 
                /// NOTE: This method also returns true when the stream is 
finished.
                /// </summary>
                public bool IsNeedingInput 
                {
                        get 
                        {
                                return input.IsNeedingInput;
                        }
                }
                
                /// <summary>
                /// Returns true, if a preset dictionary is needed to inflate 
the input.
                /// </summary>
                public bool IsNeedingDictionary 
                {
                        get 
                        {
                                return mode == DECODE_DICT && neededBits == 0;
                        }
                }
                
                /// <summary>
                /// Returns true, if the inflater has finished.  This means, 
that no
                /// input is needed and no output can be produced.
                /// </summary>
                public bool IsFinished 
                {
                        get 
                        {
                                return mode == FINISHED && 
outputWindow.GetAvailable() == 0;
                        }
                }
                
                /// <summary>
                /// Gets the adler checksum.  This is either the checksum of all
                /// uncompressed bytes returned by inflate(), or if 
needsDictionary()
                /// returns true (and thus no output was yet produced) this is 
the
                /// adler checksum of the expected dictionary.
                /// </summary>
                /// <returns>
                /// the adler checksum.
                /// </returns>
                public int Adler 
                {
                        get 
                        {
                                return IsNeedingDictionary ? readAdler : (int) 
adler.Value;
                        }
                }
                
                /// <summary>
                /// Gets the total number of output bytes returned by inflate().
                /// </summary>
                /// <returns>
                /// the total number of output bytes.
                /// </returns>
                public int TotalOut 
                {
                        get 
                        {
                                return totalOut;
                        }
                }
                
                /// <summary>
                /// Gets the total number of processed compressed input bytes.
                /// </summary>
                /// <returns>
                /// the total number of bytes of processed input bytes.
                /// </returns>
                public int TotalIn 
                {
                        get 
                        {
                                return totalIn - RemainingInput;
                        }
                }
                
                /// <summary>
                /// Gets the number of unprocessed input.  Useful, if the end 
of the
                /// stream is reached and you want to further process the bytes 
after
                /// the deflate stream.
                /// </summary>
                /// <returns>
                /// the number of bytes of the input which were not processed.
                /// </returns>
                public int RemainingInput 
                {
                        get 
                        {
                                return input.AvailableBytes;
                        }
                }
        }
}

--- NEW FILE: Deflater.cs ---
// Deflater.cs
// Copyright (C) 2001 Mike Krueger
//
// This file was translated from java, it was part of the GNU Classpath
// Copyright (C) 2001 Free Software Foundation, Inc.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
//
// Linking this library statically or dynamically with other modules is
// making a combined work based on this library.  Thus, the terms and
// conditions of the GNU General Public License cover the whole
// combination.
// 
// As a special exception, the copyright holders of this library give you
// permission to link this library with independent modules to produce an
// executable, regardless of the license terms of these independent
// modules, and to copy and distribute the resulting executable under
// terms of your choice, provided that you also meet, for each linked
// independent module, the terms and conditions of the license of that
// module.  An independent module is a module which is not derived from
// or based on this library.  If you modify this library, you may extend
// this exception to your version of the library, but you are not
// obligated to do so.  If you do not wish to do so, delete this
// exception statement from your version.

using System;

namespace ICSharpCode.SharpZipLib.Zip.Compression 
{
        
        /// <summary>
        /// This is the Deflater class.  The deflater class compresses input
        /// with the deflate algorithm described in RFC 1951.  It has several
        /// compression levels and three different strategies described below.
        ///
        /// This class is <i>not</i> thread safe.  This is inherent in the API, 
due
        /// to the split of deflate and setInput.
        /// 
        /// author of the original java version : Jochen Hoenicke
        /// </summary>
        public class Deflater
        {
                /// <summary>
                /// The best and slowest compression level.  This tries to find 
very
                /// long and distant string repetitions.
                /// </summary>
                public static  int BEST_COMPRESSION = 9;
                
                /// <summary>
                /// The worst but fastest compression level.
                /// </summary>
                public static  int BEST_SPEED = 1;
                
                /// <summary>
                /// The default compression level.
                /// </summary>
                public static  int DEFAULT_COMPRESSION = -1;
                
                /// <summary>
                /// This level won't compress at all but output uncompressed 
blocks.
                /// </summary>
                public static  int NO_COMPRESSION = 0;
                                
                /// <summary>
                /// The compression method.  This is the only method supported 
so far.
                /// There is no need to use this constant at all.
                /// </summary>
                public static  int DEFLATED = 8;
                
                /*
                * The Deflater can do the following state transitions:
                        *
                        * (1) -> INIT_STATE   ----> INIT_FINISHING_STATE ---.
                        *        /  | (2)      (5)                         |
                        *       /   v          (5)                         |
                        *   (3)| SETDICT_STATE ---> SETDICT_FINISHING_STATE |(3)
                        *       \   | (3)                 |        ,-------'
                        *        |  |                     | (3)   /
                        *        v  v          (5)        v      v
                        * (1) -> BUSY_STATE   ----> FINISHING_STATE
                        *                                | (6)
                        *                                v
                        *                           FINISHED_STATE
                        *    \_____________________________________/
                        *          | (7)
                        *          v
                        *        CLOSED_STATE
                        *
                        * (1) If we should produce a header we start in 
INIT_STATE, otherwise
                        *     we start in BUSY_STATE.
                        * (2) A dictionary may be set only when we are in 
INIT_STATE, then
                        *     we change the state as indicated.
                        * (3) Whether a dictionary is set or not, on the first 
call of deflate
                        *     we change to BUSY_STATE.
                        * (4) -- intentionally left blank -- :)
                        * (5) FINISHING_STATE is entered, when flush() is 
called to indicate that
                        *     there is no more INPUT.  There are also states 
indicating, that
                        *     the header wasn't written yet.
                        * (6) FINISHED_STATE is entered, when everything has 
been flushed to the
                        *     internal pending output buffer.
                        * (7) At any time (7)
                        *
                        */
                        
                private static  int IS_SETDICT              = 0x01;
                private static  int IS_FLUSHING             = 0x04;
                private static  int IS_FINISHING            = 0x08;
                
                private static  int INIT_STATE              = 0x00;
                private static  int SETDICT_STATE           = 0x01;
                //              private static  int INIT_FINISHING_STATE    = 
0x08;
                //              private static  int SETDICT_FINISHING_STATE = 
0x09;
                private static  int BUSY_STATE              = 0x10;
                private static  int FLUSHING_STATE          = 0x14;
                private static  int FINISHING_STATE         = 0x1c;
                private static  int FINISHED_STATE          = 0x1e;
                private static  int CLOSED_STATE            = 0x7f;
                
                /// <summary>
                /// Compression level.
                /// </summary>
                private int level;
                
                /// <summary>
                /// should we include a header.
                /// </summary>
                private bool noHeader;
                
                //              /// <summary>
                //              /// Compression strategy.
                //              /// </summary>
                //              private int strategy;
                
                /// <summary>
                /// The current state.
                /// </summary>
                private int state;
                
                /// <summary>
                /// The total bytes of output written.
                /// </summary>
                private int totalOut;
                
                /// <summary>
                /// The pending output.
                /// </summary>
                private DeflaterPending pending;
                
                /// <summary>
                /// The deflater engine.
                /// </summary>
                private DeflaterEngine engine;
                
                /// <summary>
                /// Creates a new deflater with default compression level.
                /// </summary>
                public Deflater() : this(DEFAULT_COMPRESSION, false)
                {
                        
                }
                
                /// <summary>
                /// Creates a new deflater with given compression level.
                /// </summary>
                /// <param name="lvl">
                /// the compression level, a value between NO_COMPRESSION
                /// and BEST_COMPRESSION, or DEFAULT_COMPRESSION.
                /// </param>
                /// <exception cref="System.ArgumentOutOfRangeException">if lvl 
is out of range.</exception>
                public Deflater(int lvl) : this(lvl, false)
                {
                        
                }
                
                /// <summary>
                /// Creates a new deflater with given compression level.
                /// </summary>
                /// <param name="lvl">
                /// the compression level, a value between NO_COMPRESSION
                /// and BEST_COMPRESSION.
                /// </param>
                /// <param name="nowrap">
                /// true, if we should suppress the deflate header at the
                /// beginning and the adler checksum at the end of the output.  
This is
                /// useful for the GZIP format.
                /// </param>
                /// <exception cref="System.ArgumentOutOfRangeException">if lvl 
is out of range.</exception>
                public Deflater(int lvl, bool nowrap)
                {
                        if (lvl == DEFAULT_COMPRESSION) 
                        {
                                lvl = 6;
                        } 
                        else if (lvl < NO_COMPRESSION || lvl > 
BEST_COMPRESSION) 
                        {
                                throw new ArgumentOutOfRangeException("lvl");
                        }
                        
                        pending = new DeflaterPending();
                        engine = new DeflaterEngine(pending);
                        this.noHeader = nowrap;
                        SetStrategy(DeflateStrategy.Default);
                        SetLevel(lvl);
                        Reset();
                }
                
                
                /// <summary>
                /// Resets the deflater.  The deflater acts afterwards as if it 
was
                /// just created with the same compression level and strategy 
as it
                /// had before.
                /// </summary>
                public void Reset()
                {
                        state = (noHeader ? BUSY_STATE : INIT_STATE);
                        totalOut = 0;
                        pending.Reset();
                        engine.Reset();
                }
                
                /// <summary>
                /// Gets the current adler checksum of the data that was 
processed so far.
                /// </summary>
                public int Adler 
                {
                        get 
                        {
                                return engine.Adler;
                        }
                }
                
                /// <summary>
                /// Gets the number of input bytes processed so far.
                /// </summary>
                public int TotalIn 
                {
                        get 
                        {
                                return engine.TotalIn;
                        }
                }
                
                /// <summary>
                /// Gets the number of output bytes so far.
                /// </summary>
                public int TotalOut 
                {
                        get 
                        {
                                return totalOut;
                        }
                }
                
                /// <summary>
                /// Flushes the current input block.  Further calls to 
deflate() will
                /// produce enough output to inflate everything in the current 
input
                /// block.  This is not part of Sun's JDK so I have made it 
package
                /// private.  It is used by DeflaterOutputStream to implement
                /// flush().
                /// </summary>
                public void Flush() 
                {
                        state |= IS_FLUSHING;
                }
                
                /// <summary>
                /// Finishes the deflater with the current input block.  It is 
an error
                /// to give more input after this method was called.  This 
method must
                /// be called to force all bytes to be flushed.
                /// </summary>
                public void Finish() 
                {
                        state |= IS_FLUSHING | IS_FINISHING;
                }
                
                /// <summary>
                /// Returns true if the stream was finished and no more output 
bytes
                /// are available.
                /// </summary>
                public bool IsFinished 
                {
                        get 
                        {
                                return state == FINISHED_STATE && 
pending.IsFlushed;
                        }
                }
                
                /// <summary>
                /// Returns true, if the input buffer is empty.
                /// You should then call setInput(). 
                /// NOTE: This method can also return true when the stream
                /// was finished.
                /// </summary>
                public bool IsNeedingInput 
                {
                        get 
                        {
                                return engine.NeedsInput();
                        }
                }
                
                /// <summary>
                /// Sets the data which should be compressed next.  This should 
be only
                /// called when needsInput indicates that more input is needed.
                /// If you call setInput when needsInput() returns false, the
                /// previous input that is still pending will be thrown away.
                /// The given byte array should not be changed, before 
needsInput() returns
                /// true again.
                /// This call is equivalent to <code>setInput(input, 0, 
input.length)</code>.
                /// </summary>
                /// <param name="input">
                /// the buffer containing the input data.
                /// </param>
                /// <exception cref="System.InvalidOperationException">
                /// if the buffer was finished() or ended().
                /// </exception>
                public void SetInput(byte[] input)
                {
                        SetInput(input, 0, input.Length);
                }
                
                /// <summary>
                /// Sets the data which should be compressed next.  This should 
be
                /// only called when needsInput indicates that more input is 
needed.
                /// The given byte array should not be changed, before 
needsInput() returns
                /// true again.
                /// </summary>
                /// <param name="input">
                /// the buffer containing the input data.
                /// </param>
                /// <param name="off">
                /// the start of the data.
                /// </param>
                /// <param name="len">
                /// the length of the data.
                /// </param>
                /// <exception cref="System.InvalidOperationException">
                /// if the buffer was finished() or ended() or if previous 
input is still pending.
                /// </exception>
                public void SetInput(byte[] input, int off, int len)
                {
                        if ((state & IS_FINISHING) != 0) 
                        {
                                throw new 
InvalidOperationException("finish()/end() already called");
                        }
                        engine.SetInput(input, off, len);
                }
                
                /// <summary>
                /// Sets the compression level.  There is no guarantee of the 
exact
                /// position of the change, but if you call this when 
needsInput is
                /// true the change of compression level will occur somewhere 
near
                /// before the end of the so far given input.
                /// </summary>
                /// <param name="lvl">
                /// the new compression level.
                /// </param>
                public void SetLevel(int lvl)
                {
                        if (lvl == DEFAULT_COMPRESSION) 
                        {
                                lvl = 6;
                        } 
                        else if (lvl < NO_COMPRESSION || lvl > 
BEST_COMPRESSION) 
                        {
                                throw new ArgumentOutOfRangeException("lvl");
                        }
                        
                        
                        if (level != lvl) 
                        {
                                level = lvl;
                                engine.SetLevel(lvl);
                        }
                }
                
                /// <summary>
                /// Sets the compression strategy. Strategy is one of
                /// DEFAULT_STRATEGY, HUFFMAN_ONLY and FILTERED.  For the exact
                /// position where the strategy is changed, the same as for
                /// setLevel() applies.
                /// </summary>
                /// <param name="stgy">
                /// the new compression strategy.
                /// </param>
                public void SetStrategy(DeflateStrategy stgy)
                {
                        engine.Strategy = stgy;
                }
                
                /// <summary>
                /// Deflates the current input block to the given array.  It 
returns
                /// the number of bytes compressed, or 0 if either
                /// needsInput() or finished() returns true or length is zero.
                /// </summary>
                /// <param name="output">
                /// the buffer where to write the compressed data.
                /// </param>
                public int Deflate(byte[] output)
                {
                        return Deflate(output, 0, output.Length);
                }
                
                /// <summary>
                /// Deflates the current input block to the given array.  It 
returns
                /// the number of bytes compressed, or 0 if either
                /// needsInput() or finished() returns true or length is zero.
                /// </summary>
                /// <param name="output">
                /// the buffer where to write the compressed data.
                /// </param>
                /// <param name="offset">
                /// the offset into the output array.
                /// </param>
                /// <param name="length">
                /// the maximum number of bytes that may be written.
                /// </param>
                /// <exception cref="System.InvalidOperationException">
                /// if end() was called.
                /// </exception>
                /// <exception cref="System.ArgumentOutOfRangeException">
                /// if offset and/or length don't match the array length.
                /// </exception>
                public int Deflate(byte[] output, int offset, int length)
                {
                        int origLength = length;
                        
                        if (state == CLOSED_STATE) 
                        {
                                throw new InvalidOperationException("Deflater 
closed");
                        }
                        
                        if (state < BUSY_STATE) 
                        {
                                /* output header */
                                int header = (DEFLATED +
                                        ((DeflaterConstants.MAX_WBITS - 8) << 
4)) << 8;
                                int level_flags = (level - 1) >> 1;
                                if (level_flags < 0 || level_flags > 3) 
                                {
                                        level_flags = 3;
                                }
                                header |= level_flags << 6;
                                if ((state & IS_SETDICT) != 0) 
                                {
                                        /* Dictionary was set */
                                        header |= DeflaterConstants.PRESET_DICT;
                                }
                                header += 31 - (header % 31);
                                
                                
                                pending.WriteShortMSB(header);
                                if ((state & IS_SETDICT) != 0) 
                                {
                                        int chksum = engine.Adler;
                                        engine.ResetAdler();
                                        pending.WriteShortMSB(chksum >> 16);
                                        pending.WriteShortMSB(chksum & 0xffff);
                                }
                                
                                state = BUSY_STATE | (state & (IS_FLUSHING | 
IS_FINISHING));
                        }
                        
                        for (;;) 
                        {
                                int count = pending.Flush(output, offset, 
length);
                                offset   += count;
                                totalOut += count;
                                length   -= count;
                                
                                if (length == 0 || state == FINISHED_STATE) 
                                {
                                        break;
                                }
                                
                                if (!engine.Deflate((state & IS_FLUSHING) != 0, 
(state & IS_FINISHING) != 0)) 
                                {
                                        if (state == BUSY_STATE) 
                                        {
                                                /* We need more input now */
                                                return origLength - length;
                                        } 
                                        else if (state == FLUSHING_STATE) 
                                        {
                                                if (level != NO_COMPRESSION) 
                                                {
                                                        /* We have to supply 
some lookahead.  8 bit lookahead
                                                         * are needed by the 
zlib inflater, and we must fill
                                                         * the next byte, so 
that all bits are flushed.
                                                         */
                                                        int neededbits = 8 + 
((-pending.BitCount) & 7);
                                                        while (neededbits > 0) 
                                                        {
                                                                /* write a 
static tree block consisting solely of
                                                                 * an EOF:
                                                                 */
                                                                
pending.WriteBits(2, 10);
                                                                neededbits -= 
10;
                                                        }
                                                }
                                                state = BUSY_STATE;
                                        } 
                                        else if (state == FINISHING_STATE) 
                                        {
                                                pending.AlignToByte();
                                                /* We have completed the stream 
*/
                                                if (!noHeader) 
                                                {
                                                        int adler = 
engine.Adler;
                                                        
pending.WriteShortMSB(adler >> 16);
                                                        
pending.WriteShortMSB(adler & 0xffff);
                                                }
                                                state = FINISHED_STATE;
                                        }
                                }
                        }
                        return origLength - length;
                }
                
                /// <summary>
                /// Sets the dictionary which should be used in the deflate 
process.
                /// This call is equivalent to <code>setDictionary(dict, 0, 
dict.Length)</code>.
                /// </summary>
                /// <param name="dict">
                /// the dictionary.
                /// </param>
                /// <exception cref="System.InvalidOperationException">
                /// if setInput () or deflate () were already called or another 
dictionary was already set.
                /// </exception>
                public void SetDictionary(byte[] dict)
                {
                        SetDictionary(dict, 0, dict.Length);
                }
                
                /// <summary>
                /// Sets the dictionary which should be used in the deflate 
process.
                /// The dictionary should be a byte array containing strings 
that are
                /// likely to occur in the data which should be compressed.  The
                /// dictionary is not stored in the compressed output, only a
                /// checksum.  To decompress the output you need to supply the 
same
                /// dictionary again.
                /// </summary>
                /// <param name="dict">
                /// the dictionary.
                /// </param>
                /// <param name="offset">
                /// an offset into the dictionary.
                /// </param>
                /// <param name="length">
                /// the length of the dictionary.
                /// </param>
                /// <exception cref="System.InvalidOperationException">
                /// if setInput () or deflate () were already called or another 
dictionary was already set.
                /// </exception>
                public void SetDictionary(byte[] dict, int offset, int length)
                {
                        if (state != INIT_STATE) 
                        {
                                throw new InvalidOperationException();
                        }
                        
                        state = SETDICT_STATE;
                        engine.SetDictionary(dict, offset, length);
                }
        }
}

--- NEW FILE: DeflaterHuffman.cs ---
// DeflaterHuffman.cs
// Copyright (C) 2001 Mike Krueger
//
// This file was translated from java, it was part of the GNU Classpath
// Copyright (C) 2001 Free Software Foundation, Inc.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
//
// Linking this library statically or dynamically with other modules is
// making a combined work based on this library.  Thus, the terms and
// conditions of the GNU General Public License cover the whole
// combination.
// 
// As a special exception, the copyright holders of this library give you
// permission to link this library with independent modules to produce an
// executable, regardless of the license terms of these independent
// modules, and to copy and distribute the resulting executable under
// terms of your choice, provided that you also meet, for each linked
// independent module, the terms and conditions of the license of that
// module.  An independent module is a module which is not derived from
// or based on this library.  If you modify this library, you may extend
// this exception to your version of the library, but you are not
// obligated to do so.  If you do not wish to do so, delete this
// exception statement from your version.

using System;

namespace ICSharpCode.SharpZipLib.Zip.Compression 
{
        
        /// <summary>
        /// This is the DeflaterHuffman class.
        /// 
        /// This class is <i>not</i> thread safe.  This is inherent in the API, 
due
        /// to the split of deflate and setInput.
        /// 
        /// author of the original java version : Jochen Hoenicke
        /// </summary>
        public class DeflaterHuffman
        {
                private static  int BUFSIZE = 1 << 
(DeflaterConstants.DEFAULT_MEM_LEVEL + 6);
                private static  int LITERAL_NUM = 286;
                private static  int DIST_NUM = 30;
                private static  int BITLEN_NUM = 19;
                private static  int REP_3_6    = 16;
                private static  int REP_3_10   = 17;
                private static  int REP_11_138 = 18;
                private static  int EOF_SYMBOL = 256;
                private static  int[] BL_ORDER = { 16, 17, 18, 0, 8, 7, 9, 6, 
10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
                
                private static byte[] bit4Reverse = {
                                                                                
                0,
                                                                                
                8,
                                                                                
                4,
                                                                                
                12,
                                                                                
                2,
                                                                                
                10,
                                                                                
                6,
                                                                                
                14,
                                                                                
                1,
                                                                                
                9,
                                                                                
                5,
                                                                                
                13,
                                                                                
                3,
                                                                                
                11,
                                                                                
                7,
                                                                                
                15
                                                                                
        };
                
                
                public class Tree 
                {
                        public short[] freqs;
                        public short[] codes;
                        public byte[]  length;
                        public int[]   bl_counts;
                        public int     minNumCodes, numCodes;
                        public int     maxLength;
                        DeflaterHuffman dh;
                        
                        public Tree(DeflaterHuffman dh, int elems, int 
minCodes, int maxLength) 
                        {
                                this.dh =  dh;
                                this.minNumCodes = minCodes;
                                this.maxLength  = maxLength;
                                freqs  = new short[elems];
                                bl_counts = new int[maxLength];
                        }
                        
                        public void Reset() 
                        {
                                for (int i = 0; i < freqs.Length; i++) 
                                {
                                        freqs[i] = 0;
                                }
                                codes = null;
                                length = null;
                        }
                        
                        public void WriteSymbol(int code)
                        {
                                //                              if 
(DeflaterConstants.DEBUGGING) {
                                //                                      
freqs[code]--;
                                //                                      //      
  Console.Write("writeSymbol("+freqs.length+","+code+"): ");
                                //                              }
                                dh.pending.WriteBits(codes[code] & 0xffff, 
length[code]);
                        }
                        
                        public void CheckEmpty()
                        {
                                bool empty = true;
                                for (int i = 0; i < freqs.Length; i++) 
                                {
                                        if (freqs[i] != 0) 
                                        {
                                                
//Console.WriteLine("freqs["+i+"] == "+freqs[i]);
                                                empty = false;
                                        }
                                }
                                if (!empty) 
                                {
                                        throw new Exception();
                                }
                                //Console.WriteLine("checkEmpty suceeded!");
                        }
                        
                        public void SetStaticCodes(short[] stCodes, byte[] 
stLength)
                        {
                                codes = stCodes;
                                length = stLength;
                        }
                        
                        public void BuildCodes() 
                        {
                                int numSymbols = freqs.Length;
                                int[] nextCode = new int[maxLength];
                                int code = 0;
                                codes = new short[freqs.Length];
                                
                                //                              if 
(DeflaterConstants.DEBUGGING) {
                                //                                      
//Console.WriteLine("buildCodes: "+freqs.Length);
                                //                              }
                                
                                for (int bits = 0; bits < maxLength; bits++) 
                                {
                                        nextCode[bits] = code;
                                        code += bl_counts[bits] << (15 - bits);
                                        //                                      
if (DeflaterConstants.DEBUGGING) {
                                        //                                      
        //Console.WriteLine("bits: "+(bits+1)+" count: "+bl_counts[bits]
                                        //                                      
                          +" nextCode: "+code); // HACK : Integer.toHexString(
                                        //                                      
}
                                }
                                if (DeflaterConstants.DEBUGGING && code != 
65536) 
                                {
                                        throw new Exception("Inconsistent 
bl_counts!");
                                }
                                
                                for (int i=0; i < numCodes; i++) 
                                {
                                        int bits = length[i];
                                        if (bits > 0) 
                                        {
                                                //                              
                if (DeflaterConstants.DEBUGGING) {
                                                //                              
                                //Console.WriteLine("codes["+i+"] = rev(" + 
nextCode[bits-1]+")," // HACK : Integer.toHexString(
                                                //                              
                                                  +bits);
                                                //                              
                }
                                                codes[i] = 
BitReverse(nextCode[bits-1]);
                                                nextCode[bits-1] += 1 << (16 - 
bits);
                                        }
                                }
                        }
                        
                        private void BuildLength(int[] childs)
                        {
                                this.length = new byte [freqs.Length];
                                int numNodes = childs.Length / 2;
                                int numLeafs = (numNodes + 1) / 2;
                                int overflow = 0;
                                
                                for (int i = 0; i < maxLength; i++) 
                                {
                                        bl_counts[i] = 0;
                                }
                                
                                /* First calculate optimal bit lengths */
                                int[] lengths = new int[numNodes];
                                lengths[numNodes-1] = 0;
                                
                                for (int i = numNodes - 1; i >= 0; i--) 
                                {
                                        if (childs[2*i+1] != -1) 
                                        {
                                                int bitLength = lengths[i] + 1;
                                                if (bitLength > maxLength) 
                                                {
                                                        bitLength = maxLength;
                                                        overflow++;
                                                }
                                                lengths[childs[2*i]] = 
lengths[childs[2*i+1]] = bitLength;
                                        } 
                                        else 
                                        {
                                                /* A leaf node */
                                                int bitLength = lengths[i];
                                                bl_counts[bitLength - 1]++;
                                                this.length[childs[2*i]] = 
(byte) lengths[i];
                                        }
                                }
                                
                                //                              if 
(DeflaterConstants.DEBUGGING) {
                                //                                      
//Console.WriteLine("Tree "+freqs.Length+" lengths:");
                                //                                      for 
(int i=0; i < numLeafs; i++) {
                                //                                              
//Console.WriteLine("Node "+childs[2*i]+" freq: "+freqs[childs[2*i]]
                                //                                              
                  + " len: "+length[childs[2*i]]);
                                //                                      }
                                //                              }
                                
                                if (overflow == 0) 
                                {
                                        return;
                                }
                                
                                int incrBitLen = maxLength - 1;
                                do 
                                {
                                        /* Find the first bit length which 
could increase: */
                                while (bl_counts[--incrBitLen] == 0)
                                        ;
                                        
                                        /* Move this node one down and remove a 
corresponding
                                        * amount of overflow nodes.
                                        */
                                        do 
                                        {
                                                bl_counts[incrBitLen]--;
                                                bl_counts[++incrBitLen]++;
                                                overflow -= 1 << (maxLength - 1 
- incrBitLen);
                                        } while (overflow > 0 && incrBitLen < 
maxLength - 1);
                                } while (overflow > 0);
                                
                                /* We may have overshot above.  Move some nodes 
from maxLength to
                                * maxLength-1 in that case.
                                */
                                bl_counts[maxLength-1] += overflow;
                                bl_counts[maxLength-2] -= overflow;
                                
                                /* Now recompute all bit lengths, scanning in 
increasing
                                * frequency.  It is simpler to reconstruct all 
lengths instead of
                                * fixing only the wrong ones. This idea is 
taken from 'ar'
                                * written by Haruhiko Okumura.
                                *
                                * The nodes were inserted with decreasing 
frequency into the childs
                                * array.
                                */
                                int nodePtr = 2 * numLeafs;
                                for (int bits = maxLength; bits != 0; bits--) 
                                {
                                        int n = bl_counts[bits-1];
                                        while (n > 0) 
                                        {
                                                int childPtr = 
2*childs[nodePtr++];
                                                if (childs[childPtr + 1] == -1) 
                                                {
                                                        /* We found another 
leaf */
                                                        
length[childs[childPtr]] = (byte) bits;
                                                        n--;
                                                }
                                        }
                                }
                                //                              if 
(DeflaterConstants.DEBUGGING) {
                                //                                      
//Console.WriteLine("*** After overflow elimination. ***");
                                //                                      for 
(int i=0; i < numLeafs; i++) {
                                //                                              
//Console.WriteLine("Node "+childs[2*i]+" freq: "+freqs[childs[2*i]]
                                //                                              
                  + " len: "+length[childs[2*i]]);
                                //                                      }
                                //                              }
                        }
                        
                        public void BuildTree()
                        {
                                int numSymbols = freqs.Length;
                                
                                /* heap is a priority queue, sorted by 
frequency, least frequent
                                * nodes first.  The heap is a binary tree, with 
the property, that
                                * the parent node is smaller than both child 
nodes.  This assures
                                * that the smallest node is the first parent.
                                *
                                * The binary tree is encoded in an array:  0 is 
root node and
                                * the nodes 2*n+1, 2*n+2 are the child nodes of 
node n.
                                */
                                int[] heap = new int[numSymbols];
                                int heapLen = 0;
                                int maxCode = 0;
                                for (int n = 0; n < numSymbols; n++) 
                                {
                                        int freq = freqs[n];
                                        if (freq != 0) 
                                        {
                                                /* Insert n into heap */
                                                int pos = heapLen++;
                                                int ppos;
                                                while (pos > 0 && 
freqs[heap[ppos = (pos - 1) / 2]] > freq) 
                                                {
                                                        heap[pos] = heap[ppos];
                                                        pos = ppos;
                                                }
                                                heap[pos] = n;
                                                
                                                maxCode = n;
                                        }
                                }
                                
                                /* We could encode a single literal with 0 bits 
but then we
                                * don't see the literals.  Therefore we force 
at least two
                                * literals to avoid this case.  We don't care 
about order in
                                * this case, both literals get a 1 bit code.
                                */
                                while (heapLen < 2) 
                                {
                                        int node = maxCode < 2 ? ++maxCode : 0;
                                        heap[heapLen++] = node;
                                }
                                
                                numCodes = Math.Max(maxCode + 1, minNumCodes);
                                
                                int numLeafs = heapLen;
                                int[] childs = new int[4*heapLen - 2];
                                int[] values = new int[2*heapLen - 1];
                                int numNodes = numLeafs;
                                for (int i = 0; i < heapLen; i++) 
                                {
                                        int node = heap[i];
                                        childs[2*i]   = node;
                                        childs[2*i+1] = -1;
                                        values[i] = freqs[node] << 8;
                                        heap[i] = i;
                                }
                                
                                /* Construct the Huffman tree by repeatedly 
combining the least two
                                * frequent nodes.
                                */
                                do 
                                {
                                        int first = heap[0];
                                        int last  = heap[--heapLen];
                                        
                                        /* Propagate the hole to the leafs of 
the heap */
                                        int ppos = 0;
                                        int path = 1;
                                while (path < heapLen) 
                                {
                                        if (path + 1 < heapLen && 
values[heap[path]] > values[heap[path+1]]) 
                                        {
                                                path++;
                                        }
                                                
                                        heap[ppos] = heap[path];
                                        ppos = path;
                                        path = path * 2 + 1;
                                }
                                        
                                        /* Now propagate the last element down 
along path.  Normally
                                        * it shouldn't go too deep.
                                        */
                                        int lastVal = values[last];
                                while ((path = ppos) > 0 && values[heap[ppos = 
(path - 1)/2]] > lastVal) 
                                {
                                        heap[path] = heap[ppos];
                                }
                                        heap[path] = last;
                                        
                                        
                                        int second = heap[0];
                                        
                                        /* Create a new node father of first 
and second */
                                        last = numNodes++;
                                        childs[2*last] = first;
                                        childs[2*last+1] = second;
                                        int mindepth = Math.Min(values[first] & 
0xff, values[second] & 0xff);
                                        values[last] = lastVal = values[first] 
+ values[second] - mindepth + 1;
                                        
                                        /* Again, propagate the hole to the 
leafs */
                                        ppos = 0;
                                        path = 1;
                                while (path < heapLen) 
                                {
                                        if (path + 1 < heapLen && 
values[heap[path]] > values[heap[path+1]]) 
                                        {
                                                path++;
                                        }
                                                
                                        heap[ppos] = heap[path];
                                        ppos = path;
                                        path = ppos * 2 + 1;
                                }
                                        
                                        /* Now propagate the new element down 
along path */
                                while ((path = ppos) > 0 && values[heap[ppos = 
(path - 1)/2]] > lastVal) 
                                {
                                        heap[path] = heap[ppos];
                                }
                                        heap[path] = last;
                                } while (heapLen > 1);
                                
                                if (heap[0] != childs.Length / 2 - 1) 
                                {
                                        throw new Exception("Weird!");
                                }
                                BuildLength(childs);
                        }
                        
                        public int GetEncodedLength()
                        {
                                int len = 0;
                                for (int i = 0; i < freqs.Length; i++) 
                                {
                                        len += freqs[i] * length[i];
                                }
                                return len;
                        }
                        
                        public void CalcBLFreq(Tree blTree) 
                        {
                                int max_count;               /* max repeat 
count */
                                int min_count;               /* min repeat 
count */
                                int count;                   /* repeat count of 
the current code */
                                int curlen = -1;             /* length of 
current code */
                                
                                int i = 0;
                                while (i < numCodes) 
                                {
                                        count = 1;
                                        int nextlen = length[i];
                                        if (nextlen == 0) 
                                        {
                                                max_count = 138;
                                                min_count = 3;
                                        } 
                                        else 
                                        {
                                                max_count = 6;
                                                min_count = 3;
                                                if (curlen != nextlen) 
                                                {
                                                        blTree.freqs[nextlen]++;
                                                        count = 0;
                                                }
                                        }
                                        curlen = nextlen;
                                        i++;
                                        
                                        while (i < numCodes && curlen == 
length[i]) 
                                        {
                                                i++;
                                                if (++count >= max_count) 
                                                {
                                                        break;
                                                }
                                        }
                                        
                                        if (count < min_count) 
                                        {
                                                blTree.freqs[curlen] += 
(short)count;
                                        } 
                                        else if (curlen != 0) 
                                        {
                                                blTree.freqs[REP_3_6]++;
                                        } 
                                        else if (count <= 10) 
                                        {
                                                blTree.freqs[REP_3_10]++;
                                        } 
                                        else 
                                        {
                                                blTree.freqs[REP_11_138]++;
                                        }
                                }
                        }
                        
                        public void WriteTree(Tree blTree)
                        {
                                int max_count;               /* max repeat 
count */
                                int min_count;               /* min repeat 
count */
                                int count;                   /* repeat count of 
the current code */
                                int curlen = -1;             /* length of 
current code */
                                
                                int i = 0;
                                while (i < numCodes) 
                                {
                                        count = 1;
                                        int nextlen = length[i];
                                        if (nextlen == 0) 
                                        {
                                                max_count = 138;
                                                min_count = 3;
                                        } 
                                        else 
                                        {
                                                max_count = 6;
                                                min_count = 3;
                                                if (curlen != nextlen) 
                                                {
                                                        
blTree.WriteSymbol(nextlen);
                                                        count = 0;
                                                }
                                        }
                                        curlen = nextlen;
                                        i++;
                                        
                                        while (i < numCodes && curlen == 
length[i]) 
                                        {
                                                i++;
                                                if (++count >= max_count) 
                                                {
                                                        break;
                                                }
                                        }
                                        
                                        if (count < min_count) 
                                        {
                                                while (count-- > 0) 
                                                {
                                                        
blTree.WriteSymbol(curlen);
                                                }
                                        }
                                        else if (curlen != 0) 
                                        {
                                                blTree.WriteSymbol(REP_3_6);
                                                dh.pending.WriteBits(count - 3, 
2);
                                        } 
                                        else if (count <= 10) 
                                        {
                                                blTree.WriteSymbol(REP_3_10);
                                                dh.pending.WriteBits(count - 3, 
3);
                                        } 
                                        else 
                                        {
                                                blTree.WriteSymbol(REP_11_138);
                                                dh.pending.WriteBits(count - 
11, 7);
                                        }
                                }
                        }
                }
                
                public DeflaterPending pending;
                private Tree literalTree, distTree, blTree;
                
                private short[] d_buf;
                private byte[]  l_buf;
                private int last_lit;
                private int extra_bits;
                
                private static short[] staticLCodes;
                private static byte[]  staticLLength;
                private static short[] staticDCodes;
                private static byte[]  staticDLength;
                
                /// <summary>
                /// Reverse the bits of a 16 bit value.
                /// </summary>
                public static short BitReverse(int value) 
                {
                        return (short) (bit4Reverse[value & 0xF] << 12
                                | bit4Reverse[(value >> 4) & 0xF] << 8
                                | bit4Reverse[(value >> 8) & 0xF] << 4
                                | bit4Reverse[value >> 12]);
                }
                
                
                static DeflaterHuffman() 
                {
                        /* See RFC 1951 3.2.6 */
                        /* Literal codes */
                        staticLCodes = new short[LITERAL_NUM];
                        staticLLength = new byte[LITERAL_NUM];
                        int i = 0;
                        while (i < 144) 
                        {
                                staticLCodes[i] = BitReverse((0x030 + i) << 8);
                                staticLLength[i++] = 8;
                        }
                        while (i < 256) 
                        {
                                staticLCodes[i] = BitReverse((0x190 - 144 + i) 
<< 7);
                                staticLLength[i++] = 9;
                        }
                        while (i < 280) 
                        {
                                staticLCodes[i] = BitReverse((0x000 - 256 + i) 
<< 9);
                                staticLLength[i++] = 7;
                        }
                        while (i < LITERAL_NUM) 
                        {
                                staticLCodes[i] = BitReverse((0x0c0 - 280 + i)  
<< 8);
                                staticLLength[i++] = 8;
                        }
                        
                        /* Distant codes */
                        staticDCodes = new short[DIST_NUM];
                        staticDLength = new byte[DIST_NUM];
                        for (i = 0; i < DIST_NUM; i++) 
                        {
                                staticDCodes[i] = BitReverse(i << 11);
                                staticDLength[i] = 5;
                        }
                }
                
                public DeflaterHuffman(DeflaterPending pending)
                {
                        this.pending = pending;
                        
                        literalTree = new Tree(this, LITERAL_NUM, 257, 15);
                        distTree    = new Tree(this, DIST_NUM, 1, 15);
                        blTree      = new Tree(this, BITLEN_NUM, 4, 7);
                        
                        d_buf = new short[BUFSIZE];
                        l_buf = new byte [BUFSIZE];
                }
                
                public void Reset() 
                {
                        last_lit = 0;
                        extra_bits = 0;
                        literalTree.Reset();
                        distTree.Reset();
                        blTree.Reset();
                }
                
                private int L_code(int len) 
                {
                        if (len == 255) 
                        {
                                return 285;
                        }
                        
                        int code = 257;
                        while (len >= 8) 
                        {
                                code += 4;
                                len >>= 1;
                        }
                        return code + len;
                }
                
                private int D_code(int distance) 
                {
                        int code = 0;
                        while (distance >= 4) 
                        {
                                code += 2;
                                distance >>= 1;
                        }
                        return code + distance;
                }
                
                public void SendAllTrees(int blTreeCodes)
                {
                        blTree.BuildCodes();
                        literalTree.BuildCodes();
                        distTree.BuildCodes();
                        pending.WriteBits(literalTree.numCodes - 257, 5);
                        pending.WriteBits(distTree.numCodes - 1, 5);
                        pending.WriteBits(blTreeCodes - 4, 4);
                        for (int rank = 0; rank < blTreeCodes; rank++) 
                        {
                                
pending.WriteBits(blTree.length[BL_ORDER[rank]], 3);
                        }
                        literalTree.WriteTree(blTree);
                        distTree.WriteTree(blTree);
                        //                      if 
(DeflaterConstants.DEBUGGING) {
                        //                              blTree.CheckEmpty();
                        //                      }
                }
                
                public void CompressBlock()
                {
                        for (int i = 0; i < last_lit; i++) 
                        {
                                int litlen = l_buf[i] & 0xff;
                                int dist = d_buf[i];
                                if (dist-- != 0) 
                                {
                                        //                                      
if (DeflaterConstants.DEBUGGING) {
                                        //                                      
        Console.Write("["+(dist+1)+","+(litlen+3)+"]: ");
                                        //                                      
}
                                        
                                        int lc = L_code(litlen);
                                        literalTree.WriteSymbol(lc);
                                        
                                        int bits = (lc - 261) / 4;
                                        if (bits > 0 && bits <= 5) 
                                        {
                                                pending.WriteBits(litlen & ((1 
<< bits) - 1), bits);
                                        }
                                        
                                        int dc = D_code(dist);
                                        distTree.WriteSymbol(dc);
                                        
                                        bits = dc / 2 - 1;
                                        if (bits > 0) 
                                        {
                                                pending.WriteBits(dist & ((1 << 
bits) - 1), bits);
                                        }
                                } 
                                else 
                                {
                                        //                                      
if (DeflaterConstants.DEBUGGING) {
                                        //                                      
        if (litlen > 32 && litlen < 127) {
                                        //                                      
                Console.Write("("+(char)litlen+"): ");
                                        //                                      
        } else {
                                        //                                      
                Console.Write("{"+litlen+"}: ");
                                        //                                      
        }
                                        //                                      
}
                                        literalTree.WriteSymbol(litlen);
                                }
                        }
                        //                      if 
(DeflaterConstants.DEBUGGING) {
                        //                              Console.Write("EOF: ");
                        //                      }
                        literalTree.WriteSymbol(EOF_SYMBOL);
                        //                      if 
(DeflaterConstants.DEBUGGING) {
                        //                              
literalTree.CheckEmpty();
                        //                              distTree.CheckEmpty();
                        //                      }
                }
                
                public void FlushStoredBlock(byte[] stored, int stored_offset, 
int stored_len, bool lastBlock)
                {
                        //                      if 
(DeflaterConstants.DEBUGGING) {
                        //                              
//Console.WriteLine("Flushing stored block "+ stored_len);
                        //                      }
                        pending.WriteBits((DeflaterConstants.STORED_BLOCK << 1)
                                + (lastBlock ? 1 : 0), 3);
                        pending.AlignToByte();
                        pending.WriteShort(stored_len);
                        pending.WriteShort(~stored_len);
                        pending.WriteBlock(stored, stored_offset, stored_len);
                        Reset();
                }
                
                public void FlushBlock(byte[] stored, int stored_offset, int 
stored_len, bool lastBlock)
                {
                        literalTree.freqs[EOF_SYMBOL]++;
                        
                        /* Build trees */
                        literalTree.BuildTree();
                        distTree.BuildTree();
                        
                        /* Calculate bitlen frequency */
                        literalTree.CalcBLFreq(blTree);
                        distTree.CalcBLFreq(blTree);
                        
                        /* Build bitlen tree */
                        blTree.BuildTree();
                        
                        int blTreeCodes = 4;
                        for (int i = 18; i > blTreeCodes; i--) 
                        {
                                if (blTree.length[BL_ORDER[i]] > 0) 
                                {
                                        blTreeCodes = i+1;
                                }
                        }
                        int opt_len = 14 + blTreeCodes * 3 + 
blTree.GetEncodedLength() + 
                                literalTree.GetEncodedLength() + 
distTree.GetEncodedLength() + 
                                extra_bits;
                        
                        int static_len = extra_bits;
                        for (int i = 0; i < LITERAL_NUM; i++) 
                        {
                                static_len += literalTree.freqs[i] * 
staticLLength[i];
                        }
                        for (int i = 0; i < DIST_NUM; i++) 
                        {
                                static_len += distTree.freqs[i] * 
staticDLength[i];
                        }
                        if (opt_len >= static_len) 
                        {
                                /* Force static trees */
                                opt_len = static_len;
                        }
                        
                        if (stored_offset >= 0 && stored_len+4 < opt_len >> 3) 
                        {
                                /* Store Block */
                                //                              if 
(DeflaterConstants.DEBUGGING) {
                                //                                      
//Console.WriteLine("Storing, since " + stored_len + " < " + opt_len
                                //                                              
          + " <= " + static_len);
                                //                              }
                                FlushStoredBlock(stored, stored_offset, 
stored_len, lastBlock);
                        } 
                        else if (opt_len == static_len) 
                        {
                                /* Encode with static tree */
                                
pending.WriteBits((DeflaterConstants.STATIC_TREES << 1) + (lastBlock ? 1 : 0), 
3);
                                literalTree.SetStaticCodes(staticLCodes, 
staticLLength);
                                distTree.SetStaticCodes(staticDCodes, 
staticDLength);
                                CompressBlock();
                                Reset();
                        } 
                        else 
                        {
                                /* Encode with dynamic tree */
                                pending.WriteBits((DeflaterConstants.DYN_TREES 
<< 1) + (lastBlock ? 1 : 0), 3);
                                SendAllTrees(blTreeCodes);
                                CompressBlock();
                                Reset();
                        }
                }
                
                public bool IsFull()
                {
                        return last_lit + 16 >= BUFSIZE; // HACK: This was == 
'last_lit == BUFSIZE', but errors occured with DeflateFast
                }
                
                public bool TallyLit(int lit)
                {
                        //                      if 
(DeflaterConstants.DEBUGGING) {
                        //                              if (lit > 32 && lit < 
127) {
                        //                                      
//Console.WriteLine("("+(char)lit+")");
                        //                              } else {
                        //                                      
//Console.WriteLine("{"+lit+"}");
                        //                              }
                        //                      }
                        d_buf[last_lit] = 0;
                        l_buf[last_lit++] = (byte)lit;
                        literalTree.freqs[lit]++;
                        return IsFull();
                }
                
                public bool TallyDist(int dist, int len)
                {
                        //                      if 
(DeflaterConstants.DEBUGGING) {
                        //                              
//Console.WriteLine("["+dist+","+len+"]");
                        //                      }
                        
                        d_buf[last_lit]   = (short)dist;
                        l_buf[last_lit++] = (byte)(len - 3);
                        
                        int lc = L_code(len - 3);
                        literalTree.freqs[lc]++;
                        if (lc >= 265 && lc < 285) 
                        {
                                extra_bits += (lc - 261) / 4;
                        }
                        
                        int dc = D_code(dist - 1);
                        distTree.freqs[dc]++;
                        if (dc >= 4) 
                        {
                                extra_bits += dc / 2 - 1;
                        }
                        return IsFull();
                }
        }
}

--- NEW FILE: DeflaterEngine.cs ---
// DeflaterEngine.cs
// Copyright (C) 2001 Mike Krueger
//
// This file was translated from java, it was part of the GNU Classpath
// Copyright (C) 2001 Free Software Foundation, Inc.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
//
// Linking this library statically or dynamically with other modules is
// making a combined work based on this library.  Thus, the terms and
// conditions of the GNU General Public License cover the whole
// combination.
// 
// As a special exception, the copyright holders of this library give you
// permission to link this library with independent modules to produce an
// executable, regardless of the license terms of these independent
// modules, and to copy and distribute the resulting executable under
// terms of your choice, provided that you also meet, for each linked
// independent module, the terms and conditions of the license of that
// module.  An independent module is a module which is not derived from
// or based on this library.  If you modify this library, you may extend
// this exception to your version of the library, but you are not
// obligated to do so.  If you do not wish to do so, delete this
// exception statement from your version.

using System;

using ICSharpCode.SharpZipLib.Checksums;

namespace ICSharpCode.SharpZipLib.Zip.Compression 
{
        
        public enum DeflateStrategy 
        {
                // The default strategy.
                Default  = 0,
                
                // This strategy will only allow longer string repetitions.  It 
is
                // useful for random data with a small character set.
                Filtered = 1,
                
                // This strategy will not look for string repetitions at all.  
It
                // only encodes with Huffman trees (which means, that more 
common
                // characters get a smaller encoding.
                HuffmanOnly = 2
        }
        
        public class DeflaterEngine : DeflaterConstants 
        {
                static int TOO_FAR = 4096;
                
                int ins_h;
                //              private byte[] buffer;
                short[] head;
                short[] prev;
                
                int    matchStart, matchLen;
                bool   prevAvailable;
                int    blockStart;
                int    strstart, lookahead;
                byte[] window;
                
                DeflateStrategy strategy;
                int max_chain, max_lazy, niceLength, goodLength;
                
                /// <summary>
                /// The current compression function.
                /// </summary>
                int comprFunc;
                
                /// <summary>
                /// The input data for compression.
                /// </summary>
                byte[] inputBuf;
                
                /// <summary>
                /// The total bytes of input read.
                /// </summary>
                int totalIn;
                
                /// <summary>
                /// The offset into inputBuf, where input data starts.
                /// </summary>
                int inputOff;
                
                /// <summary>
                /// The end offset of the input data.
                /// </summary>
                int inputEnd;
                
                DeflaterPending pending;
                DeflaterHuffman huffman;
                
                /// <summary>
                /// The adler checksum
                /// </summary>
                Adler32 adler;
                
                public DeflaterEngine(DeflaterPending pending) 
                {
                        this.pending = pending;
                        huffman = new DeflaterHuffman(pending);
                        adler = new Adler32();
                        
                        window = new byte[2 * WSIZE];
                        head   = new short[HASH_SIZE];
                        prev   = new short[WSIZE];
                        
                        /* We start at index 1, to avoid a implementation 
deficiency, that
                        * we cannot build a repeat pattern at index 0.
                        */
                        blockStart = strstart = 1;
                }
                
                public void Reset()
                {
                        huffman.Reset();
                        adler.Reset();
                        blockStart = strstart = 1;
                        lookahead = 0;
                        totalIn   = 0;
                        prevAvailable = false;
                        matchLen = MIN_MATCH - 1;
                        
                        for (int i = 0; i < HASH_SIZE; i++) 
                        {
                                head[i] = 0;
                        }
                        
                        for (int i = 0; i < WSIZE; i++) 
                        {
                                prev[i] = 0;
                        }
                }
                
                public void ResetAdler()
                {
                        adler.Reset();
                }
                
                public int Adler 
                {
                        get 
                        {
                                return (int)adler.Value;
                        }
                }
                
                public int TotalIn 
                {
                        get 
                        {
                                return totalIn;
                        }
                }
                
                public DeflateStrategy Strategy 
                {
                        get 
                        {
                                return strategy;
                        }
                        set 
                        {
                                strategy = value;
                        }
                }
                
                public void SetLevel(int lvl)
                {
                        goodLength = DeflaterConstants.GOOD_LENGTH[lvl];
                        max_lazy   = DeflaterConstants.MAX_LAZY[lvl];
                        niceLength = DeflaterConstants.NICE_LENGTH[lvl];
                        max_chain  = DeflaterConstants.MAX_CHAIN[lvl];
                        
                        if (DeflaterConstants.COMPR_FUNC[lvl] != comprFunc) 
                        {
                                //                              if 
(DeflaterConstants.DEBUGGING) {
                                //                                      
//Console.WriteLine("Change from "+comprFunc +" to "
                                //                                              
          + DeflaterConstants.COMPR_FUNC[lvl]);
                                //                              }
                                switch (comprFunc) 
                                {
                                        case DEFLATE_STORED:
                                                if (strstart > blockStart) 
                                                {
                                                        
huffman.FlushStoredBlock(window, blockStart,
                                                                strstart - 
blockStart, false);
                                                        blockStart = strstart;
                                                }
                                                UpdateHash();
                                                break;
                                        case DEFLATE_FAST:
                                                if (strstart > blockStart) 
                                                {
                                                        
huffman.FlushBlock(window, blockStart, strstart - blockStart,
                                                                false);
                                                        blockStart = strstart;
                                                }
                                                break;
                                        case DEFLATE_SLOW:
                                                if (prevAvailable) 
                                                {
                                                        
huffman.TallyLit(window[strstart-1] & 0xff);
                                                }
                                                if (strstart > blockStart) 
                                                {
                                                        
huffman.FlushBlock(window, blockStart, strstart - blockStart,
                                                                false);
                                                        blockStart = strstart;
                                                }
                                                prevAvailable = false;
                                                matchLen = MIN_MATCH - 1;
                                                break;
                                }
                                comprFunc = COMPR_FUNC[lvl];
                        }
                }
                
                private void UpdateHash() 
                {
                        //                      if (DEBUGGING) {
                        //                              
//Console.WriteLine("updateHash: "+strstart);
                        //                      }
                        ins_h = (window[strstart] << HASH_SHIFT) ^ 
window[strstart + 1];
                }
                
                private int InsertString() 
                {
                        short match;
                        int hash = ((ins_h << HASH_SHIFT) ^ window[strstart + 
(MIN_MATCH -1)]) & HASH_MASK;
                        
                        //                      if (DEBUGGING) {
                        //                              if (hash != 
(((window[strstart] << (2*HASH_SHIFT)) ^ 
                        //                                            
(window[strstart + 1] << HASH_SHIFT) ^ 
                        //                                            
(window[strstart + 2])) & HASH_MASK)) {
                        //                                              throw 
new Exception("hash inconsistent: "+hash+"/"
                        //                                                      
            +window[strstart]+","
                        //                                                      
            +window[strstart+1]+","
                        //                                                      
            +window[strstart+2]+","+HASH_SHIFT);
                        //                                      }
                        //                      }
                        
                        prev[strstart & WMASK] = match = head[hash];
                        head[hash] = (short)strstart;
                        ins_h = hash;
                        return match & 0xffff;
                }
                
                void SlideWindow()
                {
                        Array.Copy(window, WSIZE, window, 0, WSIZE);
                        matchStart -= WSIZE;
                        strstart   -= WSIZE;
                        blockStart -= WSIZE;
                        
                        /* Slide the hash table (could be avoided with 32 bit 
values
                         * at the expense of memory usage).
                         */
                        for (int i = 0; i < HASH_SIZE; ++i) 
                        {
                                int m = head[i] & 0xffff;
                                head[i] = (short)(m >= WSIZE ? (m - WSIZE) : 0);
                        }
                        
                        /* Slide the prev table. */
                        for (int i = 0; i < WSIZE; i++) 
                        {
                                int m = prev[i] & 0xffff;
                                prev[i] = (short)(m >= WSIZE ? (m - WSIZE) : 0);
                        }
                }
                
                public void FillWindow()
                {
                        /* If the window is almost full and there is 
insufficient lookahead,
                         * move the upper half to the lower one to make room in 
the upper half.
                         */
                        if (strstart >= WSIZE + MAX_DIST) 
                        {
                                SlideWindow();
                        }
                        
                        /* If there is not enough lookahead, but still some 
input left,
                         * read in the input
                         */
                        while (lookahead < DeflaterConstants.MIN_LOOKAHEAD && 
inputOff < inputEnd) 
                        {
                                int more = 2 * WSIZE - lookahead - strstart;
                                
                                if (more > inputEnd - inputOff) 
                                {
                                        more = inputEnd - inputOff;
                                }
                                
                                System.Array.Copy(inputBuf, inputOff, window, 
strstart + lookahead, more);
                                adler.Update(inputBuf, inputOff, more);
                                
                                inputOff += more;
                                totalIn  += more;
                                lookahead += more;
                        }
                        
                        if (lookahead >= MIN_MATCH) 
                        {
                                UpdateHash();
                        }
                }
                
                private bool FindLongestMatch(int curMatch) 
                {
                        int chainLength = this.max_chain;
                        int niceLength  = this.niceLength;
                        short[] prev    = this.prev;
                        int scan        = this.strstart;
                        int match;
                        int best_end = this.strstart + matchLen;
                        int best_len = Math.Max(matchLen, MIN_MATCH - 1);
                        
                        int limit = Math.Max(strstart - MAX_DIST, 0);
                        
                        int strend = strstart + MAX_MATCH - 1;
                        byte scan_end1 = window[best_end - 1];
                        byte scan_end  = window[best_end];
                        
                        /* Do not waste too much time if we already have a good 
match: */
                        if (best_len >= this.goodLength) 
                        {
                                chainLength >>= 2;
                        }
                        
                        /* Do not look for matches beyond the end of the input. 
This is necessary
                        * to make deflate deterministic.
                        */
                        if (niceLength > lookahead) 
                        {
                                niceLength = lookahead;
                        }
                        
                        if (DeflaterConstants.DEBUGGING && strstart > 2 * WSIZE 
- MIN_LOOKAHEAD) 
                        {
                                throw new InvalidOperationException("need 
lookahead");
                        }
                        
                        do 
                        {
                                if (DeflaterConstants.DEBUGGING && curMatch >= 
strstart) 
                                {
                                        throw new 
InvalidOperationException("future match");
                                }
                                if (window[curMatch + best_len] != scan_end     
 || 
                                        window[curMatch + best_len - 1] != 
scan_end1 || 
                                        window[curMatch] != window[scan]        
     || 
                                        window[curMatch + 1] != window[scan + 
1]) 
                                {
                                        continue;
                                }
                                
                                match = curMatch + 2;
                                scan += 2;
                                
                                /* We check for insufficient lookahead only 
every 8th comparison;
                                * the 256th check will be made at strstart+258.
                                */
                        while (window[++scan] == window[++match] && 
                                window[++scan] == window[++match] && 
                                window[++scan] == window[++match] && 
                                window[++scan] == window[++match] && 
                                window[++scan] == window[++match] && 
                                window[++scan] == window[++match] && 
                                window[++scan] == window[++match] && 
                                window[++scan] == window[++match] && scan < 
strend) ;
                                
                                if (scan > best_end) 
                                {
                                        //      if (DeflaterConstants.DEBUGGING 
&& ins_h == 0)
                                        //        System.err.println("Found 
match: "+curMatch+"-"+(scan-strstart));
                                        matchStart = curMatch;
                                        best_end = scan;
                                        best_len = scan - strstart;
                                        if (best_len >= niceLength) 
                                        {
                                                break;
                                        }
                                        
                                        scan_end1  = window[best_end - 1];
                                        scan_end   = window[best_end];
                                }
                                scan = strstart;
                        } while ((curMatch = (prev[curMatch & WMASK] & 0xffff)) 
> limit && --chainLength != 0);
                        
                        matchLen = Math.Min(best_len, lookahead);
                        return matchLen >= MIN_MATCH;
                }
                
                public void SetDictionary(byte[] buffer, int offset, int 
length) 
                {
                        if (DeflaterConstants.DEBUGGING && strstart != 1) 
                        {
                                throw new InvalidOperationException("strstart 
not 1");
                        }
                        adler.Update(buffer, offset, length);
                        if (length < MIN_MATCH) 
                        {
                                return;
                        }
                        if (length > MAX_DIST) 
                        {
                                offset += length - MAX_DIST;
                                length = MAX_DIST;
                        }
                        
                        System.Array.Copy(buffer, offset, window, strstart, 
length);
                        
                        UpdateHash();
                        --length;
                        while (--length > 0) 
                        {
                                InsertString();
                                strstart++;
                        }
                        strstart += 2;
                        blockStart = strstart;
                }
                
                private bool DeflateStored(bool flush, bool finish)
                {
                        if (!flush && lookahead == 0) 
                        {
                                return false;
                        }
                        
                        strstart += lookahead;
                        lookahead = 0;
                        
                        int storedLen = strstart - blockStart;
                        
                        if ((storedLen >= DeflaterConstants.MAX_BLOCK_SIZE) || 
/* Block is full */
                                (blockStart < WSIZE && storedLen >= MAX_DIST) 
||   /* Block may move out of window */
                                flush) 
                        {
                                bool lastBlock = finish;
                                if (storedLen > 
DeflaterConstants.MAX_BLOCK_SIZE) 
                                {
                                        storedLen = 
DeflaterConstants.MAX_BLOCK_SIZE;
                                        lastBlock = false;
                                }
                                
                                //                              if 
(DeflaterConstants.DEBUGGING) {
                                //                                      
//Console.WriteLine("storedBlock["+storedLen+","+lastBlock+"]");
                                //                              }
                                        
                                huffman.FlushStoredBlock(window, blockStart, 
storedLen, lastBlock);
                                blockStart += storedLen;
                                return !lastBlock;
                        }
                        return true;
                }
                
                private bool DeflateFast(bool flush, bool finish)
                {
                        if (lookahead < MIN_LOOKAHEAD && !flush) 
                        {
                                return false;
                        }
                        
                        while (lookahead >= MIN_LOOKAHEAD || flush) 
                        {
                                if (lookahead == 0) 
                                {
                                        /* We are flushing everything */
                                        huffman.FlushBlock(window, blockStart, 
strstart - blockStart, finish);
                                        blockStart = strstart;
                                        return false;
                                }
                                
                                if (strstart > 2 * WSIZE - MIN_LOOKAHEAD)
                                {
                                        /* slide window, as findLongestMatch 
need this.
                                         * This should only happen when 
flushing and the window
                                         * is almost full.
                                         */
                                        SlideWindow();
                                }
                                
                                int hashHead;
                                if (lookahead >= MIN_MATCH && 
                                        (hashHead = InsertString()) != 0 && 
                                        strategy != DeflateStrategy.HuffmanOnly 
&&
                                        strstart - hashHead <= MAX_DIST && 
                                        FindLongestMatch(hashHead)) 
                                {
                                        /* longestMatch sets matchStart and 
matchLen */
                                        //                                      
if (DeflaterConstants.DEBUGGING) {
                                        //                                      
        for (int i = 0 ; i < matchLen; i++) {
                                        //                                      
                if (window[strstart+i] != window[matchStart + i]) {
                                        //                                      
                        throw new Exception();
                                        //                                      
                }
                                        //                                      
        }
                                        //                                      
}
                                        
                                        huffman.TallyDist(strstart - 
matchStart, matchLen);
                                        
                                        lookahead -= matchLen;
                                        if (matchLen <= max_lazy && lookahead 
>= MIN_MATCH) 
                                        {
                                                while (--matchLen > 0) 
                                                {
                                                        ++strstart;
                                                        InsertString();
                                                }
                                                ++strstart;
                                        } 
                                        else 
                                        {
                                                strstart += matchLen;
                                                if (lookahead >= MIN_MATCH - 1) 
                                                {
                                                        UpdateHash();
                                                }
                                        }
                                        matchLen = MIN_MATCH - 1;
                                        continue;
                                } 
                                else 
                                {
                                        /* No match found */
                                        huffman.TallyLit(window[strstart] & 
0xff);
                                        ++strstart;
                                        --lookahead;
                                }
                                
                                if (huffman.IsFull()) 
                                {
                                        bool lastBlock = finish && lookahead == 
0;
                                        huffman.FlushBlock(window, blockStart, 
strstart - blockStart,
                                                lastBlock);
                                        blockStart = strstart;
                                        return !lastBlock;
                                }
                        }
                        return true;
                }
                
                private bool DeflateSlow(bool flush, bool finish)
                {
                        if (lookahead < MIN_LOOKAHEAD && !flush) 
                        {
                                return false;
                        }
                        
                        while (lookahead >= MIN_LOOKAHEAD || flush) 
                        {
                                if (lookahead == 0) 
                                {
                                        if (prevAvailable) 
                                        {
                                                
huffman.TallyLit(window[strstart-1] & 0xff);
                                        }
                                        prevAvailable = false;
                                        
                                        /* We are flushing everything */
                                        if (DeflaterConstants.DEBUGGING && 
!flush) 
                                        {
                                                throw new Exception("Not 
flushing, but no lookahead");
                                        }
                                        huffman.FlushBlock(window, blockStart, 
strstart - blockStart,
                                                finish);
                                        blockStart = strstart;
                                        return false;
                                }
                                
                                if (strstart >= 2 * WSIZE - MIN_LOOKAHEAD)
                                {
                                        /* slide window, as findLongestMatch 
need this.
                                         * This should only happen when 
flushing and the window
                                         * is almost full.
                                         */
                                        SlideWindow();
                                }
                                
                                int prevMatch = matchStart;
                                int prevLen = matchLen;
                                if (lookahead >= MIN_MATCH) 
                                {
                                        int hashHead = InsertString();
                                        if (strategy != 
DeflateStrategy.HuffmanOnly && hashHead != 0 && strstart - hashHead <= MAX_DIST 
&& FindLongestMatch(hashHead))
                                        {
                                                /* longestMatch sets matchStart 
and matchLen */
                                                        
                                                /* Discard match if too small 
and too far away */
                                                if (matchLen <= 5 && (strategy 
== DeflateStrategy.Filtered || (matchLen == MIN_MATCH && strstart - matchStart 
> TOO_FAR))) 
                                                {
                                                        matchLen = MIN_MATCH - 
1;
                                                }
                                        }
                                }
                                
                                /* previous match was better */
                                if (prevLen >= MIN_MATCH && matchLen <= 
prevLen) 
                                {
                                        //                                      
if (DeflaterConstants.DEBUGGING) {
                                        //                                      
        for (int i = 0 ; i < matchLen; i++) {
                                        //                                      
                if (window[strstart-1+i] != window[prevMatch + i])
                                        //                                      
                        throw new Exception();
                                        //                                      
        }
                                        //                                      
}
                                        huffman.TallyDist(strstart - 1 - 
prevMatch, prevLen);
                                        prevLen -= 2;
                                        do 
                                        {
                                                strstart++;
                                                lookahead--;
                                                if (lookahead >= MIN_MATCH) 
                                                {
                                                        InsertString();
                                                }
                                        } while (--prevLen > 0);
                                        strstart ++;
                                        lookahead--;
                                        prevAvailable = false;
                                        matchLen = MIN_MATCH - 1;
                                } 
                                else 
                                {
                                        if (prevAvailable) 
                                        {
                                                
huffman.TallyLit(window[strstart-1] & 0xff);
                                        }
                                        prevAvailable = true;
                                        strstart++;
                                        lookahead--;
                                }
                                
                                if (huffman.IsFull()) 
                                {
                                        int len = strstart - blockStart;
                                        if (prevAvailable) 
                                        {
                                                len--;
                                        }
                                        bool lastBlock = (finish && lookahead 
== 0 && !prevAvailable);
                                        huffman.FlushBlock(window, blockStart, 
len, lastBlock);
                                        blockStart += len;
                                        return !lastBlock;
                                }
                        }
                        return true;
                }
                
                public bool Deflate(bool flush, bool finish)
                {
                        bool progress;
                        do 
                        {
                                FillWindow();
                                bool canFlush = flush && inputOff == inputEnd;
                                //                              if 
(DeflaterConstants.DEBUGGING) {
                                //                                      
//Console.WriteLine("window: ["+blockStart+","+strstart+","
                                //                                              
          +lookahead+"], "+comprFunc+","+canFlush);
                                //                              }
                                switch (comprFunc) 
                                {
                                        case DEFLATE_STORED:
                                                progress = 
DeflateStored(canFlush, finish);
                                                break;
                                        case DEFLATE_FAST:
                                                progress = 
DeflateFast(canFlush, finish);
                                                break;
                                        case DEFLATE_SLOW:
                                                progress = 
DeflateSlow(canFlush, finish);
                                                break;
                                        default:
                                                throw new 
InvalidOperationException("unknown comprFunc");
                                }
                        } while (pending.IsFlushed && progress); /* repeat 
while we have no pending output and progress was made */
                        return progress;
                }
                
                public void SetInput(byte[] buf, int off, int len)
                {
                        if (inputOff < inputEnd) 
                        {
                                throw new InvalidOperationException("Old input 
was not completely processed");
                        }
                        
                        int end = off + len;
                        
                        /* We want to throw an ArrayIndexOutOfBoundsException 
early.  The
                        * check is very tricky: it also handles integer wrap 
around.
                        */
                        if (0 > off || off > end || end > buf.Length) 
                        {
                                throw new ArgumentOutOfRangeException();
                        }
                        
                        inputBuf = buf;
                        inputOff = off;
                        inputEnd = end;
                }
                
                public bool NeedsInput()
                {
                        return inputEnd == inputOff;
                }
        }
}

--- NEW FILE: InflaterDynHeader.cs ---
// InflaterDynHeader.cs
// Copyright (C) 2001 Mike Krueger
//
// This file was translated from java, it was part of the GNU Classpath
// Copyright (C) 2001 Free Software Foundation, Inc.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
//
// Linking this library statically or dynamically with other modules is
// making a combined work based on this library.  Thus, the terms and
// conditions of the GNU General Public License cover the whole
// combination.
//
// As a special exception, the copyright holders of this library give you
// permission to link this library with independent modules to produce an
// executable, regardless of the license terms of these independent
// modules, and to copy and distribute the resulting executable under
// terms of your choice, provided that you also meet, for each linked
// independent module, the terms and conditions of the license of that
// module.  An independent module is a module which is not derived from
// or based on this library.  If you modify this library, you may extend
// this exception to your version of the library, but you are not
// obligated to do so.  If you do not wish to do so, delete this
// exception statement from your version.

using System;

using ICSharpCode.SharpZipLib.Zip.Compression.Streams;

namespace ICSharpCode.SharpZipLib.Zip.Compression 
{
        
        class InflaterDynHeader
        {
                const int LNUM   = 0;
                const int DNUM   = 1;
                const int BLNUM  = 2;
                const int BLLENS = 3;
                const int LENS   = 4;
                const int REPS   = 5;
                
                static readonly int[] repMin  = { 3, 3, 11 };
                static readonly int[] repBits = { 2, 3,  7 };
                
                byte[] blLens;
                byte[] litdistLens;
                
                InflaterHuffmanTree blTree;
                
                int mode;
                int lnum, dnum, blnum, num;
                int repSymbol;
                byte lastLen;
                int ptr;
                
                static readonly int[] BL_ORDER = { 16, 17, 18, 0, 8, 7, 9, 6, 
10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
                
                public InflaterDynHeader()
                {
                }
                
                public bool Decode(StreamManipulator input)
                {
                        decode_loop:
                                for (;;) 
                                {
                                        switch (mode) 
                                        {
                                                case LNUM:
                                                        lnum = 
input.PeekBits(5);
                                                        if (lnum < 0) 
                                                        {
                                                                return false;
                                                        }
                                                        lnum += 257;
                                                        input.DropBits(5);
                                                        //          
System.err.println("LNUM: "+lnum);
                                                        mode = DNUM;
                                                        goto case DNUM; // fall 
through
                                                case DNUM:
                                                        dnum = 
input.PeekBits(5);
                                                        if (dnum < 0) 
                                                        {
                                                                return false;
                                                        }
                                                        dnum++;
                                                        input.DropBits(5);
                                                        //          
System.err.println("DNUM: "+dnum);
                                                        num = lnum+dnum;
                                                        litdistLens = new 
byte[num];
                                                        mode = BLNUM;
                                                        goto case BLNUM; // 
fall through
                                                case BLNUM:
                                                        blnum = 
input.PeekBits(4);
                                                        if (blnum < 0) 
                                                        {
                                                                return false;
                                                        }
                                                        blnum += 4;
                                                        input.DropBits(4);
                                                        blLens = new byte[19];
                                                        ptr = 0;
                                                        //          
System.err.println("BLNUM: "+blnum);
                                                        mode = BLLENS;
                                                        goto case BLLENS; // 
fall through
                                                case BLLENS:
                                                        while (ptr < blnum) 
                                                        {
                                                                int len = 
input.PeekBits(3);
                                                                if (len < 0) 
                                                                {
                                                                        return 
false;
                                                                }
                                                                
input.DropBits(3);
                                                                //              
System.err.println("blLens["+BL_ORDER[ptr]+"]: "+len);
                                                                
blLens[BL_ORDER[ptr]] = (byte) len;
                                                                ptr++;
                                                        }
                                                        blTree = new 
InflaterHuffmanTree(blLens);
                                                        blLens = null;
                                                        ptr = 0;
                                                        mode = LENS;
                                                        goto case LENS; // fall 
through
                                                case LENS: 
                                                {
                                                        int symbol;
                                                        while (((symbol = 
blTree.GetSymbol(input)) & ~15) == 0) 
                                                        {
                                                                /* Normal case: 
symbol in [0..15] */
                                                        
                                                                //              
  System.err.println("litdistLens["+ptr+"]: "+symbol);
                                                                
litdistLens[ptr++] = lastLen = (byte)symbol;
                                                        
                                                                if (ptr == num) 
                                                                {
                                                                        /* 
Finished */
                                                                        return 
true;
                                                                }
                                                        }
                                                
                                                        /* need more input ? */
                                                        if (symbol < 0)
                                                                return false;
                                                
                                                        /* otherwise repeat 
code */
                                                        if (symbol >= 17) 
                                                        {
                                                                /* repeat zero 
*/
                                                                //              
  System.err.println("repeating zero");
                                                                lastLen = 0;
                                                        } 
                                                        else 
                                                        {
                                                                if (ptr == 0) 
                                                                {
                                                                        throw 
new Exception();
                                                                }
                                                        }
                                                        repSymbol = symbol-16;
                                                }
                                                        mode = REPS;
                                                        goto case REPS; // fall 
through
                                                case REPS:
                                                {
                                                        int bits = 
repBits[repSymbol];
                                                        int count = 
input.PeekBits(bits);
                                                        if (count < 0) 
                                                        {
                                                                return false;
                                                        }
                                                        input.DropBits(bits);
                                                        count += 
repMin[repSymbol];
                                                        //            
System.err.println("litdistLens repeated: "+count);
                                                        
                                                        if (ptr + count > num) 
                                                        {
                                                                throw new 
Exception();
                                                        }
                                                        while (count-- > 0) 
                                                        {
                                                                
litdistLens[ptr++] = lastLen;
                                                        }
                                                        
                                                        if (ptr == num) 
                                                        {
                                                                /* Finished */
                                                                return true;
                                                        }
                                                }
                                                        mode = LENS;
                                                        goto decode_loop;
                                        }
                                }
                }
                
                public InflaterHuffmanTree BuildLitLenTree()
                {
                        byte[] litlenLens = new byte[lnum];
                        Array.Copy(litdistLens, 0, litlenLens, 0, lnum);
                        return new InflaterHuffmanTree(litlenLens);
                }
                
                public InflaterHuffmanTree BuildDistTree()
                {
                        byte[] distLens = new byte[dnum];
                        Array.Copy(litdistLens, lnum, distLens, 0, dnum);
                        return new InflaterHuffmanTree(distLens);
                }
        }
}

--- NEW FILE: DeflaterConstants.cs ---
// DeflaterConstants.cs
// Copyright (C) 2001 Mike Krueger
//
// This file was translated from java, it was part of the GNU Classpath
// Copyright (C) 2001 Free Software Foundation, Inc.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
//
// Linking this library statically or dynamically with other modules is
// making a combined work based on this library.  Thus, the terms and
// conditions of the GNU General Public License cover the whole
// combination.
// 
// As a special exception, the copyright holders of this library give you
// permission to link this library with independent modules to produce an
// executable, regardless of the license terms of these independent
// modules, and to copy and distribute the resulting executable under
// terms of your choice, provided that you also meet, for each linked
// independent module, the terms and conditions of the license of that
// module.  An independent module is a module which is not derived from
// or based on this library.  If you modify this library, you may extend
// this exception to your version of the library, but you are not
// obligated to do so.  If you do not wish to do so, delete this
// exception statement from your version.

using System;

namespace ICSharpCode.SharpZipLib.Zip.Compression 
{
        
        /// <summary>
        /// This class contains constants used for the deflater.
        /// </summary>
        public class DeflaterConstants 
        {
                public const bool DEBUGGING = false;
                
                public const int STORED_BLOCK = 0;
                public const int STATIC_TREES = 1;
                public const int DYN_TREES    = 2;
                public const int PRESET_DICT  = 0x20;
                
                public const int DEFAULT_MEM_LEVEL = 8;
                
                public const int MAX_MATCH = 258;
                public const int MIN_MATCH = 3;
                
                public const int MAX_WBITS = 15;
                public const int WSIZE = 1 << MAX_WBITS;
                public const int WMASK = WSIZE - 1;
                
                public const int HASH_BITS = DEFAULT_MEM_LEVEL + 7;
                public const int HASH_SIZE = 1 << HASH_BITS;
                public const int HASH_MASK = HASH_SIZE - 1;
                public const int HASH_SHIFT = (HASH_BITS + MIN_MATCH - 1) / 
MIN_MATCH;
                
                public const int MIN_LOOKAHEAD = MAX_MATCH + MIN_MATCH + 1;
                public const int MAX_DIST = WSIZE - MIN_LOOKAHEAD;
                
                public const int PENDING_BUF_SIZE = 1 << (DEFAULT_MEM_LEVEL + 
8);
                public static int MAX_BLOCK_SIZE = Math.Min(65535, 
PENDING_BUF_SIZE-5);
                
                public const int DEFLATE_STORED = 0;
                public const int DEFLATE_FAST   = 1;
                public const int DEFLATE_SLOW   = 2;
                
                public static int[] GOOD_LENGTH = { 0, 4, 4, 4, 4, 8,  8,  8,  
32,  32 };
                public static int[] MAX_LAZY    = { 0, 4, 5, 6, 4,16, 16, 32, 
128, 258 };
                public static int[] NICE_LENGTH = { 0, 8,16,32,16,32,128,128, 
258, 258 };
                public static int[] MAX_CHAIN   = { 0, 4, 
8,32,16,32,128,256,1024,4096 };
                public static int[] COMPR_FUNC  = { 0, 1, 1, 1, 1, 2,  2,  2,   
2,   2 };
        }
}





reply via email to

[Prev in Thread] Current Thread [Next in Thread]