1 /* LzFind.c -- Match finder for LZ algorithms
2 2017-06-10 : Igor Pavlov : Public domain */
3 
4 #include "Precomp.h"
5 
6 #include <string.h>
7 
8 #include "LzFind.h"
9 #include "LzHash.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 (~(UInt32)(kNormalizeStepMin - 1))
15 #define kMaxHistorySize ((UInt32)7 << 29)
16 
17 #define kStartMaxLen 3
18 
LzInWindow_Free(CMatchFinder * p,ISzAllocPtr alloc)19 static void LzInWindow_Free(CMatchFinder *p, ISzAllocPtr alloc)
20 {
21   if (!p->directInput)
22   {
23     ISzAlloc_Free(alloc, p->bufferBase);
24     p->bufferBase = NULL;
25   }
26 }
27 
28 /* keepSizeBefore + keepSizeAfter + keepSizeReserv must be < 4G) */
29 
LzInWindow_Create(CMatchFinder * p,UInt32 keepSizeReserv,ISzAllocPtr alloc)30 static int LzInWindow_Create(CMatchFinder *p, UInt32 keepSizeReserv, ISzAllocPtr 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 || p->blockSize != blockSize)
39   {
40     LzInWindow_Free(p, alloc);
41     p->blockSize = blockSize;
42     p->bufferBase = (Byte *)ISzAlloc_Alloc(alloc, (size_t)blockSize);
43   }
44   return (p->bufferBase != NULL);
45 }
46 
MatchFinder_GetPointerToCurrentPos(CMatchFinder * p)47 Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; }
48 
MatchFinder_GetNumAvailableBytes(CMatchFinder * p)49 UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; }
50 
MatchFinder_ReduceOffsets(CMatchFinder * p,UInt32 subValue)51 void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue)
52 {
53   p->posLimit -= subValue;
54   p->pos -= subValue;
55   p->streamPos -= subValue;
56 }
57 
MatchFinder_ReadBlock(CMatchFinder * p)58 static void MatchFinder_ReadBlock(CMatchFinder *p)
59 {
60   if (p->streamEndWasReached || p->result != SZ_OK)
61     return;
62 
63   /* We use (p->streamPos - p->pos) value. (p->streamPos < p->pos) is allowed. */
64 
65   if (p->directInput)
66   {
67     UInt32 curSize = 0xFFFFFFFF - (p->streamPos - p->pos);
68     if (curSize > p->directInputRem)
69       curSize = (UInt32)p->directInputRem;
70     p->directInputRem -= curSize;
71     p->streamPos += curSize;
72     if (p->directInputRem == 0)
73       p->streamEndWasReached = 1;
74     return;
75   }
76 
77   for (;;)
78   {
79     Byte *dest = p->buffer + (p->streamPos - p->pos);
80     size_t size = (p->bufferBase + p->blockSize - dest);
81     if (size == 0)
82       return;
83 
84     p->result = ISeqInStream_Read(p->stream, dest, &size);
85     if (p->result != SZ_OK)
86       return;
87     if (size == 0)
88     {
89       p->streamEndWasReached = 1;
90       return;
91     }
92     p->streamPos += (UInt32)size;
93     if (p->streamPos - p->pos > p->keepSizeAfter)
94       return;
95   }
96 }
97 
MatchFinder_MoveBlock(CMatchFinder * p)98 void MatchFinder_MoveBlock(CMatchFinder *p)
99 {
100   memmove(p->bufferBase,
101       p->buffer - p->keepSizeBefore,
102       (size_t)(p->streamPos - p->pos) + p->keepSizeBefore);
103   p->buffer = p->bufferBase + p->keepSizeBefore;
104 }
105 
MatchFinder_NeedMove(CMatchFinder * p)106 int MatchFinder_NeedMove(CMatchFinder *p)
107 {
108   if (p->directInput)
109     return 0;
110   /* if (p->streamEndWasReached) return 0; */
111   return ((size_t)(p->bufferBase + p->blockSize - p->buffer) <= p->keepSizeAfter);
112 }
113 
MatchFinder_ReadIfRequired(CMatchFinder * p)114 void MatchFinder_ReadIfRequired(CMatchFinder *p)
115 {
116   if (p->streamEndWasReached)
117     return;
118   if (p->keepSizeAfter >= p->streamPos - p->pos)
119     MatchFinder_ReadBlock(p);
120 }
121 
MatchFinder_CheckAndMoveAndRead(CMatchFinder * p)122 static void MatchFinder_CheckAndMoveAndRead(CMatchFinder *p)
123 {
124   if (MatchFinder_NeedMove(p))
125     MatchFinder_MoveBlock(p);
126   MatchFinder_ReadBlock(p);
127 }
128 
MatchFinder_SetDefaultSettings(CMatchFinder * p)129 static void MatchFinder_SetDefaultSettings(CMatchFinder *p)
130 {
131   p->cutValue = 32;
132   p->btMode = 1;
133   p->numHashBytes = 4;
134   p->bigHash = 0;
135 }
136 
137 #define kCrcPoly 0xEDB88320
138 
MatchFinder_Construct(CMatchFinder * p)139 void MatchFinder_Construct(CMatchFinder *p)
140 {
141   UInt32 i;
142   p->bufferBase = NULL;
143   p->directInput = 0;
144   p->hash = NULL;
145   p->expectedDataSize = (UInt64)(Int64)-1;
146   MatchFinder_SetDefaultSettings(p);
147 
148   for (i = 0; i < 256; i++)
149   {
150     UInt32 r = i;
151     unsigned j;
152     for (j = 0; j < 8; j++)
153       r = (r >> 1) ^ (kCrcPoly & ((UInt32)0 - (r & 1)));
154     p->crc[i] = r;
155   }
156 }
157 
MatchFinder_FreeThisClassMemory(CMatchFinder * p,ISzAllocPtr alloc)158 static void MatchFinder_FreeThisClassMemory(CMatchFinder *p, ISzAllocPtr alloc)
159 {
160   ISzAlloc_Free(alloc, p->hash);
161   p->hash = NULL;
162 }
163 
MatchFinder_Free(CMatchFinder * p,ISzAllocPtr alloc)164 void MatchFinder_Free(CMatchFinder *p, ISzAllocPtr alloc)
165 {
166   MatchFinder_FreeThisClassMemory(p, alloc);
167   LzInWindow_Free(p, alloc);
168 }
169 
AllocRefs(size_t num,ISzAllocPtr alloc)170 static CLzRef* AllocRefs(size_t num, ISzAllocPtr alloc)
171 {
172   size_t sizeInBytes = (size_t)num * sizeof(CLzRef);
173   if (sizeInBytes / sizeof(CLzRef) != num)
174     return NULL;
175   return (CLzRef *)ISzAlloc_Alloc(alloc, sizeInBytes);
176 }
177 
MatchFinder_Create(CMatchFinder * p,UInt32 historySize,UInt32 keepAddBufferBefore,UInt32 matchMaxLen,UInt32 keepAddBufferAfter,ISzAllocPtr alloc)178 int MatchFinder_Create(CMatchFinder *p, UInt32 historySize,
179     UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,
180     ISzAllocPtr alloc)
181 {
182   UInt32 sizeReserv;
183 
184   if (historySize > kMaxHistorySize)
185   {
186     MatchFinder_Free(p, alloc);
187     return 0;
188   }
189 
190   sizeReserv = historySize >> 1;
191        if (historySize >= ((UInt32)3 << 30)) sizeReserv = historySize >> 3;
192   else if (historySize >= ((UInt32)2 << 30)) sizeReserv = historySize >> 2;
193 
194   sizeReserv += (keepAddBufferBefore + matchMaxLen + keepAddBufferAfter) / 2 + (1 << 19);
195 
196   p->keepSizeBefore = historySize + keepAddBufferBefore + 1;
197   p->keepSizeAfter = matchMaxLen + keepAddBufferAfter;
198 
199   /* we need one additional byte, since we use MoveBlock after pos++ and before dictionary using */
200 
201   if (LzInWindow_Create(p, sizeReserv, alloc))
202   {
203     UInt32 newCyclicBufferSize = historySize + 1;
204     UInt32 hs;
205     p->matchMaxLen = matchMaxLen;
206     {
207       p->fixedHashSize = 0;
208       if (p->numHashBytes == 2)
209         hs = (1 << 16) - 1;
210       else
211       {
212         hs = historySize;
213         if (hs > p->expectedDataSize)
214           hs = (UInt32)p->expectedDataSize;
215         if (hs != 0)
216           hs--;
217         hs |= (hs >> 1);
218         hs |= (hs >> 2);
219         hs |= (hs >> 4);
220         hs |= (hs >> 8);
221         hs >>= 1;
222         hs |= 0xFFFF; /* don't change it! It's required for Deflate */
223         if (hs > (1 << 24))
224         {
225           if (p->numHashBytes == 3)
226             hs = (1 << 24) - 1;
227           else
228             hs >>= 1;
229           /* if (bigHash) mode, GetHeads4b() in LzFindMt.c needs (hs >= ((1 << 24) - 1))) */
230         }
231       }
232       p->hashMask = hs;
233       hs++;
234       if (p->numHashBytes > 2) p->fixedHashSize += kHash2Size;
235       if (p->numHashBytes > 3) p->fixedHashSize += kHash3Size;
236       if (p->numHashBytes > 4) p->fixedHashSize += kHash4Size;
237       hs += p->fixedHashSize;
238     }
239 
240     {
241       size_t newSize;
242       size_t numSons;
243       p->historySize = historySize;
244       p->hashSizeSum = hs;
245       p->cyclicBufferSize = newCyclicBufferSize;
246 
247       numSons = newCyclicBufferSize;
248       if (p->btMode)
249         numSons <<= 1;
250       newSize = hs + numSons;
251 
252       if (p->hash && p->numRefs == newSize)
253         return 1;
254 
255       MatchFinder_FreeThisClassMemory(p, alloc);
256       p->numRefs = newSize;
257       p->hash = AllocRefs(newSize, alloc);
258 
259       if (p->hash)
260       {
261         p->son = p->hash + p->hashSizeSum;
262         return 1;
263       }
264     }
265   }
266 
267   MatchFinder_Free(p, alloc);
268   return 0;
269 }
270 
MatchFinder_SetLimits(CMatchFinder * p)271 static void MatchFinder_SetLimits(CMatchFinder *p)
272 {
273   UInt32 limit = kMaxValForNormalize - p->pos;
274   UInt32 limit2 = p->cyclicBufferSize - p->cyclicBufferPos;
275 
276   if (limit2 < limit)
277     limit = limit2;
278   limit2 = p->streamPos - p->pos;
279 
280   if (limit2 <= p->keepSizeAfter)
281   {
282     if (limit2 > 0)
283       limit2 = 1;
284   }
285   else
286     limit2 -= p->keepSizeAfter;
287 
288   if (limit2 < limit)
289     limit = limit2;
290 
291   {
292     UInt32 lenLimit = p->streamPos - p->pos;
293     if (lenLimit > p->matchMaxLen)
294       lenLimit = p->matchMaxLen;
295     p->lenLimit = lenLimit;
296   }
297   p->posLimit = p->pos + limit;
298 }
299 
300 
MatchFinder_Init_LowHash(CMatchFinder * p)301 void MatchFinder_Init_LowHash(CMatchFinder *p)
302 {
303   size_t i;
304   CLzRef *items = p->hash;
305   size_t numItems = p->fixedHashSize;
306   for (i = 0; i < numItems; i++)
307     items[i] = kEmptyHashValue;
308 }
309 
310 
MatchFinder_Init_HighHash(CMatchFinder * p)311 void MatchFinder_Init_HighHash(CMatchFinder *p)
312 {
313   size_t i;
314   CLzRef *items = p->hash + p->fixedHashSize;
315   size_t numItems = (size_t)p->hashMask + 1;
316   for (i = 0; i < numItems; i++)
317     items[i] = kEmptyHashValue;
318 }
319 
320 
MatchFinder_Init_3(CMatchFinder * p,int readData)321 void MatchFinder_Init_3(CMatchFinder *p, int readData)
322 {
323   p->cyclicBufferPos = 0;
324   p->buffer = p->bufferBase;
325   p->pos =
326   p->streamPos = p->cyclicBufferSize;
327   p->result = SZ_OK;
328   p->streamEndWasReached = 0;
329 
330   if (readData)
331     MatchFinder_ReadBlock(p);
332 
333   MatchFinder_SetLimits(p);
334 }
335 
336 
MatchFinder_Init(CMatchFinder * p)337 void MatchFinder_Init(CMatchFinder *p)
338 {
339   MatchFinder_Init_HighHash(p);
340   MatchFinder_Init_LowHash(p);
341   MatchFinder_Init_3(p, True);
342 }
343 
344 
MatchFinder_GetSubValue(CMatchFinder * p)345 static UInt32 MatchFinder_GetSubValue(CMatchFinder *p)
346 {
347   return (p->pos - p->historySize - 1) & kNormalizeMask;
348 }
349 
MatchFinder_Normalize3(UInt32 subValue,CLzRef * items,size_t numItems)350 void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, size_t numItems)
351 {
352   size_t i;
353   for (i = 0; i < numItems; i++)
354   {
355     UInt32 value = items[i];
356     if (value <= subValue)
357       value = kEmptyHashValue;
358     else
359       value -= subValue;
360     items[i] = value;
361   }
362 }
363 
MatchFinder_Normalize(CMatchFinder * p)364 static void MatchFinder_Normalize(CMatchFinder *p)
365 {
366   UInt32 subValue = MatchFinder_GetSubValue(p);
367   MatchFinder_Normalize3(subValue, p->hash, p->numRefs);
368   MatchFinder_ReduceOffsets(p, subValue);
369 }
370 
MatchFinder_CheckLimits(CMatchFinder * p)371 static void MatchFinder_CheckLimits(CMatchFinder *p)
372 {
373   if (p->pos == kMaxValForNormalize)
374     MatchFinder_Normalize(p);
375   if (!p->streamEndWasReached && p->keepSizeAfter == p->streamPos - p->pos)
376     MatchFinder_CheckAndMoveAndRead(p);
377   if (p->cyclicBufferPos == p->cyclicBufferSize)
378     p->cyclicBufferPos = 0;
379   MatchFinder_SetLimits(p);
380 }
381 
Hc_GetMatchesSpec(UInt32 lenLimit,UInt32 curMatch,UInt32 pos,const Byte * cur,CLzRef * son,UInt32 _cyclicBufferPos,UInt32 _cyclicBufferSize,UInt32 cutValue,UInt32 * distances,UInt32 maxLen)382 static UInt32 * Hc_GetMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
383     UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue,
384     UInt32 *distances, UInt32 maxLen)
385 {
386   son[_cyclicBufferPos] = curMatch;
387   for (;;)
388   {
389     UInt32 delta = pos - curMatch;
390     if (cutValue-- == 0 || delta >= _cyclicBufferSize)
391       return distances;
392     {
393       const Byte *pb = cur - delta;
394       curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)];
395       if (pb[maxLen] == cur[maxLen] && *pb == *cur)
396       {
397         UInt32 len = 0;
398         while (++len != lenLimit)
399           if (pb[len] != cur[len])
400             break;
401         if (maxLen < len)
402         {
403           *distances++ = maxLen = len;
404           *distances++ = delta - 1;
405           if (len == lenLimit)
406             return distances;
407         }
408       }
409     }
410   }
411 }
412 
GetMatchesSpec1(UInt32 lenLimit,UInt32 curMatch,UInt32 pos,const Byte * cur,CLzRef * son,UInt32 _cyclicBufferPos,UInt32 _cyclicBufferSize,UInt32 cutValue,UInt32 * distances,UInt32 maxLen)413 UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
414     UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue,
415     UInt32 *distances, UInt32 maxLen)
416 {
417   CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1;
418   CLzRef *ptr1 = son + (_cyclicBufferPos << 1);
419   UInt32 len0 = 0, len1 = 0;
420   for (;;)
421   {
422     UInt32 delta = pos - curMatch;
423     if (cutValue-- == 0 || delta >= _cyclicBufferSize)
424     {
425       *ptr0 = *ptr1 = kEmptyHashValue;
426       return distances;
427     }
428     {
429       CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
430       const Byte *pb = cur - delta;
431       UInt32 len = (len0 < len1 ? len0 : len1);
432       if (pb[len] == cur[len])
433       {
434         if (++len != lenLimit && pb[len] == cur[len])
435           while (++len != lenLimit)
436             if (pb[len] != cur[len])
437               break;
438         if (maxLen < len)
439         {
440           *distances++ = maxLen = len;
441           *distances++ = delta - 1;
442           if (len == lenLimit)
443           {
444             *ptr1 = pair[0];
445             *ptr0 = pair[1];
446             return distances;
447           }
448         }
449       }
450       if (pb[len] < cur[len])
451       {
452         *ptr1 = curMatch;
453         ptr1 = pair + 1;
454         curMatch = *ptr1;
455         len1 = len;
456       }
457       else
458       {
459         *ptr0 = curMatch;
460         ptr0 = pair;
461         curMatch = *ptr0;
462         len0 = len;
463       }
464     }
465   }
466 }
467 
SkipMatchesSpec(UInt32 lenLimit,UInt32 curMatch,UInt32 pos,const Byte * cur,CLzRef * son,UInt32 _cyclicBufferPos,UInt32 _cyclicBufferSize,UInt32 cutValue)468 static void SkipMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
469     UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue)
470 {
471   CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1;
472   CLzRef *ptr1 = son + (_cyclicBufferPos << 1);
473   UInt32 len0 = 0, len1 = 0;
474   for (;;)
475   {
476     UInt32 delta = pos - curMatch;
477     if (cutValue-- == 0 || delta >= _cyclicBufferSize)
478     {
479       *ptr0 = *ptr1 = kEmptyHashValue;
480       return;
481     }
482     {
483       CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
484       const Byte *pb = cur - delta;
485       UInt32 len = (len0 < len1 ? len0 : len1);
486       if (pb[len] == cur[len])
487       {
488         while (++len != lenLimit)
489           if (pb[len] != cur[len])
490             break;
491         {
492           if (len == lenLimit)
493           {
494             *ptr1 = pair[0];
495             *ptr0 = pair[1];
496             return;
497           }
498         }
499       }
500       if (pb[len] < cur[len])
501       {
502         *ptr1 = curMatch;
503         ptr1 = pair + 1;
504         curMatch = *ptr1;
505         len1 = len;
506       }
507       else
508       {
509         *ptr0 = curMatch;
510         ptr0 = pair;
511         curMatch = *ptr0;
512         len0 = len;
513       }
514     }
515   }
516 }
517 
518 #define MOVE_POS \
519   ++p->cyclicBufferPos; \
520   p->buffer++; \
521   if (++p->pos == p->posLimit) MatchFinder_CheckLimits(p);
522 
523 #define MOVE_POS_RET MOVE_POS return offset;
524 
MatchFinder_MovePos(CMatchFinder * p)525 static void MatchFinder_MovePos(CMatchFinder *p) { MOVE_POS; }
526 
527 #define GET_MATCHES_HEADER2(minLen, ret_op) \
528   UInt32 lenLimit; UInt32 hv; const Byte *cur; UInt32 curMatch; \
529   lenLimit = p->lenLimit; { if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; }} \
530   cur = p->buffer;
531 
532 #define GET_MATCHES_HEADER(minLen) GET_MATCHES_HEADER2(minLen, return 0)
533 #define SKIP_HEADER(minLen)        GET_MATCHES_HEADER2(minLen, continue)
534 
535 #define MF_PARAMS(p) p->pos, p->buffer, p->son, p->cyclicBufferPos, p->cyclicBufferSize, p->cutValue
536 
537 #define GET_MATCHES_FOOTER(offset, maxLen) \
538   offset = (UInt32)(GetMatchesSpec1(lenLimit, curMatch, MF_PARAMS(p), \
539   distances + offset, maxLen) - distances); MOVE_POS_RET;
540 
541 #define SKIP_FOOTER \
542   SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS;
543 
544 #define UPDATE_maxLen { \
545     ptrdiff_t diff = (ptrdiff_t)0 - d2; \
546     const Byte *c = cur + maxLen; \
547     const Byte *lim = cur + lenLimit; \
548     for (; c != lim; c++) if (*(c + diff) != *c) break; \
549     maxLen = (UInt32)(c - cur); }
550 
Bt2_MatchFinder_GetMatches(CMatchFinder * p,UInt32 * distances)551 static UInt32 Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
552 {
553   UInt32 offset;
554   GET_MATCHES_HEADER(2)
555   HASH2_CALC;
556   curMatch = p->hash[hv];
557   p->hash[hv] = p->pos;
558   offset = 0;
559   GET_MATCHES_FOOTER(offset, 1)
560 }
561 
Bt3Zip_MatchFinder_GetMatches(CMatchFinder * p,UInt32 * distances)562 UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
563 {
564   UInt32 offset;
565   GET_MATCHES_HEADER(3)
566   HASH_ZIP_CALC;
567   curMatch = p->hash[hv];
568   p->hash[hv] = p->pos;
569   offset = 0;
570   GET_MATCHES_FOOTER(offset, 2)
571 }
572 
Bt3_MatchFinder_GetMatches(CMatchFinder * p,UInt32 * distances)573 static UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
574 {
575   UInt32 h2, d2, maxLen, offset, pos;
576   UInt32 *hash;
577   GET_MATCHES_HEADER(3)
578 
579   HASH3_CALC;
580 
581   hash = p->hash;
582   pos = p->pos;
583 
584   d2 = pos - hash[h2];
585 
586   curMatch = (hash + kFix3HashSize)[hv];
587 
588   hash[h2] = pos;
589   (hash + kFix3HashSize)[hv] = pos;
590 
591   maxLen = 2;
592   offset = 0;
593 
594   if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur)
595   {
596     UPDATE_maxLen
597     distances[0] = maxLen;
598     distances[1] = d2 - 1;
599     offset = 2;
600     if (maxLen == lenLimit)
601     {
602       SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p));
603       MOVE_POS_RET;
604     }
605   }
606 
607   GET_MATCHES_FOOTER(offset, maxLen)
608 }
609 
Bt4_MatchFinder_GetMatches(CMatchFinder * p,UInt32 * distances)610 static UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
611 {
612   UInt32 h2, h3, d2, d3, maxLen, offset, pos;
613   UInt32 *hash;
614   GET_MATCHES_HEADER(4)
615 
616   HASH4_CALC;
617 
618   hash = p->hash;
619   pos = p->pos;
620 
621   d2 = pos - hash[                h2];
622   d3 = pos - (hash + kFix3HashSize)[h3];
623 
624   curMatch = (hash + kFix4HashSize)[hv];
625 
626   hash[                h2] = pos;
627   (hash + kFix3HashSize)[h3] = pos;
628   (hash + kFix4HashSize)[hv] = pos;
629 
630   maxLen = 0;
631   offset = 0;
632 
633   if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur)
634   {
635     distances[0] = maxLen = 2;
636     distances[1] = d2 - 1;
637     offset = 2;
638   }
639 
640   if (d2 != d3 && d3 < p->cyclicBufferSize && *(cur - d3) == *cur)
641   {
642     maxLen = 3;
643     distances[(size_t)offset + 1] = d3 - 1;
644     offset += 2;
645     d2 = d3;
646   }
647 
648   if (offset != 0)
649   {
650     UPDATE_maxLen
651     distances[(size_t)offset - 2] = maxLen;
652     if (maxLen == lenLimit)
653     {
654       SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p));
655       MOVE_POS_RET;
656     }
657   }
658 
659   if (maxLen < 3)
660     maxLen = 3;
661 
662   GET_MATCHES_FOOTER(offset, maxLen)
663 }
664 
665 /*
666 static UInt32 Bt5_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
667 {
668   UInt32 h2, h3, h4, d2, d3, d4, maxLen, offset, pos;
669   UInt32 *hash;
670   GET_MATCHES_HEADER(5)
671 
672   HASH5_CALC;
673 
674   hash = p->hash;
675   pos = p->pos;
676 
677   d2 = pos - hash[                h2];
678   d3 = pos - (hash + kFix3HashSize)[h3];
679   d4 = pos - (hash + kFix4HashSize)[h4];
680 
681   curMatch = (hash + kFix5HashSize)[hv];
682 
683   hash[                h2] = pos;
684   (hash + kFix3HashSize)[h3] = pos;
685   (hash + kFix4HashSize)[h4] = pos;
686   (hash + kFix5HashSize)[hv] = pos;
687 
688   maxLen = 0;
689   offset = 0;
690 
691   if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur)
692   {
693     distances[0] = maxLen = 2;
694     distances[1] = d2 - 1;
695     offset = 2;
696     if (*(cur - d2 + 2) == cur[2])
697       distances[0] = maxLen = 3;
698     else if (d3 < p->cyclicBufferSize && *(cur - d3) == *cur)
699     {
700       distances[2] = maxLen = 3;
701       distances[3] = d3 - 1;
702       offset = 4;
703       d2 = d3;
704     }
705   }
706   else if (d3 < p->cyclicBufferSize && *(cur - d3) == *cur)
707   {
708     distances[0] = maxLen = 3;
709     distances[1] = d3 - 1;
710     offset = 2;
711     d2 = d3;
712   }
713 
714   if (d2 != d4 && d4 < p->cyclicBufferSize
715       && *(cur - d4) == *cur
716       && *(cur - d4 + 3) == *(cur + 3))
717   {
718     maxLen = 4;
719     distances[(size_t)offset + 1] = d4 - 1;
720     offset += 2;
721     d2 = d4;
722   }
723 
724   if (offset != 0)
725   {
726     UPDATE_maxLen
727     distances[(size_t)offset - 2] = maxLen;
728     if (maxLen == lenLimit)
729     {
730       SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p));
731       MOVE_POS_RET;
732     }
733   }
734 
735   if (maxLen < 4)
736     maxLen = 4;
737 
738   GET_MATCHES_FOOTER(offset, maxLen)
739 }
740 */
741 
Hc4_MatchFinder_GetMatches(CMatchFinder * p,UInt32 * distances)742 static UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
743 {
744   UInt32 h2, h3, d2, d3, maxLen, offset, pos;
745   UInt32 *hash;
746   GET_MATCHES_HEADER(4)
747 
748   HASH4_CALC;
749 
750   hash = p->hash;
751   pos = p->pos;
752 
753   d2 = pos - hash[                h2];
754   d3 = pos - (hash + kFix3HashSize)[h3];
755 
756   curMatch = (hash + kFix4HashSize)[hv];
757 
758   hash[                h2] = pos;
759   (hash + kFix3HashSize)[h3] = pos;
760   (hash + kFix4HashSize)[hv] = pos;
761 
762   maxLen = 0;
763   offset = 0;
764 
765   if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur)
766   {
767     distances[0] = maxLen = 2;
768     distances[1] = d2 - 1;
769     offset = 2;
770   }
771 
772   if (d2 != d3 && d3 < p->cyclicBufferSize && *(cur - d3) == *cur)
773   {
774     maxLen = 3;
775     distances[(size_t)offset + 1] = d3 - 1;
776     offset += 2;
777     d2 = d3;
778   }
779 
780   if (offset != 0)
781   {
782     UPDATE_maxLen
783     distances[(size_t)offset - 2] = maxLen;
784     if (maxLen == lenLimit)
785     {
786       p->son[p->cyclicBufferPos] = curMatch;
787       MOVE_POS_RET;
788     }
789   }
790 
791   if (maxLen < 3)
792     maxLen = 3;
793 
794   offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
795       distances + offset, maxLen) - (distances));
796   MOVE_POS_RET
797 }
798 
799 /*
800 static UInt32 Hc5_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
801 {
802   UInt32 h2, h3, h4, d2, d3, d4, maxLen, offset, pos
803   UInt32 *hash;
804   GET_MATCHES_HEADER(5)
805 
806   HASH5_CALC;
807 
808   hash = p->hash;
809   pos = p->pos;
810 
811   d2 = pos - hash[                h2];
812   d3 = pos - (hash + kFix3HashSize)[h3];
813   d4 = pos - (hash + kFix4HashSize)[h4];
814 
815   curMatch = (hash + kFix5HashSize)[hv];
816 
817   hash[                h2] = pos;
818   (hash + kFix3HashSize)[h3] = pos;
819   (hash + kFix4HashSize)[h4] = pos;
820   (hash + kFix5HashSize)[hv] = pos;
821 
822   maxLen = 0;
823   offset = 0;
824 
825   if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur)
826   {
827     distances[0] = maxLen = 2;
828     distances[1] = d2 - 1;
829     offset = 2;
830     if (*(cur - d2 + 2) == cur[2])
831       distances[0] = maxLen = 3;
832     else if (d3 < p->cyclicBufferSize && *(cur - d3) == *cur)
833     {
834       distances[2] = maxLen = 3;
835       distances[3] = d3 - 1;
836       offset = 4;
837       d2 = d3;
838     }
839   }
840   else if (d3 < p->cyclicBufferSize && *(cur - d3) == *cur)
841   {
842     distances[0] = maxLen = 3;
843     distances[1] = d3 - 1;
844     offset = 2;
845     d2 = d3;
846   }
847 
848   if (d2 != d4 && d4 < p->cyclicBufferSize
849       && *(cur - d4) == *cur
850       && *(cur - d4 + 3) == *(cur + 3))
851   {
852     maxLen = 4;
853     distances[(size_t)offset + 1] = d4 - 1;
854     offset += 2;
855     d2 = d4;
856   }
857 
858   if (offset != 0)
859   {
860     UPDATE_maxLen
861     distances[(size_t)offset - 2] = maxLen;
862     if (maxLen == lenLimit)
863     {
864       p->son[p->cyclicBufferPos] = curMatch;
865       MOVE_POS_RET;
866     }
867   }
868 
869   if (maxLen < 4)
870     maxLen = 4;
871 
872   offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
873       distances + offset, maxLen) - (distances));
874   MOVE_POS_RET
875 }
876 */
877 
Hc3Zip_MatchFinder_GetMatches(CMatchFinder * p,UInt32 * distances)878 UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
879 {
880   UInt32 offset;
881   GET_MATCHES_HEADER(3)
882   HASH_ZIP_CALC;
883   curMatch = p->hash[hv];
884   p->hash[hv] = p->pos;
885   offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
886       distances, 2) - (distances));
887   MOVE_POS_RET
888 }
889 
Bt2_MatchFinder_Skip(CMatchFinder * p,UInt32 num)890 static void Bt2_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
891 {
892   do
893   {
894     SKIP_HEADER(2)
895     HASH2_CALC;
896     curMatch = p->hash[hv];
897     p->hash[hv] = p->pos;
898     SKIP_FOOTER
899   }
900   while (--num != 0);
901 }
902 
Bt3Zip_MatchFinder_Skip(CMatchFinder * p,UInt32 num)903 void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
904 {
905   do
906   {
907     SKIP_HEADER(3)
908     HASH_ZIP_CALC;
909     curMatch = p->hash[hv];
910     p->hash[hv] = p->pos;
911     SKIP_FOOTER
912   }
913   while (--num != 0);
914 }
915 
Bt3_MatchFinder_Skip(CMatchFinder * p,UInt32 num)916 static void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
917 {
918   do
919   {
920     UInt32 h2;
921     UInt32 *hash;
922     SKIP_HEADER(3)
923     HASH3_CALC;
924     hash = p->hash;
925     curMatch = (hash + kFix3HashSize)[hv];
926     hash[h2] =
927     (hash + kFix3HashSize)[hv] = p->pos;
928     SKIP_FOOTER
929   }
930   while (--num != 0);
931 }
932 
Bt4_MatchFinder_Skip(CMatchFinder * p,UInt32 num)933 static void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
934 {
935   do
936   {
937     UInt32 h2, h3;
938     UInt32 *hash;
939     SKIP_HEADER(4)
940     HASH4_CALC;
941     hash = p->hash;
942     curMatch = (hash + kFix4HashSize)[hv];
943     hash[                h2] =
944     (hash + kFix3HashSize)[h3] =
945     (hash + kFix4HashSize)[hv] = p->pos;
946     SKIP_FOOTER
947   }
948   while (--num != 0);
949 }
950 
951 /*
952 static void Bt5_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
953 {
954   do
955   {
956     UInt32 h2, h3, h4;
957     UInt32 *hash;
958     SKIP_HEADER(5)
959     HASH5_CALC;
960     hash = p->hash;
961     curMatch = (hash + kFix5HashSize)[hv];
962     hash[                h2] =
963     (hash + kFix3HashSize)[h3] =
964     (hash + kFix4HashSize)[h4] =
965     (hash + kFix5HashSize)[hv] = p->pos;
966     SKIP_FOOTER
967   }
968   while (--num != 0);
969 }
970 */
971 
Hc4_MatchFinder_Skip(CMatchFinder * p,UInt32 num)972 static void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
973 {
974   do
975   {
976     UInt32 h2, h3;
977     UInt32 *hash;
978     SKIP_HEADER(4)
979     HASH4_CALC;
980     hash = p->hash;
981     curMatch = (hash + kFix4HashSize)[hv];
982     hash[                h2] =
983     (hash + kFix3HashSize)[h3] =
984     (hash + kFix4HashSize)[hv] = p->pos;
985     p->son[p->cyclicBufferPos] = curMatch;
986     MOVE_POS
987   }
988   while (--num != 0);
989 }
990 
991 /*
992 static void Hc5_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
993 {
994   do
995   {
996     UInt32 h2, h3, h4;
997     UInt32 *hash;
998     SKIP_HEADER(5)
999     HASH5_CALC;
1000     hash = p->hash;
1001     curMatch = hash + kFix5HashSize)[hv];
1002     hash[                h2] =
1003     (hash + kFix3HashSize)[h3] =
1004     (hash + kFix4HashSize)[h4] =
1005     (hash + kFix5HashSize)[hv] = p->pos;
1006     p->son[p->cyclicBufferPos] = curMatch;
1007     MOVE_POS
1008   }
1009   while (--num != 0);
1010 }
1011 */
1012 
Hc3Zip_MatchFinder_Skip(CMatchFinder * p,UInt32 num)1013 void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
1014 {
1015   do
1016   {
1017     SKIP_HEADER(3)
1018     HASH_ZIP_CALC;
1019     curMatch = p->hash[hv];
1020     p->hash[hv] = p->pos;
1021     p->son[p->cyclicBufferPos] = curMatch;
1022     MOVE_POS
1023   }
1024   while (--num != 0);
1025 }
1026 
MatchFinder_CreateVTable(CMatchFinder * p,IMatchFinder * vTable)1027 void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable)
1028 {
1029   vTable->Init = (Mf_Init_Func)MatchFinder_Init;
1030   vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes;
1031   vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos;
1032   if (!p->btMode)
1033   {
1034     /* if (p->numHashBytes <= 4) */
1035     {
1036       vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches;
1037       vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip;
1038     }
1039     /*
1040     else
1041     {
1042       vTable->GetMatches = (Mf_GetMatches_Func)Hc5_MatchFinder_GetMatches;
1043       vTable->Skip = (Mf_Skip_Func)Hc5_MatchFinder_Skip;
1044     }
1045     */
1046   }
1047   else if (p->numHashBytes == 2)
1048   {
1049     vTable->GetMatches = (Mf_GetMatches_Func)Bt2_MatchFinder_GetMatches;
1050     vTable->Skip = (Mf_Skip_Func)Bt2_MatchFinder_Skip;
1051   }
1052   else if (p->numHashBytes == 3)
1053   {
1054     vTable->GetMatches = (Mf_GetMatches_Func)Bt3_MatchFinder_GetMatches;
1055     vTable->Skip = (Mf_Skip_Func)Bt3_MatchFinder_Skip;
1056   }
1057   else /* if (p->numHashBytes == 4) */
1058   {
1059     vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches;
1060     vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip;
1061   }
1062   /*
1063   else
1064   {
1065     vTable->GetMatches = (Mf_GetMatches_Func)Bt5_MatchFinder_GetMatches;
1066     vTable->Skip = (Mf_Skip_Func)Bt5_MatchFinder_Skip;
1067   }
1068   */
1069 }
1070