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 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 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 47 Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; } 48 49 UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; } 50 51 void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue) 52 { 53 p->posLimit -= subValue; 54 p->pos -= subValue; 55 p->streamPos -= subValue; 56 } 57 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 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 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 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 122 static void MatchFinder_CheckAndMoveAndRead(CMatchFinder *p) 123 { 124 if (MatchFinder_NeedMove(p)) 125 MatchFinder_MoveBlock(p); 126 MatchFinder_ReadBlock(p); 127 } 128 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 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 157 static void MatchFinder_FreeThisClassMemory(CMatchFinder *p, ISzAlloc *alloc) 158 { 159 alloc->Free(alloc, p->hash); 160 p->hash = NULL; 161 } 162 163 void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc) 164 { 165 MatchFinder_FreeThisClassMemory(p, alloc); 166 LzInWindow_Free(p, alloc); 167 } 168 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 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 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 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 315 void MatchFinder_Init(CMatchFinder *p) 316 { 317 MatchFinder_Init_2(p, True); 318 } 319 320 static UInt32 MatchFinder_GetSubValue(CMatchFinder *p) 321 { 322 return (p->pos - p->historySize - 1) & kNormalizeMask; 323 } 324 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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