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