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