root/trunk/BazaReklam.Updater/ICSharpCode.SharpZipLib/Zip/Compression/InflaterHuffmanTree.cs @ 818

Wersja 597, 6.8 KB (wprowadzona przez marek, 17 years temu)

re #165

Line 
1// InflaterHuffmanTree.cs
2// Copyright (C) 2001 Mike Krueger
3//
4// This file was translated from java, it was part of the GNU Classpath
5// Copyright (C) 2001 Free Software Foundation, Inc.
6//
7// This program is free software; you can redistribute it and/or
8// modify it under the terms of the GNU General Public License
9// as published by the Free Software Foundation; either version 2
10// of the License, or (at your option) any later version.
11//
12// This program is distributed in the hope that it will be useful,
13// but WITHOUT ANY WARRANTY; without even the implied warranty of
14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15// GNU General Public License for more details.
16//
17// You should have received a copy of the GNU General Public License
18// along with this program; if not, write to the Free Software
19// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20//
21// Linking this library statically or dynamically with other modules is
22// making a combined work based on this library.  Thus, the terms and
23// conditions of the GNU General Public License cover the whole
24// combination.
25//
26// As a special exception, the copyright holders of this library give you
27// permission to link this library with independent modules to produce an
28// executable, regardless of the license terms of these independent
29// modules, and to copy and distribute the resulting executable under
30// terms of your choice, provided that you also meet, for each linked
31// independent module, the terms and conditions of the license of that
32// module.  An independent module is a module which is not derived from
33// or based on this library.  If you modify this library, you may extend
34// this exception to your version of the library, but you are not
35// obligated to do so.  If you do not wish to do so, delete this
36// exception statement from your version.
37
38using System;
39
40using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
41
42namespace ICSharpCode.SharpZipLib.Zip.Compression
43{
44       
45        /// <summary>
46        /// Huffman tree used for inflation
47        /// </summary>
48        public class InflaterHuffmanTree
49        {
50                #region Constants
51                const int MAX_BITLEN = 15;
52                #endregion
53
54                #region Instance Fields
55                short[] tree;
56                #endregion
57
58                /// <summary>
59                /// Literal length tree
60                /// </summary>
61                public static InflaterHuffmanTree defLitLenTree;
62               
63                /// <summary>
64                /// Distance tree
65                /// </summary>
66                public static InflaterHuffmanTree defDistTree;
67               
68                static InflaterHuffmanTree()
69                {
70                        try {
71                                byte[] codeLengths = new byte[288];
72                                int i = 0;
73                                while (i < 144) {
74                                        codeLengths[i++] = 8;
75                                }
76                                while (i < 256) {
77                                        codeLengths[i++] = 9;
78                                }
79                                while (i < 280) {
80                                        codeLengths[i++] = 7;
81                                }
82                                while (i < 288) {
83                                        codeLengths[i++] = 8;
84                                }
85                                defLitLenTree = new InflaterHuffmanTree(codeLengths);
86                               
87                                codeLengths = new byte[32];
88                                i = 0;
89                                while (i < 32) {
90                                        codeLengths[i++] = 5;
91                                }
92                                defDistTree = new InflaterHuffmanTree(codeLengths);
93                        } catch (Exception) {
94                                throw new SharpZipBaseException("InflaterHuffmanTree: static tree length illegal");
95                        }
96                }
97
98                #region Constructors
99                /// <summary>
100                /// Constructs a Huffman tree from the array of code lengths.
101                /// </summary>
102                /// <param name = "codeLengths">
103                /// the array of code lengths
104                /// </param>
105                public InflaterHuffmanTree(byte[] codeLengths)
106                {
107                        BuildTree(codeLengths);
108                }
109                #endregion
110
111                void BuildTree(byte[] codeLengths)
112                {
113                        int[] blCount  = new int[MAX_BITLEN + 1];
114                        int[] nextCode = new int[MAX_BITLEN + 1];
115                       
116                        for (int i = 0; i < codeLengths.Length; i++) {
117                                int bits = codeLengths[i];
118                                if (bits > 0) {
119                                        blCount[bits]++;
120                                }
121                        }
122                       
123                        int code = 0;
124                        int treeSize = 512;
125                        for (int bits = 1; bits <= MAX_BITLEN; bits++) {
126                                nextCode[bits] = code;
127                                code += blCount[bits] << (16 - bits);
128                                if (bits >= 10) {
129                                        /* We need an extra table for bit lengths >= 10. */
130                                        int start = nextCode[bits] & 0x1ff80;
131                                        int end   = code & 0x1ff80;
132                                        treeSize += (end - start) >> (16 - bits);
133                                }
134                        }
135                       
136/* -jr comment this out! doesnt work for dynamic trees and pkzip 2.04g
137                        if (code != 65536)
138                        {
139                                throw new SharpZipBaseException("Code lengths don't add up properly.");
140                        }
141*/
142                        /* Now create and fill the extra tables from longest to shortest
143                        * bit len.  This way the sub trees will be aligned.
144                        */
145                        tree = new short[treeSize];
146                        int treePtr = 512;
147                        for (int bits = MAX_BITLEN; bits >= 10; bits--) {
148                                int end   = code & 0x1ff80;
149                                code -= blCount[bits] << (16 - bits);
150                                int start = code & 0x1ff80;
151                                for (int i = start; i < end; i += 1 << 7) {
152                                        tree[DeflaterHuffman.BitReverse(i)] = (short) ((-treePtr << 4) | bits);
153                                        treePtr += 1 << (bits-9);
154                                }
155                        }
156                       
157                        for (int i = 0; i < codeLengths.Length; i++) {
158                                int bits = codeLengths[i];
159                                if (bits == 0) {
160                                        continue;
161                                }
162                                code = nextCode[bits];
163                                int revcode = DeflaterHuffman.BitReverse(code);
164                                if (bits <= 9) {
165                                        do {
166                                                tree[revcode] = (short) ((i << 4) | bits);
167                                                revcode += 1 << bits;
168                                        } while (revcode < 512);
169                                } else {
170                                        int subTree = tree[revcode & 511];
171                                        int treeLen = 1 << (subTree & 15);
172                                        subTree = -(subTree >> 4);
173                                        do {
174                                                tree[subTree | (revcode >> 9)] = (short) ((i << 4) | bits);
175                                                revcode += 1 << bits;
176                                        } while (revcode < treeLen);
177                                }
178                                nextCode[bits] = code + (1 << (16 - bits));
179                        }
180                       
181                }
182               
183                /// <summary>
184                /// Reads the next symbol from input.  The symbol is encoded using the
185                /// huffman tree.
186                /// </summary>
187                /// <param name="input">
188                /// input the input source.
189                /// </param>
190                /// <returns>
191                /// the next symbol, or -1 if not enough input is available.
192                /// </returns>
193                public int GetSymbol(StreamManipulator input)
194                {
195                        int lookahead, symbol;
196                        if ((lookahead = input.PeekBits(9)) >= 0) {
197                                if ((symbol = tree[lookahead]) >= 0) {
198                                        input.DropBits(symbol & 15);
199                                        return symbol >> 4;
200                                }
201                                int subtree = -(symbol >> 4);
202                                int bitlen = symbol & 15;
203                                if ((lookahead = input.PeekBits(bitlen)) >= 0) {
204                                        symbol = tree[subtree | (lookahead >> 9)];
205                                        input.DropBits(symbol & 15);
206                                        return symbol >> 4;
207                                } else {
208                                        int bits = input.AvailableBits;
209                                        lookahead = input.PeekBits(bits);
210                                        symbol = tree[subtree | (lookahead >> 9)];
211                                        if ((symbol & 15) <= bits) {
212                                                input.DropBits(symbol & 15);
213                                                return symbol >> 4;
214                                        } else {
215                                                return -1;
216                                        }
217                                }
218                        } else {
219                                int bits = input.AvailableBits;
220                                lookahead = input.PeekBits(bits);
221                                symbol = tree[lookahead];
222                                if (symbol >= 0 && (symbol & 15) <= bits) {
223                                        input.DropBits(symbol & 15);
224                                        return symbol >> 4;
225                                } else {
226                                        return -1;
227                                }
228                        }
229                }
230        }
231}
232
Notatka: Zobacz TracBrowser aby uzyskać więcej informacji.