private OffsetLengthPair FindMatchInSlidingWindow(byte[] input, int startIndex)
{
OffsetLengthPair match = new OffsetLengthPair();
if ((input.Length - startIndex) < minimumEncodeLength)
{
return match;
}
//create minimumEncodeLength bytes key
byte[] threeBytesHashKey = new byte[minimumEncodeLength];
Array.Copy(input, startIndex, threeBytesHashKey, 0, threeBytesHashKey.Length);
int[] findedPositions = hashTable.GetKeyMatchPositions(threeBytesHashKey);
//because hash table does not contain the hash value of last two characters
//so we need to caculate it after getting hash value from hash table.
List<int> matchPositions = new List<int>(findedPositions);
// indicate the match position
int matchedPosition = -1;
bool isMatchFound = false;
// if sliding windows count <=0, there is no match can be found, so do nothing
if (slidingWindow.Count > 0)
{
// test if there is a match at the last position of sliding windows
if (slidingWindow[slidingWindow.Count - 1] == input[startIndex]
&& input[startIndex] == input[startIndex + 1]
&& input[startIndex + 1] == input[startIndex + 2])
{
// the position is the last byte in sliding window
matchedPosition = slidingWindow.Count-1;
isMatchFound = true;
}
// test if there is a match at the second last position of sliding windows
if (slidingWindow.Count > 1)
{
if (slidingWindow[slidingWindow.Count - 2] == input[startIndex]
&& slidingWindow[slidingWindow.Count - 1] == input[startIndex + 1]
&& input[startIndex] == input[startIndex + 2])
{
// the position is the second last byte in sliding window
matchPositions.Add(slidingWindow.Count - 2);
isMatchFound = true;
}
}
}
//make sure the position will be added in ascending order.
if (matchedPosition != -1)
{
matchPositions.Add(matchedPosition);
}
// translate list to array if match is found from the second last position of sliding window
if (isMatchFound)
{
findedPositions = matchPositions.ToArray();
}
// if there is no match, return default match
if (findedPositions == null || findedPositions.Length == 0)
{
return match;
}
//caculate the offset and length
match.Offset = slidingWindow.Count - findedPositions[findedPositions.Length - 1];
match.Length = minimumEncodeLength;
for (int i = 0; i < findedPositions.Length; i++)
{
//skip already matched 3 characters
int searchIndex = startIndex + minimumEncodeLength;
int j;
for (j = (findedPositions[i]+minimumEncodeLength); j < slidingWindow.Count; j++)
{
// get the last unmatched position
if ((searchIndex == input.Length)
|| (slidingWindow[j] != input[searchIndex++]))
{
if (match.Length < (searchIndex - startIndex -1))
{
match.Length = searchIndex - startIndex -1;
match.Offset = slidingWindow.Count - findedPositions[i];
}
break;
}
}
// if length > offset
if (j >= slidingWindow.Count)
{
int mark = startIndex;
// the last two character case
if (j > 0)
{
mark = startIndex + j - slidingWindow.Count;
}
//continue find match against the current data
while (searchIndex < input.Length)
{
if (input[mark++] != input[searchIndex++])
{
// because upper line use searchIndex++, so at this position
// we need to reduce it by 1;
if (match.Length < (searchIndex - startIndex - 1))
{
match.Length = searchIndex - startIndex - 1;
match.Offset = slidingWindow.Count - findedPositions[i];
}
break;
}
}
// if searchIndex == inputLength, the way to caculate offset and length
// is different with the normal situation.
if (searchIndex == input.Length)
{
if (match.Length < searchIndex - startIndex)
{
match.Length = searchIndex - startIndex;
match.Offset = slidingWindow.Count - findedPositions[i];
}
}
}
}
return match;
}