1/* MatchFinder.c */
2/* Please call InitCrcTable before */
3
4#include <string.h>
5
6#include "MatchFinder.h"
7#include "LzHash.h"
8
9#include "../../7zCrc.h"
10
11#define kEmptyHashValue 0
12#define kMaxValForNormalize ((UInt32)0xFFFFFFFF)
13#define kNormalizeStepMin (1 << 10) /* it must be power of 2 */
14#define kNormalizeMask (~(kNormalizeStepMin - 1))
15#define kMaxHistorySize ((UInt32)3 << 30)
16
17#define kStartMaxLen 3
18
19void LzInWindow_Free(CMatchFinder *p, ISzAlloc *alloc)
20{
21  if (!p->directInput)
22  {
23    alloc->Free(p->bufferBase);
24    p->bufferBase = 0;
25  }
26}
27
28/* keepSizeBefore + keepSizeAfter + keepSizeReserv must be < 4G) */
29
30int LzInWindow_Create(CMatchFinder *p, UInt32 keepSizeReserv, ISzAlloc *alloc)
31{
32  UInt32 blockSize = p->keepSizeBefore + p->keepSizeAfter + keepSizeReserv;
33  if (p->directInput)
34  {
35    p->blockSize = blockSize;
36    return 1;
37  }
38  if (p->bufferBase == 0 || p->blockSize != blockSize)
39  {
40    LzInWindow_Free(p, alloc);
41    p->blockSize = blockSize;
42    p->bufferBase = (Byte *)alloc->Alloc(blockSize);
43  }
44  return (p->bufferBase != 0);
45}
46
47Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; }
48Byte MatchFinder_GetIndexByte(CMatchFinder *p, Int32 index) { return p->buffer[index]; }
49
50UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; }
51
52void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue)
53{
54  p->posLimit -= subValue;
55  p->pos -= subValue;
56  p->streamPos -= subValue;
57}
58
59void MatchFinder_ReadBlock(CMatchFinder *p)
60{
61  if (p->streamEndWasReached || p->result != SZ_OK)
62    return;
63  for (;;)
64  {
65    Byte *dest = p->buffer + (p->streamPos - p->pos);
66    UInt32 numReadBytes;
67    UInt32 size = (UInt32)(p->bufferBase + p->blockSize - dest);
68    if (size == 0)
69      return;
70    p->result = p->stream->Read(p->stream, dest, size, &numReadBytes);
71    if (p->result != SZ_OK)
72      return;
73    if (numReadBytes == 0)
74    {
75      p->streamEndWasReached = 1;
76      return;
77    }
78    p->streamPos += numReadBytes;
79    if (p->streamPos - p->pos > p->keepSizeAfter)
80      return;
81  }
82}
83
84void MatchFinder_MoveBlock(CMatchFinder *p)
85{
86  memmove(p->bufferBase,
87    p->buffer - p->keepSizeBefore,
88    p->streamPos - p->pos + p->keepSizeBefore);
89  p->buffer = p->bufferBase + p->keepSizeBefore;
90}
91
92int MatchFinder_NeedMove(CMatchFinder *p)
93{
94  /* if (p->streamEndWasReached) return 0; */
95  return ((size_t)(p->bufferBase + p->blockSize - p->buffer) <= p->keepSizeAfter);
96}
97
98void MatchFinder_ReadIfRequired(CMatchFinder *p)
99{
100  if (p->streamEndWasReached)
101    return;
102  if (p->keepSizeAfter >= p->streamPos - p->pos)
103    MatchFinder_ReadBlock(p);
104}
105
106void MatchFinder_CheckAndMoveAndRead(CMatchFinder *p)
107{
108  if (MatchFinder_NeedMove(p))
109    MatchFinder_MoveBlock(p);
110  MatchFinder_ReadBlock(p);
111}
112
113void MatchFinder_SetDefaultSettings(CMatchFinder *p)
114{
115  p->cutValue = 32;
116  p->btMode = 1;
117  p->numHashBytes = 4;
118  /* p->skipModeBits = 0; */
119  p->directInput = 0;
120  p->bigHash = 0;
121}
122
123void MatchFinder_Construct(CMatchFinder *p)
124{
125  p->bufferBase = 0;
126  p->directInput = 0;
127  p->hash = 0;
128  MatchFinder_SetDefaultSettings(p);
129}
130
131void MatchFinder_FreeThisClassMemory(CMatchFinder *p, ISzAlloc *alloc)
132{
133  alloc->Free(p->hash);
134  p->hash = 0;
135}
136
137void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc)
138{
139  MatchFinder_FreeThisClassMemory(p, alloc);
140  LzInWindow_Free(p, alloc);
141}
142
143CLzRef* AllocRefs(UInt32 num, ISzAlloc *alloc)
144{
145  size_t sizeInBytes = (size_t)num * sizeof(CLzRef);
146  if (sizeInBytes / sizeof(CLzRef) != num)
147    return 0;
148  return (CLzRef *)alloc->Alloc(sizeInBytes);
149}
150
151int MatchFinder_Create(CMatchFinder *p, UInt32 historySize,
152    UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,
153    ISzAlloc *alloc)
154{
155  UInt32 sizeReserv;
156  if (historySize > kMaxHistorySize)
157  {
158    MatchFinder_Free(p, alloc);
159    return 0;
160  }
161  sizeReserv = historySize >> 1;
162  if (historySize > ((UInt32)2 << 30))
163    sizeReserv = historySize >> 2;
164  sizeReserv += (keepAddBufferBefore + matchMaxLen + keepAddBufferAfter) / 2 + (1 << 19);
165
166  p->keepSizeBefore = historySize + keepAddBufferBefore + 1;
167  p->keepSizeAfter = matchMaxLen + keepAddBufferAfter;
168  /* we need one additional byte, since we use MoveBlock after pos++ and before dictionary using */
169  if (LzInWindow_Create(p, sizeReserv, alloc))
170  {
171    UInt32 newCyclicBufferSize = (historySize /* >> p->skipModeBits */) + 1;
172    UInt32 hs;
173    p->matchMaxLen = matchMaxLen;
174    {
175      p->fixedHashSize = 0;
176      if (p->numHashBytes == 2)
177        hs = (1 << 16) - 1;
178      else
179      {
180        hs = historySize - 1;
181        hs |= (hs >> 1);
182        hs |= (hs >> 2);
183        hs |= (hs >> 4);
184        hs |= (hs >> 8);
185        hs >>= 1;
186        /* hs >>= p->skipModeBits; */
187        hs |= 0xFFFF; /* don't change it! It's required for Deflate */
188        if (hs > (1 << 24))
189        {
190          if (p->numHashBytes == 3)
191            hs = (1 << 24) - 1;
192          else
193            hs >>= 1;
194        }
195      }
196      p->hashMask = hs;
197      hs++;
198      if (p->numHashBytes > 2) p->fixedHashSize += kHash2Size;
199      if (p->numHashBytes > 3) p->fixedHashSize += kHash3Size;
200      if (p->numHashBytes > 4) p->fixedHashSize += kHash4Size;
201      hs += p->fixedHashSize;
202    }
203
204    {
205      UInt32 prevSize = p->hashSizeSum + p->numSons;
206      UInt32 newSize;
207      p->historySize = historySize;
208      p->hashSizeSum = hs;
209      p->cyclicBufferSize = newCyclicBufferSize;
210      p->numSons = (p->btMode ? newCyclicBufferSize * 2 : newCyclicBufferSize);
211      newSize = p->hashSizeSum + p->numSons;
212      if (p->hash != 0 && prevSize == newSize)
213        return 1;
214      MatchFinder_FreeThisClassMemory(p, alloc);
215      p->hash = AllocRefs(newSize, alloc);
216      if (p->hash != 0)
217      {
218        p->son = p->hash + p->hashSizeSum;
219        return 1;
220      }
221    }
222  }
223  MatchFinder_Free(p, alloc);
224  return 0;
225}
226
227void MatchFinder_SetLimits(CMatchFinder *p)
228{
229  UInt32 limit = kMaxValForNormalize - p->pos;
230  UInt32 limit2 = p->cyclicBufferSize - p->cyclicBufferPos;
231  if (limit2 < limit)
232    limit = limit2;
233  limit2 = p->streamPos - p->pos;
234  if (limit2 <= p->keepSizeAfter)
235  {
236    if (limit2 > 0)
237      limit2 = 1;
238  }
239  else
240    limit2 -= p->keepSizeAfter;
241  if (limit2 < limit)
242    limit = limit2;
243  {
244    UInt32 lenLimit = p->streamPos - p->pos;
245    if (lenLimit > p->matchMaxLen)
246      lenLimit = p->matchMaxLen;
247    p->lenLimit = lenLimit;
248  }
249  p->posLimit = p->pos + limit;
250}
251
252void MatchFinder_Init(CMatchFinder *p)
253{
254  UInt32 i;
255  for(i = 0; i < p->hashSizeSum; i++)
256    p->hash[i] = kEmptyHashValue;
257  p->cyclicBufferPos = 0;
258  p->buffer = p->bufferBase;
259  p->pos = p->streamPos = p->cyclicBufferSize;
260  p->result = SZ_OK;
261  p->streamEndWasReached = 0;
262  MatchFinder_ReadBlock(p);
263  MatchFinder_SetLimits(p);
264}
265
266UInt32 MatchFinder_GetSubValue(CMatchFinder *p)
267{
268  return (p->pos - p->historySize - 1) & kNormalizeMask;
269}
270
271void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems)
272{
273  UInt32 i;
274  for (i = 0; i < numItems; i++)
275  {
276    UInt32 value = items[i];
277    if (value <= subValue)
278      value = kEmptyHashValue;
279    else
280      value -= subValue;
281    items[i] = value;
282  }
283}
284
285void MatchFinder_Normalize(CMatchFinder *p)
286{
287  UInt32 subValue = MatchFinder_GetSubValue(p);
288  MatchFinder_Normalize3(subValue, p->hash, p->hashSizeSum + p->numSons);
289  MatchFinder_ReduceOffsets(p, subValue);
290}
291
292void MatchFinder_CheckLimits(CMatchFinder *p)
293{
294  if (p->pos == kMaxValForNormalize)
295    MatchFinder_Normalize(p);
296  if (!p->streamEndWasReached && p->keepSizeAfter == p->streamPos - p->pos)
297    MatchFinder_CheckAndMoveAndRead(p);
298  if (p->cyclicBufferPos == p->cyclicBufferSize)
299    p->cyclicBufferPos = 0;
300  MatchFinder_SetLimits(p);
301}
302
303UInt32 * Hc_GetMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
304    UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue,
305    UInt32 *distances, UInt32 maxLen)
306{
307  son[_cyclicBufferPos] = curMatch;
308  for (;;)
309  {
310    UInt32 delta = pos - curMatch;
311    if (cutValue-- == 0 || delta >= _cyclicBufferSize)
312      return distances;
313    {
314      const Byte *pb = cur - delta;
315      curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)];
316      if (pb[maxLen] == cur[maxLen] && *pb == *cur)
317      {
318        UInt32 len = 0;
319        while(++len != lenLimit)
320          if (pb[len] != cur[len])
321            break;
322        if (maxLen < len)
323        {
324          *distances++ = maxLen = len;
325          *distances++ = delta - 1;
326          if (len == lenLimit)
327            return distances;
328        }
329      }
330    }
331  }
332}
333
334UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
335    UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue,
336    UInt32 *distances, UInt32 maxLen)
337{
338  CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1;
339  CLzRef *ptr1 = son + (_cyclicBufferPos << 1);
340  UInt32 len0 = 0, len1 = 0;
341  for (;;)
342  {
343    UInt32 delta = pos - curMatch;
344    if (cutValue-- == 0 || delta >= _cyclicBufferSize)
345    {
346      *ptr0 = *ptr1 = kEmptyHashValue;
347      return distances;
348    }
349    {
350      CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
351      const Byte *pb = cur - delta;
352      UInt32 len = (len0 < len1 ? len0 : len1);
353      if (pb[len] == cur[len])
354      {
355        if (++len != lenLimit && pb[len] == cur[len])
356          while(++len != lenLimit)
357            if (pb[len] != cur[len])
358              break;
359        if (maxLen < len)
360        {
361          *distances++ = maxLen = len;
362          *distances++ = delta - 1;
363          if (len == lenLimit)
364          {
365            *ptr1 = pair[0];
366            *ptr0 = pair[1];
367            return distances;
368          }
369        }
370      }
371      if (pb[len] < cur[len])
372      {
373        *ptr1 = curMatch;
374        ptr1 = pair + 1;
375        curMatch = *ptr1;
376        len1 = len;
377      }
378      else
379      {
380        *ptr0 = curMatch;
381        ptr0 = pair;
382        curMatch = *ptr0;
383        len0 = len;
384      }
385    }
386  }
387}
388
389void SkipMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
390    UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue)
391{
392  CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1;
393  CLzRef *ptr1 = son + (_cyclicBufferPos << 1);
394  UInt32 len0 = 0, len1 = 0;
395  for (;;)
396  {
397    UInt32 delta = pos - curMatch;
398    if (cutValue-- == 0 || delta >= _cyclicBufferSize)
399    {
400      *ptr0 = *ptr1 = kEmptyHashValue;
401      return;
402    }
403    {
404      CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
405      const Byte *pb = cur - delta;
406      UInt32 len = (len0 < len1 ? len0 : len1);
407      if (pb[len] == cur[len])
408      {
409        while(++len != lenLimit)
410          if (pb[len] != cur[len])
411            break;
412        {
413          if (len == lenLimit)
414          {
415            *ptr1 = pair[0];
416            *ptr0 = pair[1];
417            return;
418          }
419        }
420      }
421      if (pb[len] < cur[len])
422      {
423        *ptr1 = curMatch;
424        ptr1 = pair + 1;
425        curMatch = *ptr1;
426        len1 = len;
427      }
428      else
429      {
430        *ptr0 = curMatch;
431        ptr0 = pair;
432        curMatch = *ptr0;
433        len0 = len;
434      }
435    }
436  }
437}
438
439#define MOVE_POS \
440  ++p->cyclicBufferPos; \
441  p->buffer++; \
442  if (++p->pos == p->posLimit) MatchFinder_CheckLimits(p);
443
444#define MOVE_POS_RET MOVE_POS return offset;
445
446void MatchFinder_MovePos(CMatchFinder *p) { MOVE_POS; }
447
448#define GET_MATCHES_HEADER2(minLen, ret_op) \
449  UInt32 lenLimit; UInt32 hashValue; const Byte *cur; UInt32 curMatch; \
450  lenLimit = p->lenLimit; { if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; }} \
451  cur = p->buffer;
452
453#define GET_MATCHES_HEADER(minLen) GET_MATCHES_HEADER2(minLen, return 0)
454#define SKIP_HEADER(minLen)        GET_MATCHES_HEADER2(minLen, continue)
455
456#define MF_PARAMS(p) p->pos, p->buffer, p->son, p->cyclicBufferPos, p->cyclicBufferSize, p->cutValue
457
458#define GET_MATCHES_FOOTER(offset, maxLen) \
459  offset = (UInt32)(GetMatchesSpec1(lenLimit, curMatch, MF_PARAMS(p), \
460  distances + offset, maxLen) - distances); MOVE_POS_RET;
461
462#define SKIP_FOOTER \
463  SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS;
464
465UInt32 Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
466{
467  UInt32 offset;
468  GET_MATCHES_HEADER(2)
469  HASH2_CALC;
470  curMatch = p->hash[hashValue];
471  p->hash[hashValue] = p->pos;
472  offset = 0;
473  GET_MATCHES_FOOTER(offset, 1)
474}
475
476UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
477{
478  UInt32 offset;
479  GET_MATCHES_HEADER(3)
480  HASH_ZIP_CALC;
481  curMatch = p->hash[hashValue];
482  p->hash[hashValue] = p->pos;
483  offset = 0;
484  GET_MATCHES_FOOTER(offset, 2)
485}
486
487UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
488{
489  UInt32 hash2Value, delta2, maxLen, offset;
490  GET_MATCHES_HEADER(3)
491
492  HASH3_CALC;
493
494  delta2 = p->pos - p->hash[hash2Value];
495  curMatch = p->hash[kFix3HashSize + hashValue];
496
497  p->hash[hash2Value] =
498  p->hash[kFix3HashSize + hashValue] = p->pos;
499
500
501  maxLen = 2;
502  offset = 0;
503  if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
504  {
505    for (; maxLen != lenLimit; maxLen++)
506      if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
507        break;
508    distances[0] = maxLen;
509    distances[1] = delta2 - 1;
510    offset = 2;
511    if (maxLen == lenLimit)
512    {
513      SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p));
514      MOVE_POS_RET;
515    }
516  }
517  GET_MATCHES_FOOTER(offset, maxLen)
518}
519
520UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
521{
522  UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset;
523  GET_MATCHES_HEADER(4)
524
525  HASH4_CALC;
526
527  delta2 = p->pos - p->hash[                hash2Value];
528  delta3 = p->pos - p->hash[kFix3HashSize + hash3Value];
529  curMatch = p->hash[kFix4HashSize + hashValue];
530
531  p->hash[                hash2Value] =
532  p->hash[kFix3HashSize + hash3Value] =
533  p->hash[kFix4HashSize + hashValue] = p->pos;
534
535  maxLen = 1;
536  offset = 0;
537  if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
538  {
539    distances[0] = maxLen = 2;
540    distances[1] = delta2 - 1;
541    offset = 2;
542  }
543  if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur)
544  {
545    maxLen = 3;
546    distances[offset + 1] = delta3 - 1;
547    offset += 2;
548    delta2 = delta3;
549  }
550  if (offset != 0)
551  {
552    for (; maxLen != lenLimit; maxLen++)
553      if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
554        break;
555    distances[offset - 2] = maxLen;
556    if (maxLen == lenLimit)
557    {
558      SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p));
559      MOVE_POS_RET;
560    }
561  }
562  if (maxLen < 3)
563    maxLen = 3;
564  GET_MATCHES_FOOTER(offset, maxLen)
565}
566
567UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
568{
569  UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset;
570  GET_MATCHES_HEADER(4)
571
572  HASH4_CALC;
573
574  delta2 = p->pos - p->hash[                hash2Value];
575  delta3 = p->pos - p->hash[kFix3HashSize + hash3Value];
576  curMatch = p->hash[kFix4HashSize + hashValue];
577
578  p->hash[                hash2Value] =
579  p->hash[kFix3HashSize + hash3Value] =
580  p->hash[kFix4HashSize + hashValue] = p->pos;
581
582  maxLen = 1;
583  offset = 0;
584  if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
585  {
586    distances[0] = maxLen = 2;
587    distances[1] = delta2 - 1;
588    offset = 2;
589  }
590  if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur)
591  {
592    maxLen = 3;
593    distances[offset + 1] = delta3 - 1;
594    offset += 2;
595    delta2 = delta3;
596  }
597  if (offset != 0)
598  {
599    for (; maxLen != lenLimit; maxLen++)
600      if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
601        break;
602    distances[offset - 2] = maxLen;
603    if (maxLen == lenLimit)
604    {
605      p->son[p->cyclicBufferPos] = curMatch;
606      MOVE_POS_RET;
607    }
608  }
609  if (maxLen < 3)
610    maxLen = 3;
611  offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
612    distances + offset, maxLen) - (distances));
613  MOVE_POS_RET
614}
615
616UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
617{
618  UInt32 offset;
619  GET_MATCHES_HEADER(3)
620  HASH_ZIP_CALC;
621  curMatch = p->hash[hashValue];
622  p->hash[hashValue] = p->pos;
623  offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
624    distances, 2) - (distances));
625  MOVE_POS_RET
626}
627
628void Bt2_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
629{
630  do
631  {
632    SKIP_HEADER(2)
633    HASH2_CALC;
634    curMatch = p->hash[hashValue];
635    p->hash[hashValue] = p->pos;
636    SKIP_FOOTER
637  }
638  while (--num != 0);
639}
640
641void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
642{
643  do
644  {
645    SKIP_HEADER(3)
646    HASH_ZIP_CALC;
647    curMatch = p->hash[hashValue];
648    p->hash[hashValue] = p->pos;
649    SKIP_FOOTER
650  }
651  while (--num != 0);
652}
653
654void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
655{
656  do
657  {
658    UInt32 hash2Value;
659    SKIP_HEADER(3)
660    HASH3_CALC;
661    curMatch = p->hash[kFix3HashSize + hashValue];
662    p->hash[hash2Value] =
663    p->hash[kFix3HashSize + hashValue] = p->pos;
664    SKIP_FOOTER
665  }
666  while (--num != 0);
667}
668
669void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
670{
671  do
672  {
673    UInt32 hash2Value, hash3Value;
674    SKIP_HEADER(4)
675    HASH4_CALC;
676    curMatch = p->hash[kFix4HashSize + hashValue];
677    p->hash[                hash2Value] =
678    p->hash[kFix3HashSize + hash3Value] = p->pos;
679    p->hash[kFix4HashSize + hashValue] = p->pos;
680    SKIP_FOOTER
681  }
682  while (--num != 0);
683}
684
685void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
686{
687  do
688  {
689    UInt32 hash2Value, hash3Value;
690    SKIP_HEADER(4)
691    HASH4_CALC;
692    curMatch = p->hash[kFix4HashSize + hashValue];
693    p->hash[                hash2Value] =
694    p->hash[kFix3HashSize + hash3Value] =
695    p->hash[kFix4HashSize + hashValue] = p->pos;
696    p->son[p->cyclicBufferPos] = curMatch;
697    MOVE_POS
698  }
699  while (--num != 0);
700}
701
702void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
703{
704  do
705  {
706    SKIP_HEADER(3)
707    HASH_ZIP_CALC;
708    curMatch = p->hash[hashValue];
709    p->hash[hashValue] = p->pos;
710    p->son[p->cyclicBufferPos] = curMatch;
711    MOVE_POS
712  }
713  while (--num != 0);
714}
715
716void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable)
717{
718  vTable->Init = (Mf_Init_Func)MatchFinder_Init;
719  vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinder_GetIndexByte;
720  vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes;
721  vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos;
722  if (!p->btMode)
723  {
724    vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches;
725    vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip;
726  }
727  else if (p->numHashBytes == 2)
728  {
729    vTable->GetMatches = (Mf_GetMatches_Func)Bt2_MatchFinder_GetMatches;
730    vTable->Skip = (Mf_Skip_Func)Bt2_MatchFinder_Skip;
731  }
732  else if (p->numHashBytes == 3)
733  {
734    vTable->GetMatches = (Mf_GetMatches_Func)Bt3_MatchFinder_GetMatches;
735    vTable->Skip = (Mf_Skip_Func)Bt3_MatchFinder_Skip;
736  }
737  else
738  {
739    vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches;
740    vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip;
741  }
742}
743