public FastEncoder(bool doGZip) { this.usingGzip = doGZip; this.inputWindow = new FastEncoderWindow(); this.inputBuffer = new DeflateInput(); this.output = new Output(); this.currentMatch = new Match(); }
public override void Close() { if (stream != null) { if (mode == CompressionMode.Decompress) { readBuf = null; } else { int maxByteCount = 0; for (int i = 0; i < byteCount.Length; i++) { if (byteCount[i] > maxByteCount) { compressByte = (byte)i; maxByteCount = byteCount[i]; } } BinaryWriter writer = new BinaryWriter(stream); writer.Write(compressByte); writer.Write((int)writeBuf.Length); byte[] inputBuf = writeBuf.GetBuffer(); int bufLength = (int)writeBuf.Length; int windowStart = 0; int windowEnd = 0; for (int i = 0; i < bufLength; ) { Match maxMatch = new Match(); int maxMatchLength = 0; for (int windowIdx = windowStart; windowIdx < windowEnd; windowIdx++) { int blockSize = 0; int numBlocks = 1; if (inputBuf[i] == inputBuf[windowIdx]) { for (int k = 1; k < 0xFF; k++) { blockSize++; int offset = i + k; if ((offset >= bufLength) || ((windowIdx + k) >= windowEnd) || (inputBuf[offset] != inputBuf[windowIdx + k])) { break; } } for (int k = 1; k < 0xFF; k++) { bool addBlock = true; for (int m = 0; m < blockSize; m++) { int offset = i + (blockSize * k) + m; if ((offset >= bufLength) || (inputBuf[offset] != inputBuf[windowIdx + m])) { addBlock = false; break; } } if (addBlock) { numBlocks++; } else { break; } } int matchLength = blockSize * numBlocks; if (matchLength > maxMatchLength) { maxMatch.blockSize = blockSize; maxMatch.numBlocks = numBlocks; maxMatch.distance = i - windowIdx; maxMatch.length = matchLength; maxMatchLength = matchLength; } } } int windowOffset = 1; if (maxMatchLength > 4) { writer.Write(compressByte); if (maxMatch.distance == compressByte) { writer.Write((byte)0); } else { writer.Write((byte)maxMatch.distance); } writer.Write((byte)maxMatch.blockSize); writer.Write((byte)maxMatch.numBlocks); i += maxMatch.length; windowOffset = maxMatch.length; } else { WriteSingleByte(writer, inputBuf[i], compressByte); i++; } windowEnd += windowOffset; int windowSize = windowEnd - windowStart; if (windowSize >= 0xFF) { windowStart += windowSize - 0xFF; } } writeBuf.Close(); writeBuf = null; byteCount = null; } if (!leaveOpen) { stream.Close(); } stream = null; } }
// // Find out what we should generate next. It can be a symbol, a distance/length pair // or a symbol followed by distance/length pair // internal bool GetNextSymbolOrMatch(Match match) { Debug.Assert(_bufPos >= FastEncoderWindowSize && _bufPos < (2 * FastEncoderWindowSize), "Invalid Buffer Position!"); // initialise the value of the hash, no problem if locations bufPos, bufPos+1 // are invalid (not enough data), since we will never insert using that hash value uint hash = HashValue(0, _window[_bufPos]); hash = HashValue(hash, _window[_bufPos + 1]); int matchLen; int matchPos = 0; VerifyHashes(); // Debug only code if (_bufEnd - _bufPos <= 3) { // The hash value becomes corrupt when we get within 3 characters of the end of the // input window, since the hash value is based on 3 characters. We just stop // inserting into the hash table at this point, and allow no matches. matchLen = 0; } else { // insert string into hash table and return most recent location of same hash value int search = (int)InsertString(ref hash); // did we find a recent location of this hash value? if (search != 0) { // yes, now find a match at what we'll call position X matchLen = FindMatch(search, out matchPos, SearchDepth, NiceLength); // truncate match if we're too close to the end of the input window if (_bufPos + matchLen > _bufEnd) matchLen = _bufEnd - _bufPos; } else { // no most recent location found matchLen = 0; } } if (matchLen < MinMatch) { // didn't find a match, so output unmatched char match.State = MatchState.HasSymbol; match.Symbol = _window[_bufPos]; _bufPos++; } else { // bufPos now points to X+1 _bufPos++; // is this match so good (long) that we should take it automatically without // checking X+1 ? if (matchLen <= LazyMatchThreshold) { int nextMatchLen; int nextMatchPos = 0; // search at position X+1 int search = (int)InsertString(ref hash); // no, so check for a better match at X+1 if (search != 0) { nextMatchLen = FindMatch(search, out nextMatchPos, matchLen < GoodLength ? SearchDepth : (SearchDepth >> 2), NiceLength); // truncate match if we're too close to the end of the window // note: nextMatchLen could now be < MinMatch if (_bufPos + nextMatchLen > _bufEnd) { nextMatchLen = _bufEnd - _bufPos; } } else { nextMatchLen = 0; } // right now X and X+1 are both inserted into the search tree if (nextMatchLen > matchLen) { // since nextMatchLen > matchLen, it can't be < MinMatch here // match at X+1 is better, so output unmatched char at X match.State = MatchState.HasSymbolAndMatch; match.Symbol = _window[_bufPos - 1]; match.Position = nextMatchPos; match.Length = nextMatchLen; // insert remainder of second match into search tree // example: (*=inserted already) // // X X+1 X+2 X+3 X+4 // * * // nextmatchlen=3 // bufPos // // If nextMatchLen == 3, we want to perform 2 // insertions (at X+2 and X+3). However, first we must // inc bufPos. // _bufPos++; // now points to X+2 matchLen = nextMatchLen; InsertStrings(ref hash, matchLen); } else { // match at X is better, so take it match.State = MatchState.HasMatch; match.Position = matchPos; match.Length = matchLen; // Insert remainder of first match into search tree, minus the first // two locations, which were inserted by the FindMatch() calls. // // For example, if matchLen == 3, then we've inserted at X and X+1 // already (and bufPos is now pointing at X+1), and now we need to insert // only at X+2. // matchLen--; _bufPos++; // now bufPos points to X+2 InsertStrings(ref hash, matchLen); } } else { // match_length >= good_match // in assertion: bufPos points to X+1, location X inserted already // first match is so good that we're not even going to check at X+1 match.State = MatchState.HasMatch; match.Position = matchPos; match.Length = matchLen; // insert remainder of match at X into search tree InsertStrings(ref hash, matchLen); } } if (_bufPos == 2 * FastEncoderWindowSize) { MoveWindows(); } return true; }
public FastEncoder() { inputWindow = new FastEncoderWindow(); currentMatch = new Match(); }
internal bool GetNextSymbolOrMatch(Match match) { int num2; uint hash = this.HashValue(0, this.window[this.bufPos]); hash = this.HashValue(hash, this.window[this.bufPos + 1]); int matchPos = 0; if ((this.bufEnd - this.bufPos) <= 3) { num2 = 0; } else { int search = (int) this.InsertString(ref hash); if (search != 0) { num2 = this.FindMatch(search, out matchPos, 0x20, 0x20); if ((this.bufPos + num2) > this.bufEnd) { num2 = this.bufEnd - this.bufPos; } } else { num2 = 0; } } if (num2 < 3) { match.State = MatchState.HasSymbol; match.Symbol = this.window[this.bufPos]; this.bufPos++; } else { this.bufPos++; if (num2 <= 6) { int num5; int num6 = 0; int num7 = (int) this.InsertString(ref hash); if (num7 != 0) { num5 = this.FindMatch(num7, out num6, (num2 < 4) ? 0x20 : 8, 0x20); if ((this.bufPos + num5) > this.bufEnd) { num5 = this.bufEnd - this.bufPos; } } else { num5 = 0; } if (num5 > num2) { match.State = MatchState.HasSymbolAndMatch; match.Symbol = this.window[this.bufPos - 1]; match.Position = num6; match.Length = num5; this.bufPos++; num2 = num5; this.InsertStrings(ref hash, num2); } else { match.State = MatchState.HasMatch; match.Position = matchPos; match.Length = num2; num2--; this.bufPos++; this.InsertStrings(ref hash, num2); } } else { match.State = MatchState.HasMatch; match.Position = matchPos; match.Length = num2; this.InsertStrings(ref hash, num2); } } if (this.bufPos == 0x4000) { this.MoveWindows(); } return true; }