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