1 /**************************************************************************
3 * Copyright 2013-2014 RAD Game Tools and Valve Software
4 * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 **************************************************************************/
27 /* LzFind.c -- Match finder for LZ algorithms
28 2008-10-04 : Igor Pavlov : Public domain */
29 #include "vogl_core.h"
32 #include "lzma_LzFind.h"
33 #include "lzma_LzHash.h"
38 #define kEmptyHashValue 0
39 #define kMaxValForNormalize ((UInt32)0xFFFFFFFF)
40 #define kNormalizeStepMin (1 << 10) /* it must be power of 2 */
41 #define kNormalizeMask (~(kNormalizeStepMin - 1))
42 #define kMaxHistorySize ((UInt32)3 << 30)
44 #define kStartMaxLen 3
46 static void LzInWindow_Free(CMatchFinder *p, ISzAlloc *alloc)
50 alloc->Free(alloc, p->bufferBase);
55 /* keepSizeBefore + keepSizeAfter + keepSizeReserv must be < 4G) */
57 static int LzInWindow_Create(CMatchFinder *p, UInt32 keepSizeReserv, ISzAlloc *alloc)
59 UInt32 blockSize = p->keepSizeBefore + p->keepSizeAfter + keepSizeReserv;
62 p->blockSize = blockSize;
65 if (p->bufferBase == 0 || p->blockSize != blockSize)
67 LzInWindow_Free(p, alloc);
68 p->blockSize = blockSize;
69 p->bufferBase = (Byte *)alloc->Alloc(alloc, (size_t)blockSize);
71 return (p->bufferBase != 0);
74 Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p)
78 Byte MatchFinder_GetIndexByte(CMatchFinder *p, Int32 index)
80 return p->buffer[index];
83 UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p)
85 return p->streamPos - p->pos;
88 void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue)
90 p->posLimit -= subValue;
92 p->streamPos -= subValue;
95 static void MatchFinder_ReadBlock(CMatchFinder *p)
97 if (p->streamEndWasReached || p->result != SZ_OK)
101 Byte *dest = p->buffer + (p->streamPos - p->pos);
102 size_t size = (p->bufferBase + p->blockSize - dest);
105 p->result = p->stream->Read(p->stream, dest, &size);
106 if (p->result != SZ_OK)
110 p->streamEndWasReached = 1;
113 p->streamPos += (UInt32)size;
114 if (p->streamPos - p->pos > p->keepSizeAfter)
119 void MatchFinder_MoveBlock(CMatchFinder *p)
121 memmove(p->bufferBase,
122 p->buffer - p->keepSizeBefore,
123 (size_t)(p->streamPos - p->pos + p->keepSizeBefore));
124 p->buffer = p->bufferBase + p->keepSizeBefore;
127 int MatchFinder_NeedMove(CMatchFinder *p)
129 /* if (p->streamEndWasReached) return 0; */
130 return ((size_t)(p->bufferBase + p->blockSize - p->buffer) <= p->keepSizeAfter);
133 void MatchFinder_ReadIfRequired(CMatchFinder *p)
135 if (p->streamEndWasReached)
137 if (p->keepSizeAfter >= p->streamPos - p->pos)
138 MatchFinder_ReadBlock(p);
141 static void MatchFinder_CheckAndMoveAndRead(CMatchFinder *p)
143 if (MatchFinder_NeedMove(p))
144 MatchFinder_MoveBlock(p);
145 MatchFinder_ReadBlock(p);
148 static void MatchFinder_SetDefaultSettings(CMatchFinder *p)
153 /* p->skipModeBits = 0; */
158 #define kCrcPoly 0xEDB88320
160 void MatchFinder_Construct(CMatchFinder *p)
166 MatchFinder_SetDefaultSettings(p);
168 for (i = 0; i < 256; i++)
172 for (j = 0; j < 8; j++)
173 r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1));
178 static void MatchFinder_FreeThisClassMemory(CMatchFinder *p, ISzAlloc *alloc)
180 alloc->Free(alloc, p->hash);
184 void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc)
186 MatchFinder_FreeThisClassMemory(p, alloc);
187 LzInWindow_Free(p, alloc);
190 static CLzRef *AllocRefs(UInt32 num, ISzAlloc *alloc)
192 size_t sizeInBytes = (size_t)num * sizeof(CLzRef);
193 if (sizeInBytes / sizeof(CLzRef) != num)
195 return (CLzRef *)alloc->Alloc(alloc, sizeInBytes);
198 int MatchFinder_Create(CMatchFinder *p, UInt32 historySize,
199 UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,
203 if (historySize > kMaxHistorySize)
205 MatchFinder_Free(p, alloc);
208 sizeReserv = historySize >> 1;
209 if (historySize > ((UInt32)2 << 30))
210 sizeReserv = historySize >> 2;
211 sizeReserv += (keepAddBufferBefore + matchMaxLen + keepAddBufferAfter) / 2 + (1 << 19);
213 p->keepSizeBefore = historySize + keepAddBufferBefore + 1;
214 p->keepSizeAfter = matchMaxLen + keepAddBufferAfter;
215 /* we need one additional byte, since we use MoveBlock after pos++ and before dictionary using */
216 if (LzInWindow_Create(p, sizeReserv, alloc))
218 UInt32 newCyclicBufferSize = (historySize /* >> p->skipModeBits */) + 1;
220 p->matchMaxLen = matchMaxLen;
222 p->fixedHashSize = 0;
223 if (p->numHashBytes == 2)
227 hs = historySize - 1;
233 /* hs >>= p->skipModeBits; */
234 hs |= 0xFFFF; /* don't change it! It's required for Deflate */
237 if (p->numHashBytes == 3)
245 if (p->numHashBytes > 2)
246 p->fixedHashSize += kHash2Size;
247 if (p->numHashBytes > 3)
248 p->fixedHashSize += kHash3Size;
249 if (p->numHashBytes > 4)
250 p->fixedHashSize += kHash4Size;
251 hs += p->fixedHashSize;
255 UInt32 prevSize = p->hashSizeSum + p->numSons;
257 p->historySize = historySize;
259 p->cyclicBufferSize = newCyclicBufferSize;
260 p->numSons = (p->btMode ? newCyclicBufferSize * 2 : newCyclicBufferSize);
261 newSize = p->hashSizeSum + p->numSons;
262 if (p->hash != 0 && prevSize == newSize)
264 MatchFinder_FreeThisClassMemory(p, alloc);
265 p->hash = AllocRefs(newSize, alloc);
268 p->son = p->hash + p->hashSizeSum;
273 MatchFinder_Free(p, alloc);
277 static void MatchFinder_SetLimits(CMatchFinder *p)
279 UInt32 limit = kMaxValForNormalize - p->pos;
280 UInt32 limit2 = p->cyclicBufferSize - p->cyclicBufferPos;
283 limit2 = p->streamPos - p->pos;
284 if (limit2 <= p->keepSizeAfter)
290 limit2 -= p->keepSizeAfter;
294 UInt32 lenLimit = p->streamPos - p->pos;
295 if (lenLimit > p->matchMaxLen)
296 lenLimit = p->matchMaxLen;
297 p->lenLimit = lenLimit;
299 p->posLimit = p->pos + limit;
302 void MatchFinder_Init(CMatchFinder *p)
305 for (i = 0; i < p->hashSizeSum; i++)
306 p->hash[i] = kEmptyHashValue;
307 p->cyclicBufferPos = 0;
308 p->buffer = p->bufferBase;
309 p->pos = p->streamPos = p->cyclicBufferSize;
311 p->streamEndWasReached = 0;
312 MatchFinder_ReadBlock(p);
313 MatchFinder_SetLimits(p);
316 static UInt32 MatchFinder_GetSubValue(CMatchFinder *p)
318 return (p->pos - p->historySize - 1) & kNormalizeMask;
321 void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems)
324 for (i = 0; i < numItems; i++)
326 UInt32 value = items[i];
327 if (value <= subValue)
328 value = kEmptyHashValue;
335 static void MatchFinder_Normalize(CMatchFinder *p)
337 UInt32 subValue = MatchFinder_GetSubValue(p);
338 MatchFinder_Normalize3(subValue, p->hash, p->hashSizeSum + p->numSons);
339 MatchFinder_ReduceOffsets(p, subValue);
342 static void MatchFinder_CheckLimits(CMatchFinder *p)
344 if (p->pos == kMaxValForNormalize)
345 MatchFinder_Normalize(p);
346 if (!p->streamEndWasReached && p->keepSizeAfter == p->streamPos - p->pos)
347 MatchFinder_CheckAndMoveAndRead(p);
348 if (p->cyclicBufferPos == p->cyclicBufferSize)
349 p->cyclicBufferPos = 0;
350 MatchFinder_SetLimits(p);
353 static UInt32 *Hc_GetMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
354 UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue,
355 UInt32 *distances, UInt32 maxLen)
357 son[_cyclicBufferPos] = curMatch;
360 UInt32 delta = pos - curMatch;
361 if (cutValue-- == 0 || delta >= _cyclicBufferSize)
364 const Byte *pb = cur - delta;
365 curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)];
366 if (pb[maxLen] == cur[maxLen] && *pb == *cur)
369 while (++len != lenLimit)
370 if (pb[len] != cur[len])
374 *distances++ = maxLen = len;
375 *distances++ = delta - 1;
384 UInt32 *GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
385 UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue,
386 UInt32 *distances, UInt32 maxLen)
388 CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1;
389 CLzRef *ptr1 = son + (_cyclicBufferPos << 1);
390 UInt32 len0 = 0, len1 = 0;
393 UInt32 delta = pos - curMatch;
394 if (cutValue-- == 0 || delta >= _cyclicBufferSize)
396 *ptr0 = *ptr1 = kEmptyHashValue;
400 CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
401 const Byte *pb = cur - delta;
402 UInt32 len = (len0 < len1 ? len0 : len1);
403 if (pb[len] == cur[len])
405 if (++len != lenLimit && pb[len] == cur[len])
406 while (++len != lenLimit)
407 if (pb[len] != cur[len])
411 *distances++ = maxLen = len;
412 *distances++ = delta - 1;
421 if (pb[len] < cur[len])
439 static void SkipMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
440 UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue)
442 CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1;
443 CLzRef *ptr1 = son + (_cyclicBufferPos << 1);
444 UInt32 len0 = 0, len1 = 0;
447 UInt32 delta = pos - curMatch;
448 if (cutValue-- == 0 || delta >= _cyclicBufferSize)
450 *ptr0 = *ptr1 = kEmptyHashValue;
454 CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
455 const Byte *pb = cur - delta;
456 UInt32 len = (len0 < len1 ? len0 : len1);
457 if (pb[len] == cur[len])
459 while (++len != lenLimit)
460 if (pb[len] != cur[len])
471 if (pb[len] < cur[len])
490 ++p->cyclicBufferPos; \
492 if (++p->pos == p->posLimit) \
493 MatchFinder_CheckLimits(p);
495 #define MOVE_POS_RET MOVE_POS return offset;
497 static void MatchFinder_MovePos(CMatchFinder *p)
502 #define GET_MATCHES_HEADER2(minLen, ret_op) \
507 lenLimit = p->lenLimit; \
509 if (lenLimit < minLen) \
511 MatchFinder_MovePos(p); \
517 #define GET_MATCHES_HEADER(minLen) GET_MATCHES_HEADER2(minLen, return 0)
518 #define SKIP_HEADER(minLen) GET_MATCHES_HEADER2(minLen, continue)
520 #define MF_PARAMS(p) p->pos, p->buffer, p->son, p->cyclicBufferPos, p->cyclicBufferSize, p->cutValue
522 #define GET_MATCHES_FOOTER(offset, maxLen) \
523 offset = (UInt32)(GetMatchesSpec1(lenLimit, curMatch, MF_PARAMS(p), distances + offset, maxLen) - distances); \
526 #define SKIP_FOOTER \
527 SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); \
530 static UInt32 Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
533 GET_MATCHES_HEADER(2)
535 curMatch = p->hash[hashValue];
536 p->hash[hashValue] = p->pos;
538 GET_MATCHES_FOOTER(offset, 1)
541 UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
544 GET_MATCHES_HEADER(3)
546 curMatch = p->hash[hashValue];
547 p->hash[hashValue] = p->pos;
549 GET_MATCHES_FOOTER(offset, 2)
552 static UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
554 UInt32 hash2Value, delta2, maxLen, offset;
555 GET_MATCHES_HEADER(3)
559 delta2 = p->pos - p->hash[hash2Value];
560 curMatch = p->hash[kFix3HashSize + hashValue];
562 p->hash[hash2Value] =
563 p->hash[kFix3HashSize + hashValue] = p->pos;
567 if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
569 for (; maxLen != lenLimit; maxLen++)
570 if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
572 distances[0] = maxLen;
573 distances[1] = delta2 - 1;
575 if (maxLen == lenLimit)
577 SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p));
581 GET_MATCHES_FOOTER(offset, maxLen)
584 static UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
586 UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset;
587 GET_MATCHES_HEADER(4)
591 delta2 = p->pos - p->hash[hash2Value];
592 delta3 = p->pos - p->hash[kFix3HashSize + hash3Value];
593 curMatch = p->hash[kFix4HashSize + hashValue];
595 p->hash[hash2Value] =
596 p->hash[kFix3HashSize + hash3Value] =
597 p->hash[kFix4HashSize + hashValue] = p->pos;
601 if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
603 distances[0] = maxLen = 2;
604 distances[1] = delta2 - 1;
607 if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur)
610 distances[offset + 1] = delta3 - 1;
616 for (; maxLen != lenLimit; maxLen++)
617 if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
619 distances[offset - 2] = maxLen;
620 if (maxLen == lenLimit)
622 SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p));
628 GET_MATCHES_FOOTER(offset, maxLen)
631 static UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
633 UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset;
634 GET_MATCHES_HEADER(4)
638 delta2 = p->pos - p->hash[hash2Value];
639 delta3 = p->pos - p->hash[kFix3HashSize + hash3Value];
640 curMatch = p->hash[kFix4HashSize + hashValue];
642 p->hash[hash2Value] =
643 p->hash[kFix3HashSize + hash3Value] =
644 p->hash[kFix4HashSize + hashValue] = p->pos;
648 if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
650 distances[0] = maxLen = 2;
651 distances[1] = delta2 - 1;
654 if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur)
657 distances[offset + 1] = delta3 - 1;
663 for (; maxLen != lenLimit; maxLen++)
664 if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
666 distances[offset - 2] = maxLen;
667 if (maxLen == lenLimit)
669 p->son[p->cyclicBufferPos] = curMatch;
675 offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
676 distances + offset, maxLen) -
681 UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
684 GET_MATCHES_HEADER(3)
686 curMatch = p->hash[hashValue];
687 p->hash[hashValue] = p->pos;
688 offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
694 static void Bt2_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
700 curMatch = p->hash[hashValue];
701 p->hash[hashValue] = p->pos;
703 } while (--num != 0);
706 void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
712 curMatch = p->hash[hashValue];
713 p->hash[hashValue] = p->pos;
715 } while (--num != 0);
718 static void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
725 curMatch = p->hash[kFix3HashSize + hashValue];
726 p->hash[hash2Value] =
727 p->hash[kFix3HashSize + hashValue] = p->pos;
729 } while (--num != 0);
732 static void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
736 UInt32 hash2Value, hash3Value;
739 curMatch = p->hash[kFix4HashSize + hashValue];
740 p->hash[hash2Value] =
741 p->hash[kFix3HashSize + hash3Value] = p->pos;
742 p->hash[kFix4HashSize + hashValue] = p->pos;
744 } while (--num != 0);
747 static void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
751 UInt32 hash2Value, hash3Value;
754 curMatch = p->hash[kFix4HashSize + hashValue];
755 p->hash[hash2Value] =
756 p->hash[kFix3HashSize + hash3Value] =
757 p->hash[kFix4HashSize + hashValue] = p->pos;
758 p->son[p->cyclicBufferPos] = curMatch;
760 } while (--num != 0);
763 void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
769 curMatch = p->hash[hashValue];
770 p->hash[hashValue] = p->pos;
771 p->son[p->cyclicBufferPos] = curMatch;
773 } while (--num != 0);
776 void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable)
778 vTable->Init = (Mf_Init_Func)MatchFinder_Init;
779 vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinder_GetIndexByte;
780 vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes;
781 vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos;
784 vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches;
785 vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip;
787 else if (p->numHashBytes == 2)
789 vTable->GetMatches = (Mf_GetMatches_Func)Bt2_MatchFinder_GetMatches;
790 vTable->Skip = (Mf_Skip_Func)Bt2_MatchFinder_Skip;
792 else if (p->numHashBytes == 3)
794 vTable->GetMatches = (Mf_GetMatches_Func)Bt3_MatchFinder_GetMatches;
795 vTable->Skip = (Mf_Skip_Func)Bt3_MatchFinder_Skip;
799 vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches;
800 vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip;