public FastEncoder() { inputWindow = new FastEncoderWindow(); currentMatch = new Match(); }
// // 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; }