mirror of
https://github.com/ZDoom/Raze.git
synced 2024-12-11 13:21:49 +00:00
718112a8fe
Currently none of these is being used, but eventually they will, once more code gets ported over. So it's better to have them right away and avoid editing the project file too much, only to revert that later.
1127 lines
26 KiB
C
1127 lines
26 KiB
C
/* LzFind.c -- Match finder for LZ algorithms
|
|
2018-07-08 : Igor Pavlov : Public domain */
|
|
|
|
#include "Precomp.h"
|
|
|
|
#include <string.h>
|
|
|
|
#include "LzFind.h"
|
|
#include "LzHash.h"
|
|
|
|
#define kEmptyHashValue 0
|
|
#define kMaxValForNormalize ((UInt32)0xFFFFFFFF)
|
|
#define kNormalizeStepMin (1 << 10) /* it must be power of 2 */
|
|
#define kNormalizeMask (~(UInt32)(kNormalizeStepMin - 1))
|
|
#define kMaxHistorySize ((UInt32)7 << 29)
|
|
|
|
#define kStartMaxLen 3
|
|
|
|
static void LzInWindow_Free(CMatchFinder *p, ISzAllocPtr alloc)
|
|
{
|
|
if (!p->directInput)
|
|
{
|
|
ISzAlloc_Free(alloc, p->bufferBase);
|
|
p->bufferBase = NULL;
|
|
}
|
|
}
|
|
|
|
/* keepSizeBefore + keepSizeAfter + keepSizeReserv must be < 4G) */
|
|
|
|
static int LzInWindow_Create(CMatchFinder *p, UInt32 keepSizeReserv, ISzAllocPtr alloc)
|
|
{
|
|
UInt32 blockSize = p->keepSizeBefore + p->keepSizeAfter + keepSizeReserv;
|
|
if (p->directInput)
|
|
{
|
|
p->blockSize = blockSize;
|
|
return 1;
|
|
}
|
|
if (!p->bufferBase || p->blockSize != blockSize)
|
|
{
|
|
LzInWindow_Free(p, alloc);
|
|
p->blockSize = blockSize;
|
|
p->bufferBase = (Byte *)ISzAlloc_Alloc(alloc, (size_t)blockSize);
|
|
}
|
|
return (p->bufferBase != NULL);
|
|
}
|
|
|
|
Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; }
|
|
|
|
UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; }
|
|
|
|
void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue)
|
|
{
|
|
p->posLimit -= subValue;
|
|
p->pos -= subValue;
|
|
p->streamPos -= subValue;
|
|
}
|
|
|
|
static void MatchFinder_ReadBlock(CMatchFinder *p)
|
|
{
|
|
if (p->streamEndWasReached || p->result != SZ_OK)
|
|
return;
|
|
|
|
/* We use (p->streamPos - p->pos) value. (p->streamPos < p->pos) is allowed. */
|
|
|
|
if (p->directInput)
|
|
{
|
|
UInt32 curSize = 0xFFFFFFFF - (p->streamPos - p->pos);
|
|
if (curSize > p->directInputRem)
|
|
curSize = (UInt32)p->directInputRem;
|
|
p->directInputRem -= curSize;
|
|
p->streamPos += curSize;
|
|
if (p->directInputRem == 0)
|
|
p->streamEndWasReached = 1;
|
|
return;
|
|
}
|
|
|
|
for (;;)
|
|
{
|
|
Byte *dest = p->buffer + (p->streamPos - p->pos);
|
|
size_t size = (p->bufferBase + p->blockSize - dest);
|
|
if (size == 0)
|
|
return;
|
|
|
|
p->result = ISeqInStream_Read(p->stream, dest, &size);
|
|
if (p->result != SZ_OK)
|
|
return;
|
|
if (size == 0)
|
|
{
|
|
p->streamEndWasReached = 1;
|
|
return;
|
|
}
|
|
p->streamPos += (UInt32)size;
|
|
if (p->streamPos - p->pos > p->keepSizeAfter)
|
|
return;
|
|
}
|
|
}
|
|
|
|
void MatchFinder_MoveBlock(CMatchFinder *p)
|
|
{
|
|
memmove(p->bufferBase,
|
|
p->buffer - p->keepSizeBefore,
|
|
(size_t)(p->streamPos - p->pos) + p->keepSizeBefore);
|
|
p->buffer = p->bufferBase + p->keepSizeBefore;
|
|
}
|
|
|
|
int MatchFinder_NeedMove(CMatchFinder *p)
|
|
{
|
|
if (p->directInput)
|
|
return 0;
|
|
/* if (p->streamEndWasReached) return 0; */
|
|
return ((size_t)(p->bufferBase + p->blockSize - p->buffer) <= p->keepSizeAfter);
|
|
}
|
|
|
|
void MatchFinder_ReadIfRequired(CMatchFinder *p)
|
|
{
|
|
if (p->streamEndWasReached)
|
|
return;
|
|
if (p->keepSizeAfter >= p->streamPos - p->pos)
|
|
MatchFinder_ReadBlock(p);
|
|
}
|
|
|
|
static void MatchFinder_CheckAndMoveAndRead(CMatchFinder *p)
|
|
{
|
|
if (MatchFinder_NeedMove(p))
|
|
MatchFinder_MoveBlock(p);
|
|
MatchFinder_ReadBlock(p);
|
|
}
|
|
|
|
static void MatchFinder_SetDefaultSettings(CMatchFinder *p)
|
|
{
|
|
p->cutValue = 32;
|
|
p->btMode = 1;
|
|
p->numHashBytes = 4;
|
|
p->bigHash = 0;
|
|
}
|
|
|
|
#define kCrcPoly 0xEDB88320
|
|
|
|
void MatchFinder_Construct(CMatchFinder *p)
|
|
{
|
|
unsigned i;
|
|
p->bufferBase = NULL;
|
|
p->directInput = 0;
|
|
p->hash = NULL;
|
|
p->expectedDataSize = (UInt64)(Int64)-1;
|
|
MatchFinder_SetDefaultSettings(p);
|
|
|
|
for (i = 0; i < 256; i++)
|
|
{
|
|
UInt32 r = (UInt32)i;
|
|
unsigned j;
|
|
for (j = 0; j < 8; j++)
|
|
r = (r >> 1) ^ (kCrcPoly & ((UInt32)0 - (r & 1)));
|
|
p->crc[i] = r;
|
|
}
|
|
}
|
|
|
|
static void MatchFinder_FreeThisClassMemory(CMatchFinder *p, ISzAllocPtr alloc)
|
|
{
|
|
ISzAlloc_Free(alloc, p->hash);
|
|
p->hash = NULL;
|
|
}
|
|
|
|
void MatchFinder_Free(CMatchFinder *p, ISzAllocPtr alloc)
|
|
{
|
|
MatchFinder_FreeThisClassMemory(p, alloc);
|
|
LzInWindow_Free(p, alloc);
|
|
}
|
|
|
|
static CLzRef* AllocRefs(size_t num, ISzAllocPtr alloc)
|
|
{
|
|
size_t sizeInBytes = (size_t)num * sizeof(CLzRef);
|
|
if (sizeInBytes / sizeof(CLzRef) != num)
|
|
return NULL;
|
|
return (CLzRef *)ISzAlloc_Alloc(alloc, sizeInBytes);
|
|
}
|
|
|
|
int MatchFinder_Create(CMatchFinder *p, UInt32 historySize,
|
|
UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,
|
|
ISzAllocPtr alloc)
|
|
{
|
|
UInt32 sizeReserv;
|
|
|
|
if (historySize > kMaxHistorySize)
|
|
{
|
|
MatchFinder_Free(p, alloc);
|
|
return 0;
|
|
}
|
|
|
|
sizeReserv = historySize >> 1;
|
|
if (historySize >= ((UInt32)3 << 30)) sizeReserv = historySize >> 3;
|
|
else if (historySize >= ((UInt32)2 << 30)) sizeReserv = historySize >> 2;
|
|
|
|
sizeReserv += (keepAddBufferBefore + matchMaxLen + keepAddBufferAfter) / 2 + (1 << 19);
|
|
|
|
p->keepSizeBefore = historySize + keepAddBufferBefore + 1;
|
|
p->keepSizeAfter = matchMaxLen + keepAddBufferAfter;
|
|
|
|
/* we need one additional byte, since we use MoveBlock after pos++ and before dictionary using */
|
|
|
|
if (LzInWindow_Create(p, sizeReserv, alloc))
|
|
{
|
|
UInt32 newCyclicBufferSize = historySize + 1;
|
|
UInt32 hs;
|
|
p->matchMaxLen = matchMaxLen;
|
|
{
|
|
p->fixedHashSize = 0;
|
|
if (p->numHashBytes == 2)
|
|
hs = (1 << 16) - 1;
|
|
else
|
|
{
|
|
hs = historySize;
|
|
if (hs > p->expectedDataSize)
|
|
hs = (UInt32)p->expectedDataSize;
|
|
if (hs != 0)
|
|
hs--;
|
|
hs |= (hs >> 1);
|
|
hs |= (hs >> 2);
|
|
hs |= (hs >> 4);
|
|
hs |= (hs >> 8);
|
|
hs >>= 1;
|
|
hs |= 0xFFFF; /* don't change it! It's required for Deflate */
|
|
if (hs > (1 << 24))
|
|
{
|
|
if (p->numHashBytes == 3)
|
|
hs = (1 << 24) - 1;
|
|
else
|
|
hs >>= 1;
|
|
/* if (bigHash) mode, GetHeads4b() in LzFindMt.c needs (hs >= ((1 << 24) - 1))) */
|
|
}
|
|
}
|
|
p->hashMask = hs;
|
|
hs++;
|
|
if (p->numHashBytes > 2) p->fixedHashSize += kHash2Size;
|
|
if (p->numHashBytes > 3) p->fixedHashSize += kHash3Size;
|
|
if (p->numHashBytes > 4) p->fixedHashSize += kHash4Size;
|
|
hs += p->fixedHashSize;
|
|
}
|
|
|
|
{
|
|
size_t newSize;
|
|
size_t numSons;
|
|
p->historySize = historySize;
|
|
p->hashSizeSum = hs;
|
|
p->cyclicBufferSize = newCyclicBufferSize;
|
|
|
|
numSons = newCyclicBufferSize;
|
|
if (p->btMode)
|
|
numSons <<= 1;
|
|
newSize = hs + numSons;
|
|
|
|
if (p->hash && p->numRefs == newSize)
|
|
return 1;
|
|
|
|
MatchFinder_FreeThisClassMemory(p, alloc);
|
|
p->numRefs = newSize;
|
|
p->hash = AllocRefs(newSize, alloc);
|
|
|
|
if (p->hash)
|
|
{
|
|
p->son = p->hash + p->hashSizeSum;
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
MatchFinder_Free(p, alloc);
|
|
return 0;
|
|
}
|
|
|
|
static void MatchFinder_SetLimits(CMatchFinder *p)
|
|
{
|
|
UInt32 limit = kMaxValForNormalize - p->pos;
|
|
UInt32 limit2 = p->cyclicBufferSize - p->cyclicBufferPos;
|
|
|
|
if (limit2 < limit)
|
|
limit = limit2;
|
|
limit2 = p->streamPos - p->pos;
|
|
|
|
if (limit2 <= p->keepSizeAfter)
|
|
{
|
|
if (limit2 > 0)
|
|
limit2 = 1;
|
|
}
|
|
else
|
|
limit2 -= p->keepSizeAfter;
|
|
|
|
if (limit2 < limit)
|
|
limit = limit2;
|
|
|
|
{
|
|
UInt32 lenLimit = p->streamPos - p->pos;
|
|
if (lenLimit > p->matchMaxLen)
|
|
lenLimit = p->matchMaxLen;
|
|
p->lenLimit = lenLimit;
|
|
}
|
|
p->posLimit = p->pos + limit;
|
|
}
|
|
|
|
|
|
void MatchFinder_Init_LowHash(CMatchFinder *p)
|
|
{
|
|
size_t i;
|
|
CLzRef *items = p->hash;
|
|
size_t numItems = p->fixedHashSize;
|
|
for (i = 0; i < numItems; i++)
|
|
items[i] = kEmptyHashValue;
|
|
}
|
|
|
|
|
|
void MatchFinder_Init_HighHash(CMatchFinder *p)
|
|
{
|
|
size_t i;
|
|
CLzRef *items = p->hash + p->fixedHashSize;
|
|
size_t numItems = (size_t)p->hashMask + 1;
|
|
for (i = 0; i < numItems; i++)
|
|
items[i] = kEmptyHashValue;
|
|
}
|
|
|
|
|
|
void MatchFinder_Init_3(CMatchFinder *p, int readData)
|
|
{
|
|
p->cyclicBufferPos = 0;
|
|
p->buffer = p->bufferBase;
|
|
p->pos =
|
|
p->streamPos = p->cyclicBufferSize;
|
|
p->result = SZ_OK;
|
|
p->streamEndWasReached = 0;
|
|
|
|
if (readData)
|
|
MatchFinder_ReadBlock(p);
|
|
|
|
MatchFinder_SetLimits(p);
|
|
}
|
|
|
|
|
|
void MatchFinder_Init(CMatchFinder *p)
|
|
{
|
|
MatchFinder_Init_HighHash(p);
|
|
MatchFinder_Init_LowHash(p);
|
|
MatchFinder_Init_3(p, True);
|
|
}
|
|
|
|
|
|
static UInt32 MatchFinder_GetSubValue(CMatchFinder *p)
|
|
{
|
|
return (p->pos - p->historySize - 1) & kNormalizeMask;
|
|
}
|
|
|
|
void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, size_t numItems)
|
|
{
|
|
size_t i;
|
|
for (i = 0; i < numItems; i++)
|
|
{
|
|
UInt32 value = items[i];
|
|
if (value <= subValue)
|
|
value = kEmptyHashValue;
|
|
else
|
|
value -= subValue;
|
|
items[i] = value;
|
|
}
|
|
}
|
|
|
|
static void MatchFinder_Normalize(CMatchFinder *p)
|
|
{
|
|
UInt32 subValue = MatchFinder_GetSubValue(p);
|
|
MatchFinder_Normalize3(subValue, p->hash, p->numRefs);
|
|
MatchFinder_ReduceOffsets(p, subValue);
|
|
}
|
|
|
|
|
|
MY_NO_INLINE
|
|
static void MatchFinder_CheckLimits(CMatchFinder *p)
|
|
{
|
|
if (p->pos == kMaxValForNormalize)
|
|
MatchFinder_Normalize(p);
|
|
if (!p->streamEndWasReached && p->keepSizeAfter == p->streamPos - p->pos)
|
|
MatchFinder_CheckAndMoveAndRead(p);
|
|
if (p->cyclicBufferPos == p->cyclicBufferSize)
|
|
p->cyclicBufferPos = 0;
|
|
MatchFinder_SetLimits(p);
|
|
}
|
|
|
|
|
|
/*
|
|
(lenLimit > maxLen)
|
|
*/
|
|
MY_FORCE_INLINE
|
|
static UInt32 * Hc_GetMatchesSpec(unsigned lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
|
|
UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue,
|
|
UInt32 *distances, unsigned maxLen)
|
|
{
|
|
/*
|
|
son[_cyclicBufferPos] = curMatch;
|
|
for (;;)
|
|
{
|
|
UInt32 delta = pos - curMatch;
|
|
if (cutValue-- == 0 || delta >= _cyclicBufferSize)
|
|
return distances;
|
|
{
|
|
const Byte *pb = cur - delta;
|
|
curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)];
|
|
if (pb[maxLen] == cur[maxLen] && *pb == *cur)
|
|
{
|
|
UInt32 len = 0;
|
|
while (++len != lenLimit)
|
|
if (pb[len] != cur[len])
|
|
break;
|
|
if (maxLen < len)
|
|
{
|
|
maxLen = len;
|
|
*distances++ = len;
|
|
*distances++ = delta - 1;
|
|
if (len == lenLimit)
|
|
return distances;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
|
|
const Byte *lim = cur + lenLimit;
|
|
son[_cyclicBufferPos] = curMatch;
|
|
do
|
|
{
|
|
UInt32 delta = pos - curMatch;
|
|
if (delta >= _cyclicBufferSize)
|
|
break;
|
|
{
|
|
ptrdiff_t diff;
|
|
curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)];
|
|
diff = (ptrdiff_t)0 - delta;
|
|
if (cur[maxLen] == cur[maxLen + diff])
|
|
{
|
|
const Byte *c = cur;
|
|
while (*c == c[diff])
|
|
{
|
|
if (++c == lim)
|
|
{
|
|
distances[0] = (UInt32)(lim - cur);
|
|
distances[1] = delta - 1;
|
|
return distances + 2;
|
|
}
|
|
}
|
|
{
|
|
unsigned len = (unsigned)(c - cur);
|
|
if (maxLen < len)
|
|
{
|
|
maxLen = len;
|
|
distances[0] = (UInt32)len;
|
|
distances[1] = delta - 1;
|
|
distances += 2;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
while (--cutValue);
|
|
|
|
return distances;
|
|
}
|
|
|
|
|
|
MY_FORCE_INLINE
|
|
UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
|
|
UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue,
|
|
UInt32 *distances, UInt32 maxLen)
|
|
{
|
|
CLzRef *ptr0 = son + ((size_t)_cyclicBufferPos << 1) + 1;
|
|
CLzRef *ptr1 = son + ((size_t)_cyclicBufferPos << 1);
|
|
unsigned len0 = 0, len1 = 0;
|
|
for (;;)
|
|
{
|
|
UInt32 delta = pos - curMatch;
|
|
if (cutValue-- == 0 || delta >= _cyclicBufferSize)
|
|
{
|
|
*ptr0 = *ptr1 = kEmptyHashValue;
|
|
return distances;
|
|
}
|
|
{
|
|
CLzRef *pair = son + ((size_t)(_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
|
|
const Byte *pb = cur - delta;
|
|
unsigned len = (len0 < len1 ? len0 : len1);
|
|
UInt32 pair0 = pair[0];
|
|
if (pb[len] == cur[len])
|
|
{
|
|
if (++len != lenLimit && pb[len] == cur[len])
|
|
while (++len != lenLimit)
|
|
if (pb[len] != cur[len])
|
|
break;
|
|
if (maxLen < len)
|
|
{
|
|
maxLen = (UInt32)len;
|
|
*distances++ = (UInt32)len;
|
|
*distances++ = delta - 1;
|
|
if (len == lenLimit)
|
|
{
|
|
*ptr1 = pair0;
|
|
*ptr0 = pair[1];
|
|
return distances;
|
|
}
|
|
}
|
|
}
|
|
if (pb[len] < cur[len])
|
|
{
|
|
*ptr1 = curMatch;
|
|
ptr1 = pair + 1;
|
|
curMatch = *ptr1;
|
|
len1 = len;
|
|
}
|
|
else
|
|
{
|
|
*ptr0 = curMatch;
|
|
ptr0 = pair;
|
|
curMatch = *ptr0;
|
|
len0 = len;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void SkipMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
|
|
UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue)
|
|
{
|
|
CLzRef *ptr0 = son + ((size_t)_cyclicBufferPos << 1) + 1;
|
|
CLzRef *ptr1 = son + ((size_t)_cyclicBufferPos << 1);
|
|
unsigned len0 = 0, len1 = 0;
|
|
for (;;)
|
|
{
|
|
UInt32 delta = pos - curMatch;
|
|
if (cutValue-- == 0 || delta >= _cyclicBufferSize)
|
|
{
|
|
*ptr0 = *ptr1 = kEmptyHashValue;
|
|
return;
|
|
}
|
|
{
|
|
CLzRef *pair = son + ((size_t)(_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
|
|
const Byte *pb = cur - delta;
|
|
unsigned len = (len0 < len1 ? len0 : len1);
|
|
if (pb[len] == cur[len])
|
|
{
|
|
while (++len != lenLimit)
|
|
if (pb[len] != cur[len])
|
|
break;
|
|
{
|
|
if (len == lenLimit)
|
|
{
|
|
*ptr1 = pair[0];
|
|
*ptr0 = pair[1];
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
if (pb[len] < cur[len])
|
|
{
|
|
*ptr1 = curMatch;
|
|
ptr1 = pair + 1;
|
|
curMatch = *ptr1;
|
|
len1 = len;
|
|
}
|
|
else
|
|
{
|
|
*ptr0 = curMatch;
|
|
ptr0 = pair;
|
|
curMatch = *ptr0;
|
|
len0 = len;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#define MOVE_POS \
|
|
++p->cyclicBufferPos; \
|
|
p->buffer++; \
|
|
if (++p->pos == p->posLimit) MatchFinder_CheckLimits(p);
|
|
|
|
#define MOVE_POS_RET MOVE_POS return (UInt32)offset;
|
|
|
|
static void MatchFinder_MovePos(CMatchFinder *p) { MOVE_POS; }
|
|
|
|
#define GET_MATCHES_HEADER2(minLen, ret_op) \
|
|
unsigned lenLimit; UInt32 hv; const Byte *cur; UInt32 curMatch; \
|
|
lenLimit = (unsigned)p->lenLimit; { if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; }} \
|
|
cur = p->buffer;
|
|
|
|
#define GET_MATCHES_HEADER(minLen) GET_MATCHES_HEADER2(minLen, return 0)
|
|
#define SKIP_HEADER(minLen) GET_MATCHES_HEADER2(minLen, continue)
|
|
|
|
#define MF_PARAMS(p) p->pos, p->buffer, p->son, p->cyclicBufferPos, p->cyclicBufferSize, p->cutValue
|
|
|
|
#define GET_MATCHES_FOOTER(offset, maxLen) \
|
|
offset = (unsigned)(GetMatchesSpec1((UInt32)lenLimit, curMatch, MF_PARAMS(p), \
|
|
distances + offset, (UInt32)maxLen) - distances); MOVE_POS_RET;
|
|
|
|
#define SKIP_FOOTER \
|
|
SkipMatchesSpec((UInt32)lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS;
|
|
|
|
#define UPDATE_maxLen { \
|
|
ptrdiff_t diff = (ptrdiff_t)0 - d2; \
|
|
const Byte *c = cur + maxLen; \
|
|
const Byte *lim = cur + lenLimit; \
|
|
for (; c != lim; c++) if (*(c + diff) != *c) break; \
|
|
maxLen = (unsigned)(c - cur); }
|
|
|
|
static UInt32 Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
|
|
{
|
|
unsigned offset;
|
|
GET_MATCHES_HEADER(2)
|
|
HASH2_CALC;
|
|
curMatch = p->hash[hv];
|
|
p->hash[hv] = p->pos;
|
|
offset = 0;
|
|
GET_MATCHES_FOOTER(offset, 1)
|
|
}
|
|
|
|
UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
|
|
{
|
|
unsigned offset;
|
|
GET_MATCHES_HEADER(3)
|
|
HASH_ZIP_CALC;
|
|
curMatch = p->hash[hv];
|
|
p->hash[hv] = p->pos;
|
|
offset = 0;
|
|
GET_MATCHES_FOOTER(offset, 2)
|
|
}
|
|
|
|
static UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
|
|
{
|
|
UInt32 h2, d2, pos;
|
|
unsigned maxLen, offset;
|
|
UInt32 *hash;
|
|
GET_MATCHES_HEADER(3)
|
|
|
|
HASH3_CALC;
|
|
|
|
hash = p->hash;
|
|
pos = p->pos;
|
|
|
|
d2 = pos - hash[h2];
|
|
|
|
curMatch = (hash + kFix3HashSize)[hv];
|
|
|
|
hash[h2] = pos;
|
|
(hash + kFix3HashSize)[hv] = pos;
|
|
|
|
maxLen = 2;
|
|
offset = 0;
|
|
|
|
if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur)
|
|
{
|
|
UPDATE_maxLen
|
|
distances[0] = (UInt32)maxLen;
|
|
distances[1] = d2 - 1;
|
|
offset = 2;
|
|
if (maxLen == lenLimit)
|
|
{
|
|
SkipMatchesSpec((UInt32)lenLimit, curMatch, MF_PARAMS(p));
|
|
MOVE_POS_RET;
|
|
}
|
|
}
|
|
|
|
GET_MATCHES_FOOTER(offset, maxLen)
|
|
}
|
|
|
|
static UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
|
|
{
|
|
UInt32 h2, h3, d2, d3, pos;
|
|
unsigned maxLen, offset;
|
|
UInt32 *hash;
|
|
GET_MATCHES_HEADER(4)
|
|
|
|
HASH4_CALC;
|
|
|
|
hash = p->hash;
|
|
pos = p->pos;
|
|
|
|
d2 = pos - hash [h2];
|
|
d3 = pos - (hash + kFix3HashSize)[h3];
|
|
|
|
curMatch = (hash + kFix4HashSize)[hv];
|
|
|
|
hash [h2] = pos;
|
|
(hash + kFix3HashSize)[h3] = pos;
|
|
(hash + kFix4HashSize)[hv] = pos;
|
|
|
|
maxLen = 0;
|
|
offset = 0;
|
|
|
|
if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur)
|
|
{
|
|
maxLen = 2;
|
|
distances[0] = 2;
|
|
distances[1] = d2 - 1;
|
|
offset = 2;
|
|
}
|
|
|
|
if (d2 != d3 && d3 < p->cyclicBufferSize && *(cur - d3) == *cur)
|
|
{
|
|
maxLen = 3;
|
|
distances[(size_t)offset + 1] = d3 - 1;
|
|
offset += 2;
|
|
d2 = d3;
|
|
}
|
|
|
|
if (offset != 0)
|
|
{
|
|
UPDATE_maxLen
|
|
distances[(size_t)offset - 2] = (UInt32)maxLen;
|
|
if (maxLen == lenLimit)
|
|
{
|
|
SkipMatchesSpec((UInt32)lenLimit, curMatch, MF_PARAMS(p));
|
|
MOVE_POS_RET;
|
|
}
|
|
}
|
|
|
|
if (maxLen < 3)
|
|
maxLen = 3;
|
|
|
|
GET_MATCHES_FOOTER(offset, maxLen)
|
|
}
|
|
|
|
/*
|
|
static UInt32 Bt5_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
|
|
{
|
|
UInt32 h2, h3, h4, d2, d3, d4, maxLen, offset, pos;
|
|
UInt32 *hash;
|
|
GET_MATCHES_HEADER(5)
|
|
|
|
HASH5_CALC;
|
|
|
|
hash = p->hash;
|
|
pos = p->pos;
|
|
|
|
d2 = pos - hash [h2];
|
|
d3 = pos - (hash + kFix3HashSize)[h3];
|
|
d4 = pos - (hash + kFix4HashSize)[h4];
|
|
|
|
curMatch = (hash + kFix5HashSize)[hv];
|
|
|
|
hash [h2] = pos;
|
|
(hash + kFix3HashSize)[h3] = pos;
|
|
(hash + kFix4HashSize)[h4] = pos;
|
|
(hash + kFix5HashSize)[hv] = pos;
|
|
|
|
maxLen = 0;
|
|
offset = 0;
|
|
|
|
if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur)
|
|
{
|
|
distances[0] = maxLen = 2;
|
|
distances[1] = d2 - 1;
|
|
offset = 2;
|
|
if (*(cur - d2 + 2) == cur[2])
|
|
distances[0] = maxLen = 3;
|
|
else if (d3 < p->cyclicBufferSize && *(cur - d3) == *cur)
|
|
{
|
|
distances[2] = maxLen = 3;
|
|
distances[3] = d3 - 1;
|
|
offset = 4;
|
|
d2 = d3;
|
|
}
|
|
}
|
|
else if (d3 < p->cyclicBufferSize && *(cur - d3) == *cur)
|
|
{
|
|
distances[0] = maxLen = 3;
|
|
distances[1] = d3 - 1;
|
|
offset = 2;
|
|
d2 = d3;
|
|
}
|
|
|
|
if (d2 != d4 && d4 < p->cyclicBufferSize
|
|
&& *(cur - d4) == *cur
|
|
&& *(cur - d4 + 3) == *(cur + 3))
|
|
{
|
|
maxLen = 4;
|
|
distances[(size_t)offset + 1] = d4 - 1;
|
|
offset += 2;
|
|
d2 = d4;
|
|
}
|
|
|
|
if (offset != 0)
|
|
{
|
|
UPDATE_maxLen
|
|
distances[(size_t)offset - 2] = maxLen;
|
|
if (maxLen == lenLimit)
|
|
{
|
|
SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p));
|
|
MOVE_POS_RET;
|
|
}
|
|
}
|
|
|
|
if (maxLen < 4)
|
|
maxLen = 4;
|
|
|
|
GET_MATCHES_FOOTER(offset, maxLen)
|
|
}
|
|
*/
|
|
|
|
static UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
|
|
{
|
|
UInt32 h2, h3, d2, d3, pos;
|
|
unsigned maxLen, offset;
|
|
UInt32 *hash;
|
|
GET_MATCHES_HEADER(4)
|
|
|
|
HASH4_CALC;
|
|
|
|
hash = p->hash;
|
|
pos = p->pos;
|
|
|
|
d2 = pos - hash [h2];
|
|
d3 = pos - (hash + kFix3HashSize)[h3];
|
|
curMatch = (hash + kFix4HashSize)[hv];
|
|
|
|
hash [h2] = pos;
|
|
(hash + kFix3HashSize)[h3] = pos;
|
|
(hash + kFix4HashSize)[hv] = pos;
|
|
|
|
maxLen = 0;
|
|
offset = 0;
|
|
|
|
if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur)
|
|
{
|
|
maxLen = 2;
|
|
distances[0] = 2;
|
|
distances[1] = d2 - 1;
|
|
offset = 2;
|
|
}
|
|
|
|
if (d2 != d3 && d3 < p->cyclicBufferSize && *(cur - d3) == *cur)
|
|
{
|
|
maxLen = 3;
|
|
distances[(size_t)offset + 1] = d3 - 1;
|
|
offset += 2;
|
|
d2 = d3;
|
|
}
|
|
|
|
if (offset != 0)
|
|
{
|
|
UPDATE_maxLen
|
|
distances[(size_t)offset - 2] = (UInt32)maxLen;
|
|
if (maxLen == lenLimit)
|
|
{
|
|
p->son[p->cyclicBufferPos] = curMatch;
|
|
MOVE_POS_RET;
|
|
}
|
|
}
|
|
|
|
if (maxLen < 3)
|
|
maxLen = 3;
|
|
|
|
offset = (unsigned)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
|
|
distances + offset, maxLen) - (distances));
|
|
MOVE_POS_RET
|
|
}
|
|
|
|
/*
|
|
static UInt32 Hc5_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
|
|
{
|
|
UInt32 h2, h3, h4, d2, d3, d4, maxLen, offset, pos
|
|
UInt32 *hash;
|
|
GET_MATCHES_HEADER(5)
|
|
|
|
HASH5_CALC;
|
|
|
|
hash = p->hash;
|
|
pos = p->pos;
|
|
|
|
d2 = pos - hash [h2];
|
|
d3 = pos - (hash + kFix3HashSize)[h3];
|
|
d4 = pos - (hash + kFix4HashSize)[h4];
|
|
|
|
curMatch = (hash + kFix5HashSize)[hv];
|
|
|
|
hash [h2] = pos;
|
|
(hash + kFix3HashSize)[h3] = pos;
|
|
(hash + kFix4HashSize)[h4] = pos;
|
|
(hash + kFix5HashSize)[hv] = pos;
|
|
|
|
maxLen = 0;
|
|
offset = 0;
|
|
|
|
if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur)
|
|
{
|
|
distances[0] = maxLen = 2;
|
|
distances[1] = d2 - 1;
|
|
offset = 2;
|
|
if (*(cur - d2 + 2) == cur[2])
|
|
distances[0] = maxLen = 3;
|
|
else if (d3 < p->cyclicBufferSize && *(cur - d3) == *cur)
|
|
{
|
|
distances[2] = maxLen = 3;
|
|
distances[3] = d3 - 1;
|
|
offset = 4;
|
|
d2 = d3;
|
|
}
|
|
}
|
|
else if (d3 < p->cyclicBufferSize && *(cur - d3) == *cur)
|
|
{
|
|
distances[0] = maxLen = 3;
|
|
distances[1] = d3 - 1;
|
|
offset = 2;
|
|
d2 = d3;
|
|
}
|
|
|
|
if (d2 != d4 && d4 < p->cyclicBufferSize
|
|
&& *(cur - d4) == *cur
|
|
&& *(cur - d4 + 3) == *(cur + 3))
|
|
{
|
|
maxLen = 4;
|
|
distances[(size_t)offset + 1] = d4 - 1;
|
|
offset += 2;
|
|
d2 = d4;
|
|
}
|
|
|
|
if (offset != 0)
|
|
{
|
|
UPDATE_maxLen
|
|
distances[(size_t)offset - 2] = maxLen;
|
|
if (maxLen == lenLimit)
|
|
{
|
|
p->son[p->cyclicBufferPos] = curMatch;
|
|
MOVE_POS_RET;
|
|
}
|
|
}
|
|
|
|
if (maxLen < 4)
|
|
maxLen = 4;
|
|
|
|
offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
|
|
distances + offset, maxLen) - (distances));
|
|
MOVE_POS_RET
|
|
}
|
|
*/
|
|
|
|
UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
|
|
{
|
|
unsigned offset;
|
|
GET_MATCHES_HEADER(3)
|
|
HASH_ZIP_CALC;
|
|
curMatch = p->hash[hv];
|
|
p->hash[hv] = p->pos;
|
|
offset = (unsigned)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
|
|
distances, 2) - (distances));
|
|
MOVE_POS_RET
|
|
}
|
|
|
|
static void Bt2_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
|
|
{
|
|
do
|
|
{
|
|
SKIP_HEADER(2)
|
|
HASH2_CALC;
|
|
curMatch = p->hash[hv];
|
|
p->hash[hv] = p->pos;
|
|
SKIP_FOOTER
|
|
}
|
|
while (--num != 0);
|
|
}
|
|
|
|
void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
|
|
{
|
|
do
|
|
{
|
|
SKIP_HEADER(3)
|
|
HASH_ZIP_CALC;
|
|
curMatch = p->hash[hv];
|
|
p->hash[hv] = p->pos;
|
|
SKIP_FOOTER
|
|
}
|
|
while (--num != 0);
|
|
}
|
|
|
|
static void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
|
|
{
|
|
do
|
|
{
|
|
UInt32 h2;
|
|
UInt32 *hash;
|
|
SKIP_HEADER(3)
|
|
HASH3_CALC;
|
|
hash = p->hash;
|
|
curMatch = (hash + kFix3HashSize)[hv];
|
|
hash[h2] =
|
|
(hash + kFix3HashSize)[hv] = p->pos;
|
|
SKIP_FOOTER
|
|
}
|
|
while (--num != 0);
|
|
}
|
|
|
|
static void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
|
|
{
|
|
do
|
|
{
|
|
UInt32 h2, h3;
|
|
UInt32 *hash;
|
|
SKIP_HEADER(4)
|
|
HASH4_CALC;
|
|
hash = p->hash;
|
|
curMatch = (hash + kFix4HashSize)[hv];
|
|
hash [h2] =
|
|
(hash + kFix3HashSize)[h3] =
|
|
(hash + kFix4HashSize)[hv] = p->pos;
|
|
SKIP_FOOTER
|
|
}
|
|
while (--num != 0);
|
|
}
|
|
|
|
/*
|
|
static void Bt5_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
|
|
{
|
|
do
|
|
{
|
|
UInt32 h2, h3, h4;
|
|
UInt32 *hash;
|
|
SKIP_HEADER(5)
|
|
HASH5_CALC;
|
|
hash = p->hash;
|
|
curMatch = (hash + kFix5HashSize)[hv];
|
|
hash [h2] =
|
|
(hash + kFix3HashSize)[h3] =
|
|
(hash + kFix4HashSize)[h4] =
|
|
(hash + kFix5HashSize)[hv] = p->pos;
|
|
SKIP_FOOTER
|
|
}
|
|
while (--num != 0);
|
|
}
|
|
*/
|
|
|
|
static void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
|
|
{
|
|
do
|
|
{
|
|
UInt32 h2, h3;
|
|
UInt32 *hash;
|
|
SKIP_HEADER(4)
|
|
HASH4_CALC;
|
|
hash = p->hash;
|
|
curMatch = (hash + kFix4HashSize)[hv];
|
|
hash [h2] =
|
|
(hash + kFix3HashSize)[h3] =
|
|
(hash + kFix4HashSize)[hv] = p->pos;
|
|
p->son[p->cyclicBufferPos] = curMatch;
|
|
MOVE_POS
|
|
}
|
|
while (--num != 0);
|
|
}
|
|
|
|
/*
|
|
static void Hc5_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
|
|
{
|
|
do
|
|
{
|
|
UInt32 h2, h3, h4;
|
|
UInt32 *hash;
|
|
SKIP_HEADER(5)
|
|
HASH5_CALC;
|
|
hash = p->hash;
|
|
curMatch = hash + kFix5HashSize)[hv];
|
|
hash [h2] =
|
|
(hash + kFix3HashSize)[h3] =
|
|
(hash + kFix4HashSize)[h4] =
|
|
(hash + kFix5HashSize)[hv] = p->pos;
|
|
p->son[p->cyclicBufferPos] = curMatch;
|
|
MOVE_POS
|
|
}
|
|
while (--num != 0);
|
|
}
|
|
*/
|
|
|
|
void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
|
|
{
|
|
do
|
|
{
|
|
SKIP_HEADER(3)
|
|
HASH_ZIP_CALC;
|
|
curMatch = p->hash[hv];
|
|
p->hash[hv] = p->pos;
|
|
p->son[p->cyclicBufferPos] = curMatch;
|
|
MOVE_POS
|
|
}
|
|
while (--num != 0);
|
|
}
|
|
|
|
void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable)
|
|
{
|
|
vTable->Init = (Mf_Init_Func)MatchFinder_Init;
|
|
vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes;
|
|
vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos;
|
|
if (!p->btMode)
|
|
{
|
|
/* if (p->numHashBytes <= 4) */
|
|
{
|
|
vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches;
|
|
vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip;
|
|
}
|
|
/*
|
|
else
|
|
{
|
|
vTable->GetMatches = (Mf_GetMatches_Func)Hc5_MatchFinder_GetMatches;
|
|
vTable->Skip = (Mf_Skip_Func)Hc5_MatchFinder_Skip;
|
|
}
|
|
*/
|
|
}
|
|
else if (p->numHashBytes == 2)
|
|
{
|
|
vTable->GetMatches = (Mf_GetMatches_Func)Bt2_MatchFinder_GetMatches;
|
|
vTable->Skip = (Mf_Skip_Func)Bt2_MatchFinder_Skip;
|
|
}
|
|
else if (p->numHashBytes == 3)
|
|
{
|
|
vTable->GetMatches = (Mf_GetMatches_Func)Bt3_MatchFinder_GetMatches;
|
|
vTable->Skip = (Mf_Skip_Func)Bt3_MatchFinder_Skip;
|
|
}
|
|
else /* if (p->numHashBytes == 4) */
|
|
{
|
|
vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches;
|
|
vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip;
|
|
}
|
|
/*
|
|
else
|
|
{
|
|
vTable->GetMatches = (Mf_GetMatches_Func)Bt5_MatchFinder_GetMatches;
|
|
vTable->Skip = (Mf_Skip_Func)Bt5_MatchFinder_Skip;
|
|
}
|
|
*/
|
|
}
|