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