📄 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) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -