strex: added `detectUrl()`
[iv.d.git] / dlzma / enc.d
blob5788751962381d5ae32f413451c2e71082ac4ca7
1 /* converted by Ketmar // Invisible Vector <ketmar@ketmar.no-ip.org>
2 * Understanding is not required. Only obedience.
4 * This program is free software. It comes without any warranty, to
5 * the extent permitted by applicable law. You can redistribute it
6 * and/or modify it under the terms of the Do What The Fuck You Want
7 * To Public License, Version 2, as published by Sam Hocevar. See
8 * http://www.wtfpl.net/txt/copying/ for more details.
9 */
10 module iv.dlzma.enc;
11 nothrow:
13 /* use slightly smaller (around 300 bytes) code with branching in compressor? */
14 //version = LZMA_ENC_USE_BRANCH;
16 //version = LZMA_SANITY_MAGIC;
18 private import iv.dlzma;
21 // ////////////////////////////////////////////////////////////////////////// //
22 // ////////////////////////////////////////////////////////////////////////// //
23 // ////////////////////////////////////////////////////////////////////////// //
24 // ////////////////////////////////////////////////////////////////////////// //
25 private:
27 private void SetUi32 (const(void)* p, in uint v) nothrow @trusted @nogc { pragma(inline, true); *(cast(uint*)p) = v; }
28 private ushort GetUi16 (const(void)* v) nothrow @trusted @nogc { pragma(inline, true); return *(cast(const(ushort)*)v); }
30 alias CLzRef = uint;
32 struct CMatchFinder {
33 ubyte *buffer;
34 uint pos;
35 uint posLimit;
36 uint streamPos; /* wrap over Zero is allowed (streamPos < pos). Use (uint32_t)(streamPos - pos) */
37 uint lenLimit;
39 uint cyclicBufferPos;
40 uint cyclicBufferSize; /* it must be = (historySize + 1) */
42 ubyte streamEndWasReached;
43 ubyte btMode;
44 ubyte bigHash;
45 ubyte directInput;
47 uint matchMaxLen;
48 CLzRef *hash;
49 CLzRef *son;
50 uint hashMask;
51 uint cutValue;
53 ubyte *bufferBase;
54 ISeqInStream *stream;
56 uint blockSize;
57 uint keepSizeBefore;
58 uint keepSizeAfter;
60 uint numHashBytes;
61 usize directInputRem;
62 uint historySize;
63 uint fixedHashSize;
64 uint hashSizeSum;
65 SRes result;
66 uint[256] crc;
67 usize numRefs;
69 ulong expectedDataSize;
72 //#define Inline_MatchFinder_GetPointerToCurrentPos(p) ((const ubyte *)(p)->buffer)
74 //#define Inline_MatchFinder_GetNumAvailableBytes(p) ((uint)((p)->streamPos - (p)->pos))
75 enum Inline_MatchFinder_GetNumAvailableBytes(string p) = `(cast(uint)((`~p~`).streamPos - (`~p~`).pos))`;
78 #define Inline_MatchFinder_IsFinishedOK(p) \
79 ((p)->streamEndWasReached \
80 && (p)->streamPos == (p)->pos \
81 && (!(p)->directInput || (p)->directInputRem == 0))
85 int MatchFinder_NeedMove(CMatchFinder *p);
86 /* uint8_t *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p); */
87 void MatchFinder_MoveBlock(CMatchFinder *p);
88 void MatchFinder_ReadIfRequired(CMatchFinder *p);
90 void MatchFinder_Construct(CMatchFinder *p);
92 /* Conditions:
93 historySize <= 3 GB
94 keepAddBufferBefore + matchMaxLen + keepAddBufferAfter < 511MB
96 int MatchFinder_Create(CMatchFinder *p, uint historySize,
97 uint keepAddBufferBefore, uint matchMaxLen, uint keepAddBufferAfter,
98 ISzAllocPtr alloc);
99 void MatchFinder_Free(CMatchFinder *p, ISzAllocPtr alloc);
100 void MatchFinder_Normalize3(uint subValue, CLzRef *items, usize numItems);
101 // void MatchFinder_ReduceOffsets(CMatchFinder *p, uint32_t subValue);
105 #define Inline_MatchFinder_InitPos(p, val) \
106 (p)->pos = (val); \
107 (p)->streamPos = (val);
111 #define Inline_MatchFinder_ReduceOffsets(p, subValue) \
112 (p)->pos -= (subValue); \
113 (p)->streamPos -= (subValue);
117 uint* GetMatchesSpec1(uint lenLimit, uint curMatch, uint pos, const ubyte *buffer, CLzRef *son,
118 usize _cyclicBufferPos, uint _cyclicBufferSize, uint _cutValue,
119 uint *distances, uint maxLen);
123 Conditions:
124 Mf_GetNumAvailableBytes_Func must be called before each Mf_GetMatchLen_Func.
125 Mf_GetPointerToCurrentPos_Func's result must be used only before any other function
128 alias Mf_Init_Func = void function (void *object);
129 alias Mf_GetNumAvailableBytes_Func = uint function (void *object);
130 alias Mf_GetPointerToCurrentPos_Func = const(ubyte)* function (void *object);
131 alias Mf_GetMatches_Func = uint* function (void *object, uint *distances);
132 alias Mf_Skip_Func = void function (void *object, uint);
134 struct /*_IMatchFinder*/ IMatchFinder2 {
135 Mf_Init_Func Init;
136 Mf_GetNumAvailableBytes_Func GetNumAvailableBytes;
137 Mf_GetPointerToCurrentPos_Func GetPointerToCurrentPos;
138 Mf_GetMatches_Func GetMatches;
139 Mf_Skip_Func Skip;
143 void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder2 *vTable);
145 void MatchFinder_Init_LowHash(CMatchFinder *p);
146 void MatchFinder_Init_HighHash(CMatchFinder *p);
147 void MatchFinder_Init_4(CMatchFinder *p);
148 void MatchFinder_Init(CMatchFinder *p);
150 uint* Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, uint *distances);
151 uint* Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, uint *distances);
153 void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, uint num);
154 void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, uint num);
156 void LzFindPrepare(void);
160 /* LzHash.h -- HASH functions for LZ algorithms
161 2019-10-30 : Igor Pavlov : Public domain */
164 (kHash2Size >= (1 << 8)) : Required
165 (kHash3Size >= (1 << 16)) : Required
168 enum kHash2Size = (1 << 10);
169 enum kHash3Size = (1 << 16);
170 // #define kHash4Size (1 << 20)
172 enum kFix3HashSize = (kHash2Size);
173 enum kFix4HashSize = (kHash2Size + kHash3Size);
174 // #define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size)
177 We use up to 3 crc values for hash:
178 crc0
179 crc1 << Shift_1
180 crc2 << Shift_2
181 (Shift_1 = 5) and (Shift_2 = 10) is good tradeoff.
182 Small values for Shift are not good for collision rate.
183 Big value for Shift_2 increases the minimum size
184 of hash table, that will be slow for small files.
187 enum kLzHash_CrcShift_1 = 5;
188 enum kLzHash_CrcShift_2 = 10;
192 enum kBlockMoveAlign = (1 << 7); // alignment for memmove()
193 enum kBlockSizeAlign = (1 << 16); // alignment for block allocation
194 enum kBlockSizeReserveMin = (1 << 24); // it's 1/256 from 4 GB dictinary
196 enum kEmptyHashValue = 0;
198 enum kMaxValForNormalize = cast(uint)0;
199 // #define kMaxValForNormalize ((uint)(1 << 20) + 0xFFF) // for debug
201 // #define kNormalizeAlign (1 << 7) // alignment for speculated accesses
204 // #define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size)
205 enum kFix5HashSize = kFix4HashSize;
207 // (crc[0 ... 255] & 0xFF) provides one-to-one correspondence to [0 ... 255]
210 HASH3_CALC:
211 if (cur[0]) and (h2) match, then cur[1] also match
212 if (cur[0]) and (hv) match, then cur[1] and cur[2] also match
214 enum HASH3_CALC = q{
215 uint temp = p.crc[cur[0]] ^ cur[1];
216 h2 = temp & (kHash2Size - 1);
217 hv = (temp ^ (cast(uint)cur[2] << 8)) & p.hashMask;
220 enum HASH4_CALC = q{
221 uint temp = p.crc[cur[0]] ^ cur[1];
222 h2 = temp & (kHash2Size - 1);
223 temp ^= (cast(uint)cur[2] << 8);
224 h3 = temp & (kHash3Size - 1);
225 hv = (temp ^ (p.crc[cur[3]] << kLzHash_CrcShift_1)) & p.hashMask;
228 enum HASH5_CALC = q{
229 uint temp = p.crc[cur[0]] ^ cur[1];
230 h2 = temp & (kHash2Size - 1);
231 temp ^= (cast(uint)cur[2] << 8);
232 h3 = temp & (kHash3Size - 1);
233 temp ^= (p.crc[cur[3]] << kLzHash_CrcShift_1);
234 /* h4 = temp & p->hash4Mask; */ /* (kHash4Size - 1); */
235 hv = (temp ^ (p.crc[cur[4]] << kLzHash_CrcShift_2)) & p.hashMask;
238 enum HASH_ZIP_CALC = `hv = ((cur[2] | (cast(uint)cur[0] << 8)) ^ p.crc[cur[1]]) & 0xFFFF;`;
241 private void LzInWindow_Free(CMatchFinder *p, ISzAllocPtr alloc)
243 if (!p.directInput)
245 ISzAlloc_Free(alloc, p.bufferBase);
246 p.bufferBase = null;
251 private int LzInWindow_Create2(CMatchFinder *p, uint blockSize, ISzAllocPtr alloc)
253 if (blockSize == 0)
254 return 0;
255 if (!p.bufferBase || p.blockSize != blockSize)
257 // usize blockSizeT;
258 LzInWindow_Free(p, alloc);
259 p.blockSize = blockSize;
260 // blockSizeT = blockSize;
262 // printf("\nblockSize = 0x%x\n", blockSize);
264 #if defined _WIN64
265 // we can allocate 4GiB, but still use uint for (p->blockSize)
266 // we use uint type for (p->blockSize), because
267 // we don't want to wrap over 4 GiB,
268 // when we use (p->streamPos - p->pos) that is uint.
269 if (blockSize >= (uint)0 - (uint)kBlockSizeAlign)
271 blockSizeT = ((usize)1 << 32);
272 printf("\nchanged to blockSizeT = 4GiB\n");
274 #endif
277 p.bufferBase = cast(ubyte *)ISzAlloc_Alloc(alloc, blockSize);
278 // printf("\nbufferBase = %p\n", p->bufferBase);
279 // return 0; // for debug
281 return (p.bufferBase != null);
284 private const(ubyte)* MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { pragma(inline, true); return p.buffer; }
286 private uint MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { pragma(inline, true); return mixin(Inline_MatchFinder_GetNumAvailableBytes!"p"); }
289 //MY_NO_INLINE
290 private void MatchFinder_ReadBlock(CMatchFinder *p)
292 if (p.streamEndWasReached || p.result != SZ_OK)
293 return;
295 /* We use (p->streamPos - p->pos) value.
296 (p->streamPos < p->pos) is allowed. */
298 if (p.directInput)
300 uint curSize = 0xFFFFFFFF - mixin(Inline_MatchFinder_GetNumAvailableBytes!"p");
301 if (curSize > p.directInputRem)
302 curSize = cast(uint)p.directInputRem;
303 p.directInputRem -= curSize;
304 p.streamPos += curSize;
305 if (p.directInputRem == 0)
306 p.streamEndWasReached = 1;
307 return;
310 for (;;)
312 ubyte *dest = p.buffer + mixin(Inline_MatchFinder_GetNumAvailableBytes!"p");
313 usize size = cast(usize)(p.bufferBase + p.blockSize - dest);
314 if (size == 0)
316 /* we call ReadBlock() after NeedMove() and MoveBlock().
317 NeedMove() and MoveBlock() povide more than (keepSizeAfter)
318 to the end of (blockSize).
319 So we don't execute this branch in normal code flow.
320 We can go here, if we will call ReadBlock() before NeedMove(), MoveBlock().
322 // p->result = SZ_ERROR_FAIL; // we can show error here
323 return;
326 // #define kRead 3
327 // if (size > kRead) size = kRead; // for debug
329 //p.result = ISeqInStream_Read(p.stream, dest, &size);
330 p.result = p.stream.Read(p.stream, dest, &size);
331 if (p.result != SZ_OK)
332 return;
333 if (size == 0)
335 p.streamEndWasReached = 1;
336 return;
338 p.streamPos += cast(uint)size;
339 if (mixin(Inline_MatchFinder_GetNumAvailableBytes!"p") > p.keepSizeAfter)
340 return;
341 /* here and in another (p->keepSizeAfter) checks we keep on 1 byte more than was requested by Create() function
342 (Inline_MatchFinder_GetNumAvailableBytes(p) >= p->keepSizeAfter) - minimal required size */
345 // on exit: (p->result != SZ_OK || p->streamEndWasReached || Inline_MatchFinder_GetNumAvailableBytes(p) > p->keepSizeAfter)
350 //MY_NO_INLINE
351 private void MatchFinder_MoveBlock (CMatchFinder *p) @nogc {
352 import core.stdc.string : memmove;
353 const usize offset = cast(usize)(p.buffer - p.bufferBase) - p.keepSizeBefore;
354 const usize keepBefore = (offset & (kBlockMoveAlign - 1)) + p.keepSizeBefore;
355 p.buffer = p.bufferBase + keepBefore;
356 memmove(p.bufferBase,
357 p.bufferBase + (offset & ~(cast(usize)kBlockMoveAlign - 1)),
358 keepBefore + cast(usize)mixin(Inline_MatchFinder_GetNumAvailableBytes!"p"));
361 /* We call MoveBlock() before ReadBlock().
362 So MoveBlock() can be wasteful operation, if the whole input data
363 can fit in current block even without calling MoveBlock().
364 in important case where (dataSize <= historySize)
365 condition (p->blockSize > dataSize + p->keepSizeAfter) is met
366 So there is no MoveBlock() in that case case.
369 private int MatchFinder_NeedMove (CMatchFinder *p) @nogc {
370 if (p.directInput)
371 return 0;
372 if (p.streamEndWasReached || p.result != SZ_OK)
373 return 0;
374 return (cast(usize)(p.bufferBase + p.blockSize - p.buffer) <= p.keepSizeAfter);
377 private void MatchFinder_ReadIfRequired (CMatchFinder *p) {
378 if (p.keepSizeAfter >= mixin(Inline_MatchFinder_GetNumAvailableBytes!"p"))
379 MatchFinder_ReadBlock(p);
383 private void MatchFinder_SetDefaultSettings (CMatchFinder* p) @nogc {
384 p.cutValue = 32;
385 p.btMode = 1;
386 p.numHashBytes = 4;
387 p.bigHash = 0;
390 enum kCrcPoly = 0xEDB88320;
392 private void MatchFinder_Construct (CMatchFinder* p) @nogc {
393 uint i;
394 p.bufferBase = null;
395 p.directInput = 0;
396 p.hash = null;
397 p.expectedDataSize = cast(ulong)cast(long)-1;
398 MatchFinder_SetDefaultSettings(p);
400 for (i = 0; i < 256; i++)
402 uint r = cast(uint)i;
403 uint j;
404 for (j = 0; j < 8; j++)
405 r = (r >> 1) ^ (kCrcPoly & (cast(uint)0 - (r & 1)));
406 p.crc[i] = r;
410 private void MatchFinder_FreeThisClassMemory(CMatchFinder *p, ISzAllocPtr alloc)
412 ISzAlloc_Free(alloc, p.hash);
413 p.hash = null;
416 private void MatchFinder_Free(CMatchFinder *p, ISzAllocPtr alloc)
418 MatchFinder_FreeThisClassMemory(p, alloc);
419 LzInWindow_Free(p, alloc);
422 private CLzRef* AllocRefs(usize num, ISzAllocPtr alloc)
424 usize sizeInBytes = cast(usize)num * CLzRef.sizeof;
425 if (sizeInBytes / CLzRef.sizeof != num)
426 return null;
427 return cast(CLzRef *)ISzAlloc_Alloc(alloc, sizeInBytes);
430 static assert(kBlockSizeReserveMin >= kBlockSizeAlign * 2, "Stop_Compiling_Bad_Reserve");
434 private uint GetBlockSize (CMatchFinder* p, uint historySize) @nogc {
435 uint blockSize = (p.keepSizeBefore + p.keepSizeAfter);
437 if (historySize > kMaxHistorySize)
438 return 0;
440 // printf("\nhistorySize == 0x%x\n", historySize);
442 if (p.keepSizeBefore < historySize || blockSize < p.keepSizeBefore) // if 32-bit overflow
443 return 0;
446 const uint kBlockSizeMax = cast(uint)0 - cast(uint)kBlockSizeAlign;
447 const uint rem = kBlockSizeMax - blockSize;
448 const uint reserve = (blockSize >> (blockSize < (cast(uint)1 << 30) ? 1 : 2))
449 + (1 << 12) + kBlockMoveAlign + kBlockSizeAlign; // do not overflow 32-bit here
450 if (blockSize >= kBlockSizeMax
451 || rem < kBlockSizeReserveMin) // we reject settings that will be slow
452 return 0;
453 if (reserve >= rem)
454 blockSize = kBlockSizeMax;
455 else
457 blockSize += reserve;
458 blockSize &= ~cast(uint)(kBlockSizeAlign - 1);
461 // printf("\n LzFind_blockSize = %x\n", blockSize);
462 // printf("\n LzFind_blockSize = %d\n", blockSize >> 20);
463 return blockSize;
467 private int MatchFinder_Create(CMatchFinder *p, uint historySize,
468 uint keepAddBufferBefore, uint matchMaxLen, uint keepAddBufferAfter,
469 ISzAllocPtr alloc)
471 /* we need one additional byte in (p->keepSizeBefore),
472 since we use MoveBlock() after (p->pos++) and before dictionary using */
473 // keepAddBufferBefore = (uint)0xFFFFFFFF - (1 << 22); // for debug
474 p.keepSizeBefore = historySize + keepAddBufferBefore + 1;
476 keepAddBufferAfter += matchMaxLen;
477 /* we need (p->keepSizeAfter >= p->numHashBytes) */
478 if (keepAddBufferAfter < p.numHashBytes)
479 keepAddBufferAfter = p.numHashBytes;
480 // keepAddBufferAfter -= 2; // for debug
481 p.keepSizeAfter = keepAddBufferAfter;
483 if (p.directInput)
484 p.blockSize = 0;
485 if (p.directInput || LzInWindow_Create2(p, GetBlockSize(p, historySize), alloc))
487 const uint newCyclicBufferSize = historySize + 1; // do not change it
488 uint hs;
489 p.matchMaxLen = matchMaxLen;
491 // uint hs4;
492 p.fixedHashSize = 0;
493 hs = (1 << 16) - 1;
494 if (p.numHashBytes != 2)
496 hs = historySize;
497 if (hs > p.expectedDataSize)
498 hs = cast(uint)p.expectedDataSize;
499 if (hs != 0)
500 hs--;
501 hs |= (hs >> 1);
502 hs |= (hs >> 2);
503 hs |= (hs >> 4);
504 hs |= (hs >> 8);
505 // we propagated 16 bits in (hs). Low 16 bits must be set later
506 hs >>= 1;
507 if (hs >= (1 << 24))
509 if (p.numHashBytes == 3)
510 hs = (1 << 24) - 1;
511 else
512 hs >>= 1;
513 /* if (bigHash) mode, GetHeads4b() in LzFindMt.c needs (hs >= ((1 << 24) - 1))) */
516 // hs = ((uint)1 << 25) - 1; // for test
518 // (hash_size >= (1 << 16)) : Required for (numHashBytes > 2)
519 hs |= (1 << 16) - 1; /* don't change it! */
521 // bt5: we adjust the size with recommended minimum size
522 if (p.numHashBytes >= 5)
523 hs |= (256 << kLzHash_CrcShift_2) - 1;
525 p.hashMask = hs;
526 hs++;
529 hs4 = (1 << 20);
530 if (hs4 > hs)
531 hs4 = hs;
532 // hs4 = (1 << 16); // for test
533 p->hash4Mask = hs4 - 1;
536 if (p.numHashBytes > 2) p.fixedHashSize += kHash2Size;
537 if (p.numHashBytes > 3) p.fixedHashSize += kHash3Size;
538 // if (p->numHashBytes > 4) p->fixedHashSize += hs4; // kHash4Size;
539 hs += p.fixedHashSize;
543 usize newSize;
544 usize numSons;
545 p.historySize = historySize;
546 p.hashSizeSum = hs;
547 p.cyclicBufferSize = newCyclicBufferSize; // it must be = (historySize + 1)
549 numSons = newCyclicBufferSize;
550 if (p.btMode)
551 numSons <<= 1;
552 newSize = hs + numSons;
554 // aligned size is not required here, but it can be better for some loops
555 enum NUM_REFS_ALIGN_MASK = 0xF;
556 newSize = (newSize + NUM_REFS_ALIGN_MASK) & ~cast(usize)NUM_REFS_ALIGN_MASK;
558 if (p.hash && p.numRefs == newSize)
559 return 1;
561 MatchFinder_FreeThisClassMemory(p, alloc);
562 p.numRefs = newSize;
563 p.hash = AllocRefs(newSize, alloc);
565 if (p.hash)
567 p.son = p.hash + p.hashSizeSum;
568 return 1;
573 MatchFinder_Free(p, alloc);
574 return 0;
578 private void MatchFinder_SetLimits (CMatchFinder* p) @nogc {
579 uint k;
580 uint n = kMaxValForNormalize - p.pos;
581 if (n == 0)
582 n = cast(uint)cast(int)-1; // we allow (pos == 0) at start even with (kMaxValForNormalize == 0)
584 k = p.cyclicBufferSize - p.cyclicBufferPos;
585 if (k < n)
586 n = k;
588 k = mixin(Inline_MatchFinder_GetNumAvailableBytes!"p");
590 const uint ksa = p.keepSizeAfter;
591 uint mm = p.matchMaxLen;
592 if (k > ksa)
593 k -= ksa; // we must limit exactly to keepSizeAfter for ReadBlock
594 else if (k >= mm)
596 // the limitation for (p->lenLimit) update
597 k -= mm; // optimization : to reduce the number of checks
598 k++;
599 // k = 1; // non-optimized version : for debug
601 else
603 mm = k;
604 if (k != 0)
605 k = 1;
607 p.lenLimit = mm;
609 if (k < n)
610 n = k;
612 p.posLimit = p.pos + n;
616 private void MatchFinder_Init_LowHash (CMatchFinder* p) @nogc {
617 usize i;
618 CLzRef *items = p.hash;
619 const usize numItems = p.fixedHashSize;
620 for (i = 0; i < numItems; i++)
621 items[i] = kEmptyHashValue;
625 private void MatchFinder_Init_HighHash (CMatchFinder* p) @nogc {
626 usize i;
627 CLzRef *items = p.hash + p.fixedHashSize;
628 const usize numItems = cast(usize)p.hashMask + 1;
629 for (i = 0; i < numItems; i++)
630 items[i] = kEmptyHashValue;
634 private void MatchFinder_Init_4 (CMatchFinder* p) @nogc {
635 p.buffer = p.bufferBase;
637 /* kEmptyHashValue = 0 (Zero) is used in hash tables as NO-VALUE marker.
638 the code in CMatchFinderMt expects (pos = 1) */
639 p.pos =
640 p.streamPos =
641 1; // it's smallest optimal value. do not change it
642 // 0; // for debug
644 p.result = SZ_OK;
645 p.streamEndWasReached = 0;
649 // (CYC_TO_POS_OFFSET == 0) is expected by some optimized code
650 enum CYC_TO_POS_OFFSET = 0;
651 // #define CYC_TO_POS_OFFSET 1 // for debug
653 private void MatchFinder_Init (CMatchFinder* p) {
654 MatchFinder_Init_HighHash(p);
655 MatchFinder_Init_LowHash(p);
656 MatchFinder_Init_4(p);
657 // if (readData)
658 MatchFinder_ReadBlock(p);
660 /* if we init (cyclicBufferPos = pos), then we can use one variable
661 instead of both (cyclicBufferPos) and (pos) : only before (cyclicBufferPos) wrapping */
662 p.cyclicBufferPos = (p.pos - CYC_TO_POS_OFFSET); // init with relation to (pos)
663 // p->cyclicBufferPos = 0; // smallest value
664 // p->son[0] = p->son[1] = 0; // unused: we can init skipped record for speculated accesses.
665 MatchFinder_SetLimits(p);
670 // kEmptyHashValue must be zero
671 // #define SASUB_32(i) v = items[i]; m = v - subValue; if (v < subValue) m = kEmptyHashValue; items[i] = m;
672 //#define SASUB_32(i) v = items[i]; if (v < subValue) v = subValue; items[i] = v - subValue;
673 enum SASUB_32(string i) = `v = items[`~i~`]; if (v < subValue) v = subValue; items[`~i~`] = v - subValue;`;
675 //MY_NO_INLINE
676 private void LzFind_SaturSub_32 (uint subValue, CLzRef* items, const(CLzRef)* lim) @nogc {
679 uint v;
680 mixin(SASUB_32!"0");
681 mixin(SASUB_32!"1");
682 mixin(SASUB_32!"2");
683 mixin(SASUB_32!"3");
684 mixin(SASUB_32!"4");
685 mixin(SASUB_32!"5");
686 mixin(SASUB_32!"6");
687 mixin(SASUB_32!"7");
688 items += 8;
690 while (items != lim);
694 //MY_NO_INLINE
695 private void MatchFinder_Normalize3 (uint subValue, CLzRef* items, usize numItems) @nogc {
696 enum K_NORM_ALIGN_BLOCK_SIZE = (1 << 6);
698 CLzRef *lim;
700 for (; numItems != 0 && (cast(uint)cast(ptrdiff_t)items & (K_NORM_ALIGN_BLOCK_SIZE - 1)) != 0; numItems--)
702 uint v;
703 mixin(SASUB_32!"0");
704 items++;
708 enum K_NORM_ALIGN_MASK = (K_NORM_ALIGN_BLOCK_SIZE / 4 - 1);
709 lim = items + (numItems & ~cast(usize)K_NORM_ALIGN_MASK);
710 numItems &= K_NORM_ALIGN_MASK;
711 if (items != lim)
713 LzFind_SaturSub_32(subValue, items, lim);
715 items = lim;
719 for (; numItems != 0; numItems--)
721 uint v;
722 mixin(SASUB_32!"0");
723 items++;
729 // call MatchFinder_CheckLimits() only after (p->pos++) update
731 //MY_NO_INLINE
732 private void MatchFinder_CheckLimits (CMatchFinder* p) {
733 if (// !p->streamEndWasReached && p->result == SZ_OK &&
734 p.keepSizeAfter == mixin(Inline_MatchFinder_GetNumAvailableBytes!"p"))
736 // we try to read only in exact state (p->keepSizeAfter == Inline_MatchFinder_GetNumAvailableBytes(p))
737 if (MatchFinder_NeedMove(p))
738 MatchFinder_MoveBlock(p);
739 MatchFinder_ReadBlock(p);
742 if (p.pos == kMaxValForNormalize)
743 if (mixin(Inline_MatchFinder_GetNumAvailableBytes!"p") >= p.numHashBytes) // optional optimization for last bytes of data.
745 if we disable normalization for last bytes of data, and
746 if (data_size == 4 GiB), we don't call wastfull normalization,
747 but (pos) will be wrapped over Zero (0) in that case.
748 And we cannot resume later to normal operation
751 // MatchFinder_Normalize(p);
752 /* after normalization we need (p->pos >= p->historySize + 1); */
753 /* we can reduce subValue to aligned value, if want to keep alignment
754 of (p->pos) and (p->buffer) for speculated accesses. */
755 const uint subValue = (p.pos - p.historySize - 1) /* & ~(uint)(kNormalizeAlign - 1) */;
756 // const uint subValue = (1 << 15); // for debug
757 // printf("\nMatchFinder_Normalize() subValue == 0x%x\n", subValue);
758 usize numSonRefs = p.cyclicBufferSize;
759 if (p.btMode)
760 numSonRefs <<= 1;
762 //Inline_MatchFinder_ReduceOffsets(p, subValue);
763 p.pos -= subValue;
764 p.streamPos -= subValue;
766 MatchFinder_Normalize3(subValue, p.hash, cast(usize)p.hashSizeSum + numSonRefs);
769 if (p.cyclicBufferPos == p.cyclicBufferSize)
770 p.cyclicBufferPos = 0;
772 MatchFinder_SetLimits(p);
777 (lenLimit > maxLen)
779 //MY_FORCE_INLINE
780 private uint * Hc_GetMatchesSpec (usize lenLimit, uint curMatch, uint pos, const(ubyte)* cur, CLzRef *son,
781 usize _cyclicBufferPos, uint _cyclicBufferSize, uint cutValue,
782 uint *d, uint maxLen) @nogc
785 son[_cyclicBufferPos] = curMatch;
786 for (;;)
788 uint delta = pos - curMatch;
789 if (cutValue-- == 0 || delta >= _cyclicBufferSize)
790 return d;
792 const ubyte *pb = cur - delta;
793 curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)];
794 if (pb[maxLen] == cur[maxLen] && *pb == *cur)
796 uint len = 0;
797 while (++len != lenLimit)
798 if (pb[len] != cur[len])
799 break;
800 if (maxLen < len)
802 maxLen = len;
803 *d++ = len;
804 *d++ = delta - 1;
805 if (len == lenLimit)
806 return d;
813 const(ubyte)* lim = cur + lenLimit;
814 son[_cyclicBufferPos] = curMatch;
818 uint delta;
820 if (curMatch == 0)
821 break;
822 // if (curMatch2 >= curMatch) return null;
823 delta = pos - curMatch;
824 if (delta >= _cyclicBufferSize)
825 break;
827 ptrdiff_t diff;
828 curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)];
829 diff = cast(ptrdiff_t)0 - cast(ptrdiff_t)delta;
830 if (cur[maxLen] == cur[cast(ptrdiff_t)maxLen + diff])
832 const(ubyte)* c = cur;
833 while (*c == c[diff])
835 if (++c == lim)
837 d[0] = cast(uint)(lim - cur);
838 d[1] = delta - 1;
839 return d + 2;
843 const uint len = cast(uint)(c - cur);
844 if (maxLen < len)
846 maxLen = len;
847 d[0] = cast(uint)len;
848 d[1] = delta - 1;
849 d += 2;
855 while (--cutValue);
857 return d;
861 //MY_FORCE_INLINE
862 private uint* GetMatchesSpec1 (uint lenLimit, uint curMatch, uint pos, const(ubyte)* cur, CLzRef *son,
863 usize _cyclicBufferPos, uint _cyclicBufferSize, uint cutValue,
864 uint *d, uint maxLen) @nogc
866 CLzRef *ptr0 = son + (cast(usize)_cyclicBufferPos << 1) + 1;
867 CLzRef *ptr1 = son + (cast(usize)_cyclicBufferPos << 1);
868 uint len0 = 0, len1 = 0;
870 uint cmCheck;
872 // if (curMatch >= pos) { *ptr0 = *ptr1 = kEmptyHashValue; return null; }
874 cmCheck = cast(uint)(pos - _cyclicBufferSize);
875 if (cast(uint)pos <= _cyclicBufferSize)
876 cmCheck = 0;
878 if (cmCheck < curMatch)
881 const uint delta = pos - curMatch;
883 CLzRef *pair = son + (cast(usize)(_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
884 const ubyte *pb = cur - delta;
885 uint len = (len0 < len1 ? len0 : len1);
886 const uint pair0 = pair[0];
887 if (pb[len] == cur[len])
889 if (++len != lenLimit && pb[len] == cur[len])
890 while (++len != lenLimit)
891 if (pb[len] != cur[len])
892 break;
893 if (maxLen < len)
895 maxLen = cast(uint)len;
896 *d++ = cast(uint)len;
897 *d++ = delta - 1;
898 if (len == lenLimit)
900 *ptr1 = pair0;
901 *ptr0 = pair[1];
902 return d;
906 if (pb[len] < cur[len])
908 *ptr1 = curMatch;
909 // const uint curMatch2 = pair[1];
910 // if (curMatch2 >= curMatch) { *ptr0 = *ptr1 = kEmptyHashValue; return null; }
911 // curMatch = curMatch2;
912 curMatch = pair[1];
913 ptr1 = pair + 1;
914 len1 = len;
916 else
918 *ptr0 = curMatch;
919 curMatch = pair[0];
920 ptr0 = pair;
921 len0 = len;
925 while(--cutValue && cmCheck < curMatch);
927 *ptr0 = *ptr1 = kEmptyHashValue;
928 return d;
932 private void SkipMatchesSpec (uint lenLimit, uint curMatch, uint pos, const(ubyte)* cur, CLzRef *son,
933 usize _cyclicBufferPos, uint _cyclicBufferSize, uint cutValue) @nogc
935 CLzRef *ptr0 = son + (cast(usize)_cyclicBufferPos << 1) + 1;
936 CLzRef *ptr1 = son + (cast(usize)_cyclicBufferPos << 1);
937 uint len0 = 0, len1 = 0;
939 uint cmCheck;
941 cmCheck = cast(uint)(pos - _cyclicBufferSize);
942 if (cast(uint)pos <= _cyclicBufferSize)
943 cmCheck = 0;
945 if (// curMatch >= pos || // failure
946 cmCheck < curMatch)
949 const uint delta = pos - curMatch;
951 CLzRef *pair = son + (cast(usize)(_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
952 const ubyte *pb = cur - delta;
953 uint len = (len0 < len1 ? len0 : len1);
954 if (pb[len] == cur[len])
956 while (++len != lenLimit)
957 if (pb[len] != cur[len])
958 break;
960 if (len == lenLimit)
962 *ptr1 = pair[0];
963 *ptr0 = pair[1];
964 return;
968 if (pb[len] < cur[len])
970 *ptr1 = curMatch;
971 curMatch = pair[1];
972 ptr1 = pair + 1;
973 len1 = len;
975 else
977 *ptr0 = curMatch;
978 curMatch = pair[0];
979 ptr0 = pair;
980 len0 = len;
984 while(--cutValue && cmCheck < curMatch);
986 *ptr0 = *ptr1 = kEmptyHashValue;
987 return;
991 enum MOVE_POS = q{
992 ++p.cyclicBufferPos;
993 p.buffer++;
994 { const uint pos1 = p.pos + 1; p.pos = pos1; if (pos1 == p.posLimit) MatchFinder_CheckLimits(p); }
997 enum MOVE_POS_RET = MOVE_POS~`return distances;`;
999 //MY_NO_INLINE
1000 private void MatchFinder_MovePos (CMatchFinder *p) {
1001 pragma(inline, true);
1002 /* we go here at the end of stream data, when (avail < num_hash_bytes)
1003 We don't update sons[cyclicBufferPos << btMode].
1004 So (sons) record will contain junk. And we cannot resume match searching
1005 to normal operation, even if we will provide more input data in buffer.
1006 p->sons[p->cyclicBufferPos << p->btMode] = 0; // kEmptyHashValue
1007 if (p->btMode)
1008 p->sons[(p->cyclicBufferPos << p->btMode) + 1] = 0; // kEmptyHashValue
1010 mixin(MOVE_POS);
1013 enum GET_MATCHES_HEADER2(string minLen, string ret_op) = `
1014 uint lenLimit; uint hv; ubyte *cur; uint curMatch;
1015 lenLimit = cast(uint)p.lenLimit; { if (lenLimit < `~minLen~`) { MatchFinder_MovePos(p); `~ret_op~`; } }
1016 cur = p.buffer;
1019 enum GET_MATCHES_HEADER(string minLen) = GET_MATCHES_HEADER2!(minLen, "return distances");
1020 //enum SKIP_HEADER(string minLen) = `do { `~GET_MATCHES_HEADER2!(minLen, "continue");
1021 enum SKIP_HEADER(string minLen) = GET_MATCHES_HEADER2!(minLen, "continue");
1023 enum MF_PARAMS(string p) = `lenLimit, curMatch, `~p~`.pos, `~p~`.buffer, `~p~`.son, `~p~`.cyclicBufferPos, `~p~`.cyclicBufferSize, `~p~`.cutValue`;
1025 //#define SKIP_FOOTER SkipMatchesSpec(MF_PARAMS(p)); mixin(MOVE_POS); } while (--num);
1026 enum SKIP_FOOTER = `SkipMatchesSpec(`~MF_PARAMS!"p"~`);`~MOVE_POS;
1029 enum GET_MATCHES_FOOTER_BASE(string _maxLen_, string func) = `
1030 distances = `~func~`(`~MF_PARAMS!"p"~`, distances, cast(uint)`~_maxLen_~`);`~MOVE_POS_RET;
1032 enum GET_MATCHES_FOOTER_BT(string _maxLen_) = GET_MATCHES_FOOTER_BASE!(_maxLen_, "GetMatchesSpec1");
1034 enum GET_MATCHES_FOOTER_HC(string _maxLen_) = GET_MATCHES_FOOTER_BASE!(_maxLen_, "Hc_GetMatchesSpec");
1038 enum UPDATE_maxLen = q{
1039 const ptrdiff_t diff = cast(ptrdiff_t)0 - cast(ptrdiff_t)d2;
1040 const(ubyte)* c = cur + maxLen;
1041 const(ubyte)* lim = cur + lenLimit;
1042 for (; c != lim; c++) if (*(c + diff) != *c) break;
1043 maxLen = cast(uint)(c - cur);
1047 private uint* Bt2_MatchFinder_GetMatches (CMatchFinder* p, uint* distances) {
1048 mixin(GET_MATCHES_HEADER!"2");
1049 hv = GetUi16(cur);
1050 curMatch = p.hash[hv];
1051 p.hash[hv] = p.pos;
1052 mixin(GET_MATCHES_FOOTER_BT!"1");
1055 private uint* Bt3Zip_MatchFinder_GetMatches (CMatchFinder* p, uint* distances) {
1056 mixin(GET_MATCHES_HEADER!"3");
1057 mixin(HASH_ZIP_CALC);
1058 curMatch = p.hash[hv];
1059 p.hash[hv] = p.pos;
1060 mixin(GET_MATCHES_FOOTER_BT!"2");
1064 enum SET_mmm = q{
1065 mmm = p.cyclicBufferSize;
1066 if (pos < mmm) mmm = pos;
1070 private uint* Bt3_MatchFinder_GetMatches (CMatchFinder* p, uint* distances) {
1071 uint mmm;
1072 uint h2, d2, pos;
1073 uint maxLen;
1074 uint *hash;
1075 mixin(GET_MATCHES_HEADER!"3");
1077 mixin(HASH3_CALC);
1079 hash = p.hash;
1080 pos = p.pos;
1082 d2 = pos - hash[h2];
1084 curMatch = (hash + kFix3HashSize)[hv];
1086 hash[h2] = pos;
1087 (hash + kFix3HashSize)[hv] = pos;
1089 mixin(SET_mmm);
1091 maxLen = 2;
1093 if (d2 < mmm && *(cur - d2) == *cur)
1095 mixin(UPDATE_maxLen);
1096 distances[0] = cast(uint)maxLen;
1097 distances[1] = d2 - 1;
1098 distances += 2;
1099 if (maxLen == lenLimit)
1101 mixin(`SkipMatchesSpec(`~MF_PARAMS!"p"~`);`);
1102 mixin(MOVE_POS_RET);
1106 mixin(GET_MATCHES_FOOTER_BT!"maxLen");
1110 private uint* Bt4_MatchFinder_GetMatches (CMatchFinder* p, uint* distances) {
1111 uint mmm;
1112 uint h2, h3, d2, d3, pos;
1113 uint maxLen;
1114 uint *hash;
1115 mixin(GET_MATCHES_HEADER!"4");
1117 mixin(HASH4_CALC);
1119 hash = p.hash;
1120 pos = p.pos;
1122 d2 = pos - hash [h2];
1123 d3 = pos - (hash + kFix3HashSize)[h3];
1124 curMatch = (hash + kFix4HashSize)[hv];
1126 hash [h2] = pos;
1127 (hash + kFix3HashSize)[h3] = pos;
1128 (hash + kFix4HashSize)[hv] = pos;
1130 mixin(SET_mmm);
1132 maxLen = 3;
1134 for (;;)
1136 if (d2 < mmm && *(cur - d2) == *cur)
1138 distances[0] = 2;
1139 distances[1] = d2 - 1;
1140 distances += 2;
1141 if (*(cur - d2 + 2) == cur[2])
1143 // distances[-2] = 3;
1145 else if (d3 < mmm && *(cur - d3) == *cur)
1147 d2 = d3;
1148 distances[1] = d3 - 1;
1149 distances += 2;
1151 else
1152 break;
1154 else if (d3 < mmm && *(cur - d3) == *cur)
1156 d2 = d3;
1157 distances[1] = d3 - 1;
1158 distances += 2;
1160 else
1161 break;
1163 mixin(UPDATE_maxLen);
1164 distances[-2] = cast(uint)maxLen;
1165 if (maxLen == lenLimit)
1167 mixin(`SkipMatchesSpec(`~MF_PARAMS!"p"~`);`);
1168 mixin(MOVE_POS_RET);
1170 break;
1173 mixin(GET_MATCHES_FOOTER_BT!"maxLen");
1177 private uint* Bt5_MatchFinder_GetMatches (CMatchFinder* p, uint* distances) {
1178 uint mmm;
1179 uint h2, h3, d2, d3, maxLen, pos;
1180 uint *hash;
1181 mixin(GET_MATCHES_HEADER!"5");
1183 mixin(HASH5_CALC);
1185 hash = p.hash;
1186 pos = p.pos;
1188 d2 = pos - hash [h2];
1189 d3 = pos - (hash + kFix3HashSize)[h3];
1190 // d4 = pos - (hash + kFix4HashSize)[h4];
1192 curMatch = (hash + kFix5HashSize)[hv];
1194 hash [h2] = pos;
1195 (hash + kFix3HashSize)[h3] = pos;
1196 // (hash + kFix4HashSize)[h4] = pos;
1197 (hash + kFix5HashSize)[hv] = pos;
1199 mixin(SET_mmm);
1201 maxLen = 4;
1203 for (;;)
1205 if (d2 < mmm && *(cur - d2) == *cur)
1207 distances[0] = 2;
1208 distances[1] = d2 - 1;
1209 distances += 2;
1210 if (*(cur - d2 + 2) == cur[2])
1213 else if (d3 < mmm && *(cur - d3) == *cur)
1215 distances[1] = d3 - 1;
1216 distances += 2;
1217 d2 = d3;
1219 else
1220 break;
1222 else if (d3 < mmm && *(cur - d3) == *cur)
1224 distances[1] = d3 - 1;
1225 distances += 2;
1226 d2 = d3;
1228 else
1229 break;
1231 distances[-2] = 3;
1232 if (*(cur - d2 + 3) != cur[3])
1233 break;
1234 mixin(UPDATE_maxLen);
1235 distances[-2] = cast(uint)maxLen;
1236 if (maxLen == lenLimit)
1238 mixin(`SkipMatchesSpec(`~MF_PARAMS!"p"~`);`);
1239 mixin(MOVE_POS_RET);
1241 break;
1244 mixin(GET_MATCHES_FOOTER_BT!"maxLen");
1248 private uint* Hc4_MatchFinder_GetMatches (CMatchFinder* p, uint* distances) {
1249 uint mmm;
1250 uint h2, h3, d2, d3, pos;
1251 uint maxLen;
1252 uint *hash;
1253 mixin(GET_MATCHES_HEADER!"4");
1255 mixin(HASH4_CALC);
1257 hash = p.hash;
1258 pos = p.pos;
1260 d2 = pos - hash [h2];
1261 d3 = pos - (hash + kFix3HashSize)[h3];
1262 curMatch = (hash + kFix4HashSize)[hv];
1264 hash [h2] = pos;
1265 (hash + kFix3HashSize)[h3] = pos;
1266 (hash + kFix4HashSize)[hv] = pos;
1268 mixin(SET_mmm);
1270 maxLen = 3;
1272 for (;;)
1274 if (d2 < mmm && *(cur - d2) == *cur)
1276 distances[0] = 2;
1277 distances[1] = d2 - 1;
1278 distances += 2;
1279 if (*(cur - d2 + 2) == cur[2])
1281 // distances[-2] = 3;
1283 else if (d3 < mmm && *(cur - d3) == *cur)
1285 d2 = d3;
1286 distances[1] = d3 - 1;
1287 distances += 2;
1289 else
1290 break;
1292 else if (d3 < mmm && *(cur - d3) == *cur)
1294 d2 = d3;
1295 distances[1] = d3 - 1;
1296 distances += 2;
1298 else
1299 break;
1301 mixin(UPDATE_maxLen);
1302 distances[-2] = cast(uint)maxLen;
1303 if (maxLen == lenLimit)
1305 p.son[p.cyclicBufferPos] = curMatch;
1306 mixin(MOVE_POS_RET);
1308 break;
1311 mixin(GET_MATCHES_FOOTER_HC!"maxLen");
1315 private uint *Hc5_MatchFinder_GetMatches (CMatchFinder* p, uint* distances) {
1316 uint mmm;
1317 uint h2, h3, d2, d3, maxLen, pos;
1318 uint *hash;
1319 mixin(GET_MATCHES_HEADER!"5");
1321 mixin(HASH5_CALC);
1323 hash = p.hash;
1324 pos = p.pos;
1326 d2 = pos - hash [h2];
1327 d3 = pos - (hash + kFix3HashSize)[h3];
1328 // d4 = pos - (hash + kFix4HashSize)[h4];
1330 curMatch = (hash + kFix5HashSize)[hv];
1332 hash [h2] = pos;
1333 (hash + kFix3HashSize)[h3] = pos;
1334 // (hash + kFix4HashSize)[h4] = pos;
1335 (hash + kFix5HashSize)[hv] = pos;
1337 mixin(SET_mmm);
1339 maxLen = 4;
1341 for (;;)
1343 if (d2 < mmm && *(cur - d2) == *cur)
1345 distances[0] = 2;
1346 distances[1] = d2 - 1;
1347 distances += 2;
1348 if (*(cur - d2 + 2) == cur[2])
1351 else if (d3 < mmm && *(cur - d3) == *cur)
1353 distances[1] = d3 - 1;
1354 distances += 2;
1355 d2 = d3;
1357 else
1358 break;
1360 else if (d3 < mmm && *(cur - d3) == *cur)
1362 distances[1] = d3 - 1;
1363 distances += 2;
1364 d2 = d3;
1366 else
1367 break;
1369 distances[-2] = 3;
1370 if (*(cur - d2 + 3) != cur[3])
1371 break;
1372 mixin(UPDATE_maxLen);
1373 distances[-2] = maxLen;
1374 if (maxLen == lenLimit)
1376 p.son[p.cyclicBufferPos] = curMatch;
1377 mixin(MOVE_POS_RET);
1379 break;
1382 mixin(GET_MATCHES_FOOTER_HC!"maxLen");
1386 private uint* Hc3Zip_MatchFinder_GetMatches (CMatchFinder* p, uint* distances) {
1387 mixin(GET_MATCHES_HEADER!"3");
1388 mixin(HASH_ZIP_CALC);
1389 curMatch = p.hash[hv];
1390 p.hash[hv] = p.pos;
1391 mixin(GET_MATCHES_FOOTER_HC!"2");
1395 private void Bt2_MatchFinder_Skip (CMatchFinder* p, uint num) {
1396 do { mixin(SKIP_HEADER!"2");
1398 hv = GetUi16(cur);
1399 curMatch = p.hash[hv];
1400 p.hash[hv] = p.pos;
1402 mixin(SKIP_FOOTER); } while (--num);
1405 private void Bt3Zip_MatchFinder_Skip (CMatchFinder* p, uint num) {
1406 do { mixin(SKIP_HEADER!"3");
1408 mixin(HASH_ZIP_CALC);
1409 curMatch = p.hash[hv];
1410 p.hash[hv] = p.pos;
1412 mixin(SKIP_FOOTER); } while (--num);
1415 private void Bt3_MatchFinder_Skip (CMatchFinder* p, uint num) {
1416 do { mixin(SKIP_HEADER!"3");
1418 uint h2;
1419 uint *hash;
1420 mixin(HASH3_CALC);
1421 hash = p.hash;
1422 curMatch = (hash + kFix3HashSize)[hv];
1423 hash[h2] =
1424 (hash + kFix3HashSize)[hv] = p.pos;
1426 mixin(SKIP_FOOTER); } while (--num);
1429 private void Bt4_MatchFinder_Skip (CMatchFinder* p, uint num) {
1430 do { mixin(SKIP_HEADER!"4");
1432 uint h2, h3;
1433 uint *hash;
1434 mixin(HASH4_CALC);
1435 hash = p.hash;
1436 curMatch = (hash + kFix4HashSize)[hv];
1437 hash [h2] =
1438 (hash + kFix3HashSize)[h3] =
1439 (hash + kFix4HashSize)[hv] = p.pos;
1441 mixin(SKIP_FOOTER); } while (--num);
1444 private void Bt5_MatchFinder_Skip (CMatchFinder* p, uint num) {
1445 do { mixin(SKIP_HEADER!"5");
1447 uint h2, h3;
1448 uint *hash;
1449 mixin(HASH5_CALC);
1450 hash = p.hash;
1451 curMatch = (hash + kFix5HashSize)[hv];
1452 hash [h2] =
1453 (hash + kFix3HashSize)[h3] =
1454 // (hash + kFix4HashSize)[h4] =
1455 (hash + kFix5HashSize)[hv] = p.pos;
1457 mixin(SKIP_FOOTER); } while (--num);
1461 private void Hc4_MatchFinder_Skip (CMatchFinder* p, uint num) {
1462 enum minLenSKH = 4;
1463 do { if (p.lenLimit < minLenSKH) { MatchFinder_MovePos(p); num--; continue; } {
1464 ubyte *cur;
1465 uint *hash;
1466 uint *son;
1467 uint pos = p.pos;
1468 uint num2 = num;
1469 /* (p->pos == p->posLimit) is not allowed here !!! */
1470 { const uint rem = p.posLimit - pos; if (num2 > rem) num2 = rem; }
1471 num -= num2;
1472 { const uint cycPos = p.cyclicBufferPos;
1473 son = p.son + cycPos;
1474 p.cyclicBufferPos = cycPos + num2; }
1475 cur = p.buffer;
1476 hash = p.hash;
1477 do {
1478 uint curMatch;
1479 uint hv;
1481 uint h2, h3;
1482 mixin(HASH4_CALC);
1483 curMatch = (hash + kFix4HashSize)[hv];
1484 hash [h2] =
1485 (hash + kFix3HashSize)[h3] =
1486 (hash + kFix4HashSize)[hv] = pos;
1488 //HC_SKIP_FOOTER
1489 cur++; pos++; *son++ = curMatch;
1490 } while (--num2);
1491 p.buffer = cur;
1492 p.pos = pos;
1493 if (pos == p.posLimit) MatchFinder_CheckLimits(p);
1494 }} while(num);
1498 private void Hc5_MatchFinder_Skip (CMatchFinder* p, uint num) {
1499 enum minLenSKH = 5;
1500 do { if (p.lenLimit < minLenSKH) { MatchFinder_MovePos(p); num--; continue; } {
1501 ubyte *cur;
1502 uint *hash;
1503 uint *son;
1504 uint pos = p.pos;
1505 uint num2 = num;
1506 /* (p->pos == p->posLimit) is not allowed here !!! */
1507 { const uint rem = p.posLimit - pos; if (num2 > rem) num2 = rem; }
1508 num -= num2;
1509 { const uint cycPos = p.cyclicBufferPos;
1510 son = p.son + cycPos;
1511 p.cyclicBufferPos = cycPos + num2; }
1512 cur = p.buffer;
1513 hash = p.hash;
1514 do {
1515 uint curMatch;
1516 uint hv;
1518 uint h2, h3;
1519 mixin(HASH5_CALC);
1520 curMatch = (hash + kFix5HashSize)[hv];
1521 hash [h2] =
1522 (hash + kFix3HashSize)[h3] =
1523 // (hash + kFix4HashSize)[h4] =
1524 (hash + kFix5HashSize)[hv] = pos;
1526 //HC_SKIP_FOOTER
1527 cur++; pos++; *son++ = curMatch;
1528 } while (--num2);
1529 p.buffer = cur;
1530 p.pos = pos;
1531 if (pos == p.posLimit) MatchFinder_CheckLimits(p);
1532 }} while(num);
1536 private void Hc3Zip_MatchFinder_Skip (CMatchFinder* p, uint num) {
1537 enum minLenSKH = 3;
1538 do { if (p.lenLimit < minLenSKH) { MatchFinder_MovePos(p); num--; continue; } {
1539 ubyte *cur;
1540 uint *hash;
1541 uint *son;
1542 uint pos = p.pos;
1543 uint num2 = num;
1544 /* (p->pos == p->posLimit) is not allowed here !!! */
1545 { const uint rem = p.posLimit - pos; if (num2 > rem) num2 = rem; }
1546 num -= num2;
1547 { const uint cycPos = p.cyclicBufferPos;
1548 son = p.son + cycPos;
1549 p.cyclicBufferPos = cycPos + num2; }
1550 cur = p.buffer;
1551 hash = p.hash;
1552 do {
1553 uint curMatch;
1554 uint hv;
1556 mixin(HASH_ZIP_CALC);
1557 curMatch = hash[hv];
1558 hash[hv] = pos;
1560 //HC_SKIP_FOOTER
1561 cur++; pos++; *son++ = curMatch;
1562 } while (--num2);
1563 p.buffer = cur;
1564 p.pos = pos;
1565 if (pos == p.posLimit) MatchFinder_CheckLimits(p);
1566 }} while(num);
1570 private void MatchFinder_CreateVTable (CMatchFinder* p, IMatchFinder2* vTable) @nogc {
1571 vTable.Init = cast(Mf_Init_Func)&MatchFinder_Init;
1572 vTable.GetNumAvailableBytes = cast(Mf_GetNumAvailableBytes_Func)&MatchFinder_GetNumAvailableBytes;
1573 vTable.GetPointerToCurrentPos = cast(Mf_GetPointerToCurrentPos_Func)&MatchFinder_GetPointerToCurrentPos;
1574 if (!p.btMode)
1576 if (p.numHashBytes <= 4)
1578 vTable.GetMatches = cast(Mf_GetMatches_Func)&Hc4_MatchFinder_GetMatches;
1579 vTable.Skip = cast(Mf_Skip_Func)&Hc4_MatchFinder_Skip;
1581 else
1583 vTable.GetMatches = cast(Mf_GetMatches_Func)&Hc5_MatchFinder_GetMatches;
1584 vTable.Skip = cast(Mf_Skip_Func)&Hc5_MatchFinder_Skip;
1587 else if (p.numHashBytes == 2)
1589 vTable.GetMatches = cast(Mf_GetMatches_Func)&Bt2_MatchFinder_GetMatches;
1590 vTable.Skip = cast(Mf_Skip_Func)&Bt2_MatchFinder_Skip;
1592 else if (p.numHashBytes == 3)
1594 vTable.GetMatches = cast(Mf_GetMatches_Func)&Bt3_MatchFinder_GetMatches;
1595 vTable.Skip = cast(Mf_Skip_Func)&Bt3_MatchFinder_Skip;
1597 else if (p.numHashBytes == 4)
1599 vTable.GetMatches = cast(Mf_GetMatches_Func)&Bt4_MatchFinder_GetMatches;
1600 vTable.Skip = cast(Mf_Skip_Func)&Bt4_MatchFinder_Skip;
1602 else
1604 vTable.GetMatches = cast(Mf_GetMatches_Func)&Bt5_MatchFinder_GetMatches;
1605 vTable.Skip = cast(Mf_Skip_Func)&Bt5_MatchFinder_Skip;
1610 private void LzFindPrepare () @nogc {
1614 // ////////////////////////////////////////////////////////////////////////// //
1615 // ////////////////////////////////////////////////////////////////////////// //
1616 // ////////////////////////////////////////////////////////////////////////// //
1617 // ////////////////////////////////////////////////////////////////////////// //
1618 /* for good normalization speed we still reserve 256 MB before 4 GB range */
1619 enum kLzmaMaxHistorySize = (cast(uint)15 << 28);
1621 enum kNumTopBits = 24;
1622 enum kTopValue = (cast(uint)1 << kNumTopBits);
1624 enum kNumBitModelTotalBits = 11;
1625 enum kBitModelTotal = (1 << kNumBitModelTotalBits);
1626 enum kNumMoveBits = 5;
1627 enum kProbInitValue = (kBitModelTotal >> 1);
1629 enum kNumMoveReducingBits = 4;
1630 enum kNumBitPriceShiftBits = 4;
1631 // #define kBitPrice (1 << kNumBitPriceShiftBits)
1633 enum REP_LEN_COUNT = 64;
1636 //==========================================================================
1638 // LzmaEncProps_Init
1640 //==========================================================================
1641 public void LzmaEncProps_Init (CLzmaEncProps* p) @nogc {
1642 p.level = 5;
1643 p.dictSize = p.mc = 0;
1644 p.reduceSize = cast(ulong)cast(long)-1;
1645 p.lc = p.lp = p.pb = p.algo = p.fb = p.btMode = p.numHashBytes = -1;
1646 p.writeEndMark = 0;
1650 //==========================================================================
1652 // LzmaEncProps_Normalize
1654 //==========================================================================
1655 public void LzmaEncProps_Normalize (CLzmaEncProps* p) @nogc {
1656 int level = p.level;
1657 if (level < 0) level = 5;
1658 p.level = level;
1660 if (p.dictSize == 0)
1661 p.dictSize =
1662 ( level <= 3 ? (cast(uint)1 << (level * 2 + 16)) :
1663 ( level <= 6 ? (cast(uint)1 << (level + 19)) :
1664 ( level <= 7 ? (cast(uint)1 << 25) : (cast(uint)1 << 26)
1665 )));
1667 if (p.dictSize > p.reduceSize)
1669 uint v = cast(uint)p.reduceSize;
1670 const uint kReduceMin = (cast(uint)1 << 12);
1671 if (v < kReduceMin)
1672 v = kReduceMin;
1673 if (p.dictSize > v)
1674 p.dictSize = v;
1677 if (p.lc < 0) p.lc = 3;
1678 if (p.lp < 0) p.lp = 0;
1679 if (p.pb < 0) p.pb = 2;
1681 if (p.algo < 0) p.algo = (level < 5 ? 0 : 1);
1682 if (p.fb < 0) p.fb = (level < 7 ? 32 : 64);
1683 if (p.btMode < 0) p.btMode = (p.algo == 0 ? 0 : 1);
1684 if (p.numHashBytes < 0) p.numHashBytes = (p.btMode ? 4 : 5);
1685 if (p.mc == 0) p.mc = (16 + (cast(uint)p.fb >> 1)) >> (p.btMode ? 0 : 1);
1689 //==========================================================================
1691 // LzmaEncProps_GetDictSize
1693 //==========================================================================
1694 public uint LzmaEncProps_GetDictSize (const(CLzmaEncProps)* props2) @nogc {
1695 CLzmaEncProps props = *props2;
1696 LzmaEncProps_Normalize(&props);
1697 return props.dictSize;
1702 x86/x64:
1704 BSR:
1705 IF (SRC == 0) ZF = 1, DEST is undefined;
1706 AMD : DEST is unchanged;
1707 IF (SRC != 0) ZF = 0; DEST is index of top non-zero bit
1708 BSR is slow in some processors
1710 LZCNT:
1711 IF (SRC == 0) CF = 1, DEST is size_in_bits_of_register(src) (32 or 64)
1712 IF (SRC != 0) CF = 0, DEST = num_lead_zero_bits
1713 IF (DEST == 0) ZF = 1;
1715 LZCNT works only in new processors starting from Haswell.
1716 if LZCNT is not supported by processor, then it's executed as BSR.
1717 LZCNT can be faster than BSR, if supported.
1721 //k8: define this for ARM (for some reason)
1722 // #define LZMA_LOG_BSR
1724 #ifdef LZMA_LOG_BSR
1727 C code: : (30 - __builtin_clz(x))
1728 gcc9/gcc10 for x64 /x86 : 30 - (bsr(x) xor 31)
1729 clang10 for x64 : 31 + (bsr(x) xor -32)
1732 #define MY_clz(x) ((uint)__builtin_clz(x))
1733 // __lzcnt32
1734 // __builtin_ia32_lzcnt_u32
1737 #ifndef BSR2_RET
1739 #define BSR2_RET(pos, res) { uint zz = 30 - MY_clz(pos); \
1740 res = (zz + zz) + (pos >> zz); }
1742 #endif
1745 uint GetPosSlot1(uint pos);
1746 uint GetPosSlot1(uint pos)
1748 uint res;
1749 BSR2_RET(pos, res);
1750 return res;
1752 #define GetPosSlot2(pos, res) { BSR2_RET(pos, res); }
1753 #define GetPosSlot(pos, res) { if (pos < 2) res = pos; else BSR2_RET(pos, res); }
1756 #else // ! LZMA_LOG_BSR
1759 enum kNumLogBits = (11 + usize.sizeof / 8 * 3);
1761 enum kDicLogSizeMaxCompress = ((kNumLogBits - 1) * 2 + 7);
1763 private void LzmaEnc_FastPosInit (ubyte* g_FastPos) @nogc {
1764 uint slot;
1765 g_FastPos[0] = 0;
1766 g_FastPos[1] = 1;
1767 g_FastPos += 2;
1769 for (slot = 2; slot < kNumLogBits * 2; slot++)
1771 usize k = (cast(usize)1 << ((slot >> 1) - 1));
1772 usize j;
1773 for (j = 0; j < k; j++)
1774 g_FastPos[j] = cast(ubyte)slot;
1775 g_FastPos += k;
1779 /* we can use ((limit - pos) >> 31) only if (pos < ((uint)1 << 31)) */
1781 #define BSR2_RET(pos, res) { uint zz = 6 + ((kNumLogBits - 1) & \
1782 (0 - (((((uint)1 << (kNumLogBits + 6)) - 1) - pos) >> 31))); \
1783 res = p->g_FastPos[pos >> zz] + (zz * 2); }
1787 #define BSR2_RET(pos, res) { uint zz = 6 + ((kNumLogBits - 1) & \
1788 (0 - (((((uint)1 << (kNumLogBits)) - 1) - (pos >> 6)) >> 31))); \
1789 res = p->g_FastPos[pos >> zz] + (zz * 2); }
1792 enum BSR2_RET(string pos, string res) = `
1793 { uint zz = (`~pos~` < (1 << (kNumLogBits + 6))) ? 6 : 6 + kNumLogBits - 1;
1794 `~res~` = p.g_FastPos[`~pos~` >> zz] + (zz * 2); }
1798 #define BSR2_RET(pos, res) { res = (pos < (1 << (kNumLogBits + 6))) ? \
1799 p->g_FastPos[pos >> 6] + 12 : \
1800 p->g_FastPos[pos >> (6 + kNumLogBits - 1)] + (6 + (kNumLogBits - 1)) * 2; }
1803 enum GetPosSlot1(string pos) = `p.g_FastPos[`~pos~`]`;
1805 enum GetPosSlot2(string pos, string res) = BSR2_RET!(pos, res);
1807 enum GetPosSlot(string pos, string res) = `{
1808 if (`~pos~` < kNumFullDistances) `~res~` = p.g_FastPos[`~pos~` & (kNumFullDistances - 1)];
1809 else {`~BSR2_RET!(pos, res)~`}
1812 //#endif // LZMA_LOG_BSR
1815 enum LZMA_NUM_REPS = 4;
1817 alias CState = ushort;
1818 alias CExtra = ushort;
1820 struct COptimal {
1821 uint price;
1822 CState state;
1823 CExtra extra;
1824 // 0 : normal
1825 // 1 : LIT : MATCH
1826 // > 1 : MATCH (extra-1) : LIT : REP0 (len)
1827 uint len;
1828 uint dist;
1829 uint[LZMA_NUM_REPS] reps;
1833 // 18.06
1834 enum kNumOpts = (1 << 11);
1835 enum kPackReserve = (kNumOpts * 8);
1836 // #define kNumOpts (1 << 12)
1837 // #define kPackReserve (1 + kNumOpts * 2)
1839 enum kNumLenToPosStates = 4;
1840 enum kNumPosSlotBits = 6;
1841 // #define kDicLogSizeMin 0
1842 enum kDicLogSizeMax = 32;
1843 enum kDistTableSizeMax = (kDicLogSizeMax * 2);
1845 enum kNumAlignBits = 4;
1846 enum kAlignTableSize = (1 << kNumAlignBits);
1847 enum kAlignMask = (kAlignTableSize - 1);
1849 enum kStartPosModelIndex = 4;
1850 enum kEndPosModelIndex = 14;
1851 enum kNumFullDistances = (1 << (kEndPosModelIndex >> 1));
1853 enum LZMA_PB_MAX = 4;
1854 enum LZMA_LC_MAX = 8;
1855 enum LZMA_LP_MAX = 4;
1857 enum LZMA_NUM_PB_STATES_MAX = (1 << LZMA_PB_MAX);
1859 enum kLenNumLowBits = 3;
1860 enum kLenNumLowSymbols = (1 << kLenNumLowBits);
1861 enum kLenNumHighBits = 8;
1862 enum kLenNumHighSymbols = (1 << kLenNumHighBits);
1863 enum kLenNumSymbolsTotal = (kLenNumLowSymbols * 2 + kLenNumHighSymbols);
1865 enum LZMA_MATCH_LEN_MIN = 2;
1866 enum LZMA_MATCH_LEN_MAX = (LZMA_MATCH_LEN_MIN + kLenNumSymbolsTotal - 1);
1868 enum kNumStates = 12;
1871 struct CLenEnc {
1872 CLzmaProb[LZMA_NUM_PB_STATES_MAX << (kLenNumLowBits + 1)] low;
1873 CLzmaProb[kLenNumHighSymbols] high;
1877 struct CLenPriceEnc {
1878 uint tableSize;
1879 uint[kLenNumSymbolsTotal][LZMA_NUM_PB_STATES_MAX] prices;
1880 // uint prices1[LZMA_NUM_PB_STATES_MAX][kLenNumLowSymbols * 2];
1881 // uint prices2[kLenNumSymbolsTotal];
1884 enum GET_PRICE_LEN(string p, string posState, string len) =
1885 `((`~p~`).prices[`~posState~`][cast(usize)(`~len~`) - LZMA_MATCH_LEN_MIN])`;
1888 #define GET_PRICE_LEN(p, posState, len) \
1889 ((p)->prices2[(usize)(len) - 2] + ((p)->prices1[posState][((len) - 2) & (kLenNumLowSymbols * 2 - 1)] & (((len) - 2 - kLenNumLowSymbols * 2) >> 9)))
1892 struct CRangeEnc {
1893 uint range;
1894 uint cache;
1895 ulong low;
1896 ulong cacheSize;
1897 ubyte *buf;
1898 ubyte *bufLim;
1899 ubyte *bufBase;
1900 ISeqOutStream *outStream;
1901 ulong processed;
1902 SRes res;
1906 struct CSaveState {
1907 CLzmaProb *litProbs;
1909 uint state;
1910 uint[LZMA_NUM_REPS] reps;
1912 CLzmaProb[1 << kNumAlignBits] posAlignEncoder;
1913 CLzmaProb[kNumStates] isRep;
1914 CLzmaProb[kNumStates] isRepG0;
1915 CLzmaProb[kNumStates] isRepG1;
1916 CLzmaProb[kNumStates] isRepG2;
1917 CLzmaProb[LZMA_NUM_PB_STATES_MAX][kNumStates] isMatch;
1918 CLzmaProb[LZMA_NUM_PB_STATES_MAX][kNumStates] isRep0Long;
1920 CLzmaProb[1 << kNumPosSlotBits][kNumLenToPosStates] posSlotEncoder;
1921 CLzmaProb[kNumFullDistances] posEncoders;
1923 CLenEnc lenProbs;
1924 CLenEnc repLenProbs;
1928 alias CProbPrice = uint;
1929 alias BoolInt = int;
1932 struct CLzmaEnc {
1933 void *matchFinderObj;
1934 IMatchFinder2 matchFinder;
1936 uint optCur;
1937 uint optEnd;
1939 uint longestMatchLen;
1940 uint numPairs;
1941 uint numAvail;
1943 uint state;
1944 uint numFastBytes;
1945 uint additionalOffset;
1946 uint[LZMA_NUM_REPS] reps;
1947 uint lpMask, pbMask;
1948 CLzmaProb *litProbs;
1949 CRangeEnc rc;
1951 uint backRes;
1953 uint lc, lp, pb;
1954 uint lclp;
1956 BoolInt fastMode;
1957 BoolInt writeEndMark;
1958 BoolInt finished;
1959 BoolInt multiThread;
1960 BoolInt needInit;
1961 // BoolInt _maxMode;
1963 ulong nowPos64;
1965 uint matchPriceCount;
1966 // uint alignPriceCount;
1967 int repLenEncCounter;
1969 uint distTableSize;
1971 uint dictSize;
1972 SRes result;
1974 CMatchFinder matchFinderBase;
1977 // we suppose that we have 8-bytes alignment after CMatchFinder
1979 // LZ thread
1980 CProbPrice[kBitModelTotal >> kNumMoveReducingBits] ProbPrices;
1982 // we want {len , dist} pairs to be 8-bytes aligned in matches array
1983 uint[LZMA_MATCH_LEN_MAX * 2 + 2] matches;
1985 // we want 8-bytes alignment here
1986 uint[kAlignTableSize] alignPrices;
1987 uint[kDistTableSizeMax][kNumLenToPosStates] posSlotPrices;
1988 uint[kNumFullDistances][kNumLenToPosStates] distancesPrices;
1990 CLzmaProb[1 << kNumAlignBits] posAlignEncoder;
1991 CLzmaProb[kNumStates] isRep;
1992 CLzmaProb[kNumStates] isRepG0;
1993 CLzmaProb[kNumStates] isRepG1;
1994 CLzmaProb[kNumStates] isRepG2;
1995 CLzmaProb[LZMA_NUM_PB_STATES_MAX][kNumStates] isMatch;
1996 CLzmaProb[LZMA_NUM_PB_STATES_MAX][kNumStates] isRep0Long;
1997 CLzmaProb[1 << kNumPosSlotBits][kNumLenToPosStates] posSlotEncoder;
1998 CLzmaProb[kNumFullDistances] posEncoders;
2000 CLenEnc lenProbs;
2001 CLenEnc repLenProbs;
2003 //#ifndef LZMA_LOG_BSR
2004 ubyte[1 << kNumLogBits] g_FastPos;
2005 //#endif
2007 CLenPriceEnc lenEnc;
2008 CLenPriceEnc repLenEnc;
2010 COptimal[kNumOpts] opt;
2012 CSaveState saveState;
2014 // BoolInt mf_Failure;
2018 //#define MFB (p.matchFinderBase)
2021 //==========================================================================
2023 // LzmaEnc_SetProps
2025 //==========================================================================
2026 public SRes LzmaEnc_SetProps (CLzmaEncHandle pp, const(CLzmaEncProps)* props2) @nogc {
2027 CLzmaEnc *p = cast(CLzmaEnc *)pp;
2028 CLzmaEncProps props = *props2;
2029 LzmaEncProps_Normalize(&props);
2031 if (props.lc > LZMA_LC_MAX
2032 || props.lp > LZMA_LP_MAX
2033 || props.pb > LZMA_PB_MAX)
2034 return SZ_ERROR_PARAM;
2037 if (props.dictSize > kLzmaMaxHistorySize)
2038 props.dictSize = kLzmaMaxHistorySize;
2040 //#ifndef LZMA_LOG_BSR
2042 const ulong dict64 = props.dictSize;
2043 if (dict64 > (cast(ulong)1 << kDicLogSizeMaxCompress))
2044 return SZ_ERROR_PARAM;
2046 //#endif
2048 p.dictSize = props.dictSize;
2050 uint fb = cast(uint)props.fb;
2051 if (fb < 5)
2052 fb = 5;
2053 if (fb > LZMA_MATCH_LEN_MAX)
2054 fb = LZMA_MATCH_LEN_MAX;
2055 p.numFastBytes = fb;
2057 p.lc = cast(uint)props.lc;
2058 p.lp = cast(uint)props.lp;
2059 p.pb = cast(uint)props.pb;
2060 p.fastMode = (props.algo == 0);
2061 // p->_maxMode = True;
2062 (p.matchFinderBase).btMode = cast(ubyte)(props.btMode ? 1 : 0);
2064 uint numHashBytes = 4;
2065 if (props.btMode)
2067 if (props.numHashBytes < 2) numHashBytes = 2;
2068 else if (props.numHashBytes < 4) numHashBytes = cast(uint)props.numHashBytes;
2070 if (props.numHashBytes >= 5) numHashBytes = 5;
2072 (p.matchFinderBase).numHashBytes = numHashBytes;
2075 (p.matchFinderBase).cutValue = props.mc;
2077 p.writeEndMark = cast(BoolInt)props.writeEndMark;
2079 return SZ_OK;
2083 //==========================================================================
2085 // LzmaEnc_SetDataSize
2087 //==========================================================================
2088 public void LzmaEnc_SetDataSize (CLzmaEncHandle pp, ulong expectedDataSiize) @nogc {
2089 CLzmaEnc *p = cast(CLzmaEnc *)pp;
2090 (p.matchFinderBase).expectedDataSize = expectedDataSiize;
2094 enum kState_Start = 0;
2095 enum kState_LitAfterMatch = 4;
2096 enum kState_LitAfterRep = 5;
2097 enum kState_MatchAfterLit = 7;
2098 enum kState_RepAfterLit = 8;
2100 immutable ubyte[kNumStates] kLiteralNextStates = [0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5];
2101 immutable ubyte[kNumStates] kMatchNextStates = [7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10];
2102 immutable ubyte[kNumStates] kRepNextStates = [8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11];
2103 immutable ubyte[kNumStates] kShortRepNextStates= [9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11];
2105 enum IsLitState(string s) = `((`~s~`) < 7)`;
2106 enum GetLenToPosState2(string len) = `(((`~len~`) < kNumLenToPosStates - 1) ? (`~len~`) : kNumLenToPosStates - 1)`;
2107 enum GetLenToPosState(string len) = `(((`~len~`) < kNumLenToPosStates + 1) ? (`~len~`) - 2 : kNumLenToPosStates - 1)`;
2109 enum kInfinityPrice = (1 << 30);
2111 private void RangeEnc_Construct (CRangeEnc* p) @nogc {
2112 p.outStream = null;
2113 p.bufBase = null;
2116 enum RangeEnc_GetProcessed(string p) = `((`~p~`).processed + cast(usize)((`~p~`).buf - (`~p~`).bufBase) + (`~p~`).cacheSize)`;
2117 enum RangeEnc_GetProcessed_sizet(string p) = `(cast(usize)(`~p~`).processed + cast(usize)((`~p~`).buf - (`~p~`).bufBase) + cast(usize)(`~p~`).cacheSize)`;
2119 enum RC_BUF_SIZE = (1 << 16);
2121 private int RangeEnc_Alloc (CRangeEnc *p, ISzAllocPtr alloc) {
2122 if (!p.bufBase)
2124 p.bufBase = cast(ubyte *)ISzAlloc_Alloc(alloc, RC_BUF_SIZE);
2125 if (!p.bufBase)
2126 return 0;
2127 p.bufLim = p.bufBase + RC_BUF_SIZE;
2129 return 1;
2132 private void RangeEnc_Free (CRangeEnc *p, ISzAllocPtr alloc) {
2133 ISzAlloc_Free(alloc, p.bufBase);
2134 p.bufBase = null;
2138 private void RangeEnc_Init (CRangeEnc* p) @nogc {
2139 /* Stream.Init(); */
2140 p.range = 0xFFFFFFFF;
2141 p.cache = 0;
2142 p.low = 0;
2143 p.cacheSize = 0;
2145 p.buf = p.bufBase;
2147 p.processed = 0;
2148 p.res = SZ_OK;
2151 //MY_NO_INLINE
2152 private void RangeEnc_FlushStream (CRangeEnc* p) {
2153 usize num;
2154 if (p.res != SZ_OK) {
2155 //k8: the following code line was absent, and it looks like
2156 //k8: the encoder could perform OOB writes on some incompressible data.
2157 //k8: most of the time it is harmless, but it's still a bug.
2158 p.buf = p.bufBase;
2159 return;
2161 num = cast(usize)(p.buf - p.bufBase);
2164 if (num != ISeqOutStream_Write(p.outStream, p.bufBase, num))
2165 p.res = SZ_ERROR_WRITE;
2167 if (num && p.outStream.Write(p.outStream, p.bufBase, num) != num) p.res = SZ_ERROR_WRITE;
2169 p.processed += num;
2170 p.buf = p.bufBase;
2173 //MY_NO_INLINE
2174 private void RangeEnc_ShiftLow(CRangeEnc *p)
2176 uint low = cast(uint)p.low;
2177 uint high = cast(uint)(p.low >> 32);
2178 p.low = cast(uint)(low << 8);
2179 if (low < cast(uint)0xFF000000 || high != 0)
2182 ubyte *buf = p.buf;
2183 *buf++ = cast(ubyte)(p.cache + high);
2184 p.cache = cast(uint)(low >> 24);
2185 p.buf = buf;
2186 if (buf == p.bufLim)
2187 RangeEnc_FlushStream(p);
2188 if (p.cacheSize == 0)
2189 return;
2191 high += 0xFF;
2192 for (;;)
2194 ubyte *buf = p.buf;
2195 *buf++ = cast(ubyte)(high);
2196 p.buf = buf;
2197 if (buf == p.bufLim)
2198 RangeEnc_FlushStream(p);
2199 if (--p.cacheSize == 0)
2200 return;
2203 p.cacheSize++;
2206 private void RangeEnc_FlushData(CRangeEnc *p)
2208 int i;
2209 for (i = 0; i < 5; i++)
2210 RangeEnc_ShiftLow(p);
2213 enum RC_NORM(string p) = `if (range < kTopValue) { range <<= 8; RangeEnc_ShiftLow(`~p~`); }`;
2215 enum RC_BIT_PRE(string p, string prob) = `
2216 ttt = *(`~prob~`);
2217 newBound = (range >> kNumBitModelTotalBits) * ttt;
2220 // #define LZMA_ENC_USE_BRANCH
2222 version(LZMA_ENC_USE_BRANCH) {
2224 enum RC_BIT(string p, string prob, string bit) = `{
2225 `~RC_BIT_PRE!(p, prob)~`
2226 if (`~bit~` == 0) { range = newBound; ttt += (kBitModelTotal - ttt) >> kNumMoveBits; }
2227 else { (`~p~`).low += newBound; range -= newBound; ttt -= ttt >> kNumMoveBits; }
2228 *(`~prob~`) = cast(CLzmaProb)ttt;
2229 `~RC_NORM!p~`
2233 } else {
2235 enum RC_BIT(string p, string prob, string bit) = `{
2236 uint mask;
2237 `~RC_BIT_PRE!(p, prob)~`
2238 mask = 0 - cast(uint)`~bit~`;
2239 range &= mask;
2240 mask &= newBound;
2241 range -= mask;
2242 (`~p~`).low += mask;
2243 mask = cast(uint)`~bit~` - 1;
2244 range += newBound & mask;
2245 mask &= (kBitModelTotal - ((1 << kNumMoveBits) - 1));
2246 mask += ((1 << kNumMoveBits) - 1);
2247 ttt += cast(uint)(cast(int)(mask - ttt) >> kNumMoveBits);
2248 *(`~prob~`) = cast(CLzmaProb)ttt;
2249 `~RC_NORM!p~`
2256 enum RC_BIT_0_BASE(string p, string prob) =
2257 `range = newBound; *(`~prob~`) = cast(CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits));`;
2259 enum RC_BIT_1_BASE(string p, string prob) =
2260 `range -= newBound; (`~p~`).low += newBound; *(`~prob~`) = cast(CLzmaProb)(ttt - (ttt >> kNumMoveBits));`;
2262 enum RC_BIT_0(string p, string prob) =
2263 RC_BIT_0_BASE!(p, prob)~
2264 RC_NORM!(p);
2266 enum RC_BIT_1(string p, string prob) =
2267 RC_BIT_1_BASE!(p, prob)~
2268 RC_NORM!(p);
2270 private void RangeEnc_EncodeBit_0(CRangeEnc *p, CLzmaProb *prob)
2272 uint range, ttt, newBound;
2273 range = p.range;
2274 mixin(RC_BIT_PRE!("p", "prob"));
2275 mixin(RC_BIT_0!("p", "prob"));
2276 p.range = range;
2279 private void LitEnc_Encode(CRangeEnc *p, CLzmaProb *probs, uint sym)
2281 uint range = p.range;
2282 sym |= 0x100;
2285 uint ttt, newBound;
2286 // RangeEnc_EncodeBit(p, probs + (sym >> 8), (sym >> 7) & 1);
2287 CLzmaProb *prob = probs + (sym >> 8);
2288 uint bit = (sym >> 7) & 1;
2289 sym <<= 1;
2290 mixin(RC_BIT!("p", "prob", "bit"));
2292 while (sym < 0x10000);
2293 p.range = range;
2296 private void LitEnc_EncodeMatched(CRangeEnc *p, CLzmaProb *probs, uint sym, uint matchByte)
2298 uint range = p.range;
2299 uint offs = 0x100;
2300 sym |= 0x100;
2303 uint ttt, newBound;
2304 CLzmaProb *prob;
2305 uint bit;
2306 matchByte <<= 1;
2307 // RangeEnc_EncodeBit(p, probs + (offs + (matchByte & offs) + (sym >> 8)), (sym >> 7) & 1);
2308 prob = probs + (offs + (matchByte & offs) + (sym >> 8));
2309 bit = (sym >> 7) & 1;
2310 sym <<= 1;
2311 offs &= ~(matchByte ^ sym);
2312 mixin(RC_BIT!("p", "prob", "bit"));
2314 while (sym < 0x10000);
2315 p.range = range;
2320 private void LzmaEnc_InitPriceTables(CProbPrice *ProbPrices)
2322 uint i;
2323 for (i = 0; i < (kBitModelTotal >> kNumMoveReducingBits); i++)
2325 const uint kCyclesBits = kNumBitPriceShiftBits;
2326 uint w = (i << kNumMoveReducingBits) + (1 << (kNumMoveReducingBits - 1));
2327 uint bitCount = 0;
2328 uint j;
2329 for (j = 0; j < kCyclesBits; j++)
2331 w = w * w;
2332 bitCount <<= 1;
2333 while (w >= (cast(uint)1 << 16))
2335 w >>= 1;
2336 bitCount++;
2339 ProbPrices[i] = cast(CProbPrice)((cast(uint)kNumBitModelTotalBits << kCyclesBits) - 15 - bitCount);
2340 // printf("\n%3d: %5d", i, ProbPrices[i]);
2345 enum GET_PRICE(string prob, string bit) =
2346 `p.ProbPrices[((`~prob~`) ^ cast(uint)(((-cast(int)(`~bit~`))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits]`;
2348 enum GET_PRICEa(string prob, string bit) =
2349 `ProbPrices[((`~prob~`) ^ cast(uint)((-(cast(int)(`~bit~`))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits]`;
2351 enum GET_PRICE_0(string prob) = `p.ProbPrices[(`~prob~`) >> kNumMoveReducingBits]`;
2352 enum GET_PRICE_1(string prob) = `p.ProbPrices[((`~prob~`) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits]`;
2354 enum GET_PRICEa_0(string prob) = `ProbPrices[(`~prob~`) >> kNumMoveReducingBits]`;
2355 enum GET_PRICEa_1(string prob) = `ProbPrices[((`~prob~`) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits]`;
2358 private uint LitEnc_GetPrice(const CLzmaProb *probs, uint sym, const CProbPrice *ProbPrices)
2360 uint price = 0;
2361 sym |= 0x100;
2364 uint bit = sym & 1;
2365 sym >>= 1;
2366 price += mixin(GET_PRICEa!("probs[sym]", "bit"));
2368 while (sym >= 2);
2369 return price;
2373 private uint LitEnc_Matched_GetPrice(const CLzmaProb *probs, uint sym, uint matchByte, const CProbPrice *ProbPrices)
2375 uint price = 0;
2376 uint offs = 0x100;
2377 sym |= 0x100;
2380 matchByte <<= 1;
2381 price += mixin(GET_PRICEa!("probs[offs + (matchByte & offs) + (sym >> 8)]", "(sym >> 7) & 1"));
2382 sym <<= 1;
2383 offs &= ~(matchByte ^ sym);
2385 while (sym < 0x10000);
2386 return price;
2390 private void RcTree_ReverseEncode(CRangeEnc *rc, CLzmaProb *probs, uint numBits, uint sym)
2392 uint range = rc.range;
2393 uint m = 1;
2396 uint ttt, newBound;
2397 uint bit = sym & 1;
2398 // RangeEnc_EncodeBit(rc, probs + m, bit);
2399 sym >>= 1;
2400 mixin(RC_BIT!("rc", "probs + m", "bit"));
2401 m = (m << 1) | bit;
2403 while (--numBits);
2404 rc.range = range;
2409 private void LenEnc_Init (CLenEnc* p) @nogc {
2410 uint i;
2411 for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << (kLenNumLowBits + 1)); i++)
2412 p.low[i] = kProbInitValue;
2413 for (i = 0; i < kLenNumHighSymbols; i++)
2414 p.high[i] = kProbInitValue;
2417 private void LenEnc_Encode(CLenEnc *p, CRangeEnc *rc, uint sym, uint posState)
2419 uint range, ttt, newBound;
2420 CLzmaProb *probs = p.low.ptr;
2421 range = rc.range;
2422 mixin(RC_BIT_PRE!("rc", "probs"));
2423 if (sym >= kLenNumLowSymbols)
2425 mixin(RC_BIT_1!("rc", "probs"));
2426 probs += kLenNumLowSymbols;
2427 mixin(RC_BIT_PRE!("rc", "probs"));
2428 if (sym >= kLenNumLowSymbols * 2)
2430 mixin(RC_BIT_1!("rc", "probs"));
2431 rc.range = range;
2432 // RcTree_Encode(rc, p->high, kLenNumHighBits, sym - kLenNumLowSymbols * 2);
2433 LitEnc_Encode(rc, p.high.ptr, sym - kLenNumLowSymbols * 2);
2434 return;
2436 sym -= kLenNumLowSymbols;
2439 // RcTree_Encode(rc, probs + (posState << kLenNumLowBits), kLenNumLowBits, sym);
2441 uint m;
2442 uint bit;
2443 mixin(RC_BIT_0!("rc", "probs"));
2444 probs += (posState << (1 + kLenNumLowBits));
2445 bit = (sym >> 2) ; mixin(RC_BIT!("rc", "probs + 1", "bit")); m = (1 << 1) + bit;
2446 bit = (sym >> 1) & 1; mixin(RC_BIT!("rc", "probs + m", "bit")); m = (m << 1) + bit;
2447 bit = sym & 1; mixin(RC_BIT!("rc", "probs + m", "bit"));
2448 rc.range = range;
2452 private void SetPrices_3 (const(CLzmaProb)* probs, uint startPrice, uint* prices, const(CProbPrice)* ProbPrices) @nogc {
2453 uint i;
2454 for (i = 0; i < 8; i += 2)
2456 uint price = startPrice;
2457 uint prob;
2458 price += mixin(GET_PRICEa!("probs[1 ]", "(i >> 2)"));
2459 price += mixin(GET_PRICEa!("probs[2 + (i >> 2)]", "(i >> 1) & 1"));
2460 prob = probs[4 + (i >> 1)];
2461 prices[i ] = price + mixin(GET_PRICEa_0!"prob");
2462 prices[i + 1] = price + mixin(GET_PRICEa_1!"prob");
2467 //MY_NO_INLINE
2468 private void LenPriceEnc_UpdateTables(
2469 CLenPriceEnc *p,
2470 uint numPosStates,
2471 const(CLenEnc)* enc,
2472 const(CProbPrice)* ProbPrices)
2474 uint b;
2477 uint prob = enc.low[0];
2478 uint a, c;
2479 uint posState;
2480 b = mixin(GET_PRICEa_1!"prob");
2481 a = mixin(GET_PRICEa_0!"prob");
2482 c = b + mixin(GET_PRICEa_0!"enc.low[kLenNumLowSymbols]");
2483 for (posState = 0; posState < numPosStates; posState++)
2485 uint *prices = p.prices[posState].ptr;
2486 const(CLzmaProb)* probs = enc.low.ptr + (posState << (1 + kLenNumLowBits));
2487 SetPrices_3(probs, a, prices, ProbPrices);
2488 SetPrices_3(probs + kLenNumLowSymbols, c, prices + kLenNumLowSymbols, ProbPrices);
2494 uint i;
2495 uint b;
2496 a = GET_PRICEa_0(enc->low[0]);
2497 for (i = 0; i < kLenNumLowSymbols; i++)
2498 p->prices2[i] = a;
2499 a = GET_PRICEa_1(enc->low[0]);
2500 b = a + GET_PRICEa_0(enc->low[kLenNumLowSymbols]);
2501 for (i = kLenNumLowSymbols; i < kLenNumLowSymbols * 2; i++)
2502 p->prices2[i] = b;
2503 a += GET_PRICEa_1(enc->low[kLenNumLowSymbols]);
2507 // p->counter = numSymbols;
2508 // p->counter = 64;
2511 uint i = p.tableSize;
2513 if (i > kLenNumLowSymbols * 2)
2515 const(CLzmaProb)* probs = enc.high.ptr;
2516 uint *prices = p.prices[0].ptr + kLenNumLowSymbols * 2;
2517 i -= kLenNumLowSymbols * 2 - 1;
2518 i >>= 1;
2519 b += mixin(GET_PRICEa_1!"enc.low[kLenNumLowSymbols]");
2523 p->prices2[i] = a +
2524 // RcTree_GetPrice(enc->high, kLenNumHighBits, i - kLenNumLowSymbols * 2, ProbPrices);
2525 LitEnc_GetPrice(probs, i - kLenNumLowSymbols * 2, ProbPrices);
2527 // uint price = a + RcTree_GetPrice(probs, kLenNumHighBits - 1, sym, ProbPrices);
2528 uint sym = --i + (1 << (kLenNumHighBits - 1));
2529 uint price = b;
2532 uint bit = sym & 1;
2533 sym >>= 1;
2534 price += mixin(GET_PRICEa!("probs[sym]", "bit"));
2536 while (sym >= 2);
2539 uint prob = probs[cast(usize)i + (1 << (kLenNumHighBits - 1))];
2540 prices[cast(usize)i * 2 ] = price + mixin(GET_PRICEa_0!"prob");
2541 prices[cast(usize)i * 2 + 1] = price + mixin(GET_PRICEa_1!"prob");
2544 while (i);
2547 import core.stdc.string : memcpy;
2548 uint posState;
2549 usize num = (p.tableSize - kLenNumLowSymbols * 2) * (p.prices[0][0]).sizeof;
2550 for (posState = 1; posState < numPosStates; posState++)
2551 memcpy(p.prices[posState].ptr + kLenNumLowSymbols * 2, p.prices[0].ptr + kLenNumLowSymbols * 2, num);
2558 #ifdef SHOW_STAT
2559 g_STAT_OFFSET += num;
2560 printf("\n MovePos %u", num);
2561 #endif
2564 enum MOVE_POS1(string p, string num) = `{
2565 `~p~`.additionalOffset += (`~num~`);
2566 `~p~`.matchFinder.Skip(`~p~`.matchFinderObj, cast(uint)(`~num~`)); }
2570 private uint ReadMatchDistances(CLzmaEnc *p, uint *numPairsRes)
2572 uint numPairs;
2574 p.additionalOffset++;
2575 p.numAvail = p.matchFinder.GetNumAvailableBytes(p.matchFinderObj);
2577 const uint *d = p.matchFinder.GetMatches(p.matchFinderObj, p.matches.ptr);
2578 // if (!d) { p->mf_Failure = True; *numPairsRes = 0; return 0; }
2579 numPairs = cast(uint)(d - p.matches.ptr);
2581 *numPairsRes = numPairs;
2584 #ifdef SHOW_STAT
2585 printf("\n i = %u numPairs = %u ", g_STAT_OFFSET, numPairs / 2);
2586 g_STAT_OFFSET++;
2588 uint i;
2589 for (i = 0; i < numPairs; i += 2)
2590 printf("%2u %6u | ", p.matches[i], p.matches[i + 1]);
2592 #endif
2595 if (numPairs == 0)
2596 return 0;
2598 const uint len = p.matches[cast(usize)numPairs - 2];
2599 if (len != p.numFastBytes)
2600 return len;
2602 uint numAvail = p.numAvail;
2603 if (numAvail > LZMA_MATCH_LEN_MAX)
2604 numAvail = LZMA_MATCH_LEN_MAX;
2606 const(ubyte)* p1 = p.matchFinder.GetPointerToCurrentPos(p.matchFinderObj) - 1;
2607 const(ubyte)* p2 = p1 + len;
2608 const ptrdiff_t dif = cast(ptrdiff_t)-1 - cast(ptrdiff_t)p.matches[cast(usize)numPairs - 1];
2609 const(ubyte)* lim = p1 + numAvail;
2610 for (; p2 != lim && *p2 == p2[dif]; p2++)
2612 return cast(uint)(p2 - p1);
2618 enum MARK_LIT = (cast(uint)cast(int)-1);
2620 enum MakeAs_Lit(string p) = `{ (`~p~`).dist = MARK_LIT; (`~p~`).extra = 0; }`;
2621 enum MakeAs_ShortRep(string p) = `{ (`~p~`).dist = 0; (`~p~`).extra = 0; }`;
2622 enum IsShortRep(string p) = `((`~p~`).dist == 0)`;
2625 enum GetPrice_ShortRep(string p, string state, string posState) =
2626 `( `~GET_PRICE_0!(p~`.isRepG0[`~state~`]`)~` + `~GET_PRICE_0!(p~`.isRep0Long[`~state~`][`~posState~`]`)~`)`;
2628 enum GetPrice_Rep_0(string p, string state, string posState) = `(
2629 `~GET_PRICE_1!(p~`.isMatch[`~state~`][`~posState~`]`)~`
2630 + `~GET_PRICE_1!(p~`.isRep0Long[`~state~`][`~posState~`]`)~`)
2631 + `~GET_PRICE_1!(p~`.isRep[`~state~`]`)~`
2632 + `~GET_PRICE_0!(p~`.isRepG0[`~state~`]`);
2634 //MY_FORCE_INLINE
2635 private uint GetPrice_PureRep(const(CLzmaEnc)* p, uint repIndex, usize state, usize posState)
2637 uint price;
2638 uint prob = p.isRepG0[state];
2639 if (repIndex == 0)
2641 price = mixin(GET_PRICE_0!"prob");
2642 price += mixin(GET_PRICE_1!"p.isRep0Long[state][posState]");
2644 else
2646 price = mixin(GET_PRICE_1!"prob");
2647 prob = p.isRepG1[state];
2648 if (repIndex == 1)
2649 price += mixin(GET_PRICE_0!"prob");
2650 else
2652 price += mixin(GET_PRICE_1!"prob");
2653 price += mixin(GET_PRICE!("p.isRepG2[state]", "repIndex - 2"));
2656 return price;
2660 private uint Backward(CLzmaEnc *p, uint cur)
2662 uint wr = cur + 1;
2663 p.optEnd = wr;
2665 for (;;)
2667 uint dist = p.opt[cur].dist;
2668 uint len = cast(uint)p.opt[cur].len;
2669 uint extra = cast(uint)p.opt[cur].extra;
2670 cur -= len;
2672 if (extra)
2674 wr--;
2675 p.opt[wr].len = cast(uint)len;
2676 cur -= extra;
2677 len = extra;
2678 if (extra == 1)
2680 p.opt[wr].dist = dist;
2681 dist = MARK_LIT;
2683 else
2685 p.opt[wr].dist = 0;
2686 len--;
2687 wr--;
2688 p.opt[wr].dist = MARK_LIT;
2689 p.opt[wr].len = 1;
2693 if (cur == 0)
2695 p.backRes = dist;
2696 p.optCur = wr;
2697 return len;
2700 wr--;
2701 p.opt[wr].dist = dist;
2702 p.opt[wr].len = cast(uint)len;
2708 enum LIT_PROBS(string pos, string prevByte) =
2709 `(p.litProbs + cast(uint)3 * (((((`~pos~`) << 8) + (`~prevByte~`)) & p.lpMask) << p.lc))`;
2712 private uint GetOptimum(CLzmaEnc *p, uint position)
2714 uint last, cur;
2715 uint[LZMA_NUM_REPS] reps;
2716 uint[LZMA_NUM_REPS] repLens;
2717 uint *matches;
2720 uint numAvail;
2721 uint numPairs, mainLen, repMaxIndex, i, posState;
2722 uint matchPrice, repMatchPrice;
2723 const(ubyte)* data;
2724 ubyte curByte, matchByte;
2726 p.optCur = p.optEnd = 0;
2728 if (p.additionalOffset == 0)
2729 mainLen = ReadMatchDistances(p, &numPairs);
2730 else
2732 mainLen = p.longestMatchLen;
2733 numPairs = p.numPairs;
2736 numAvail = p.numAvail;
2737 if (numAvail < 2)
2739 p.backRes = MARK_LIT;
2740 return 1;
2742 if (numAvail > LZMA_MATCH_LEN_MAX)
2743 numAvail = LZMA_MATCH_LEN_MAX;
2745 data = p.matchFinder.GetPointerToCurrentPos(p.matchFinderObj) - 1;
2746 repMaxIndex = 0;
2748 for (i = 0; i < LZMA_NUM_REPS; i++)
2750 uint len;
2751 const(ubyte)* data2;
2752 reps[i] = p.reps[i];
2753 data2 = data - reps[i];
2754 if (data[0] != data2[0] || data[1] != data2[1])
2756 repLens[i] = 0;
2757 continue;
2759 for (len = 2; len < numAvail && data[len] == data2[len]; len++)
2761 repLens[i] = len;
2762 if (len > repLens[repMaxIndex])
2763 repMaxIndex = i;
2764 if (len == LZMA_MATCH_LEN_MAX) // 21.03 : optimization
2765 break;
2768 if (repLens[repMaxIndex] >= p.numFastBytes)
2770 uint len;
2771 p.backRes = cast(uint)repMaxIndex;
2772 len = repLens[repMaxIndex];
2773 mixin(MOVE_POS1!("p", "len - 1"));
2774 return len;
2777 matches = p.matches.ptr;
2778 //!#define MATCHES matches
2779 // #define MATCHES p->matches
2781 if (mainLen >= p.numFastBytes)
2783 p.backRes = p.matches[cast(usize)numPairs - 1] + LZMA_NUM_REPS;
2784 mixin(MOVE_POS1!("p", "mainLen - 1"));
2785 return mainLen;
2788 curByte = *data;
2789 matchByte = *(data - reps[0]);
2791 last = repLens[repMaxIndex];
2792 if (last <= mainLen)
2793 last = mainLen;
2795 if (last < 2 && curByte != matchByte)
2797 p.backRes = MARK_LIT;
2798 return 1;
2801 p.opt[0].state = cast(CState)p.state;
2803 posState = (position & p.pbMask);
2806 const(CLzmaProb)* probs = mixin(LIT_PROBS!("position", "*(data - 1)"));
2807 p.opt[1].price = mixin(GET_PRICE_0!"p.isMatch[p.state][posState]") +
2808 (!mixin(IsLitState!"p.state") ?
2809 LitEnc_Matched_GetPrice(probs, curByte, matchByte, p.ProbPrices.ptr) :
2810 LitEnc_GetPrice(probs, curByte, p.ProbPrices.ptr));
2813 mixin(MakeAs_Lit!"&p.opt[1]");
2815 matchPrice = mixin(GET_PRICE_1!"p.isMatch[p.state][posState]");
2816 repMatchPrice = matchPrice + mixin(GET_PRICE_1!"p.isRep[p.state]");
2818 // 18.06
2819 if (matchByte == curByte && repLens[0] == 0)
2821 uint shortRepPrice = repMatchPrice + mixin(GetPrice_ShortRep!("p", "p.state", "posState"));
2822 if (shortRepPrice < p.opt[1].price)
2824 p.opt[1].price = shortRepPrice;
2825 mixin(MakeAs_ShortRep!"&p.opt[1]");
2827 if (last < 2)
2829 p.backRes = p.opt[1].dist;
2830 return 1;
2834 p.opt[1].len = 1;
2836 p.opt[0].reps[0] = reps[0];
2837 p.opt[0].reps[1] = reps[1];
2838 p.opt[0].reps[2] = reps[2];
2839 p.opt[0].reps[3] = reps[3];
2841 // ---------- REP ----------
2843 for (i = 0; i < LZMA_NUM_REPS; i++)
2845 uint repLen = repLens[i];
2846 uint price;
2847 if (repLen < 2)
2848 continue;
2849 price = repMatchPrice + GetPrice_PureRep(p, i, p.state, posState);
2852 uint price2 = price + mixin(GET_PRICE_LEN!("&p.repLenEnc", "posState", "repLen"));
2853 COptimal *opt = &p.opt[repLen];
2854 if (price2 < opt.price)
2856 opt.price = price2;
2857 opt.len = cast(uint)repLen;
2858 opt.dist = cast(uint)i;
2859 opt.extra = 0;
2862 while (--repLen >= 2);
2866 // ---------- MATCH ----------
2868 uint len = repLens[0] + 1;
2869 if (len <= mainLen)
2871 uint offs = 0;
2872 uint normalMatchPrice = matchPrice + mixin(GET_PRICE_0!"p.isRep[p.state]");
2874 if (len < 2)
2875 len = 2;
2876 else
2877 while (len > p.matches[offs])
2878 offs += 2;
2880 for (; ; len++)
2882 COptimal *opt;
2883 uint dist = p.matches[cast(usize)offs + 1];
2884 uint price = normalMatchPrice + mixin(GET_PRICE_LEN!("&p.lenEnc", "posState", "len"));
2885 uint lenToPosState = mixin(GetLenToPosState!"len");
2887 if (dist < kNumFullDistances)
2888 price += p.distancesPrices[lenToPosState][dist & (kNumFullDistances - 1)];
2889 else
2891 uint slot;
2892 mixin(GetPosSlot2!("dist", "slot"));
2893 price += p.alignPrices[dist & kAlignMask];
2894 price += p.posSlotPrices[lenToPosState][slot];
2897 opt = &p.opt[len];
2899 if (price < opt.price)
2901 opt.price = price;
2902 opt.len = cast(uint)len;
2903 opt.dist = dist + LZMA_NUM_REPS;
2904 opt.extra = 0;
2907 if (len == p.matches[offs])
2909 offs += 2;
2910 if (offs == numPairs)
2911 break;
2918 cur = 0;
2921 #ifdef SHOW_STAT2
2922 /* if (position >= 0) */
2924 uint i;
2925 printf("\n pos = %4X", position);
2926 for (i = cur; i <= last; i++)
2927 printf("\nprice[%4X] = %u", position - cur + i, p.opt[i].price);
2929 #endif
2935 // ---------- Optimal Parsing ----------
2937 for (;;)
2939 uint numAvail;
2940 uint numAvailFull;
2941 uint newLen, numPairs, prev, state, posState, startLen;
2942 uint litPrice, matchPrice, repMatchPrice;
2943 BoolInt nextIsLit;
2944 ubyte curByte, matchByte;
2945 const(ubyte)* data;
2946 COptimal *curOpt;
2947 COptimal *nextOpt;
2949 if (++cur == last)
2950 break;
2952 // 18.06
2953 if (cur >= kNumOpts - 64)
2955 uint j, best;
2956 uint price = p.opt[cur].price;
2957 best = cur;
2958 for (j = cur + 1; j <= last; j++)
2960 uint price2 = p.opt[j].price;
2961 if (price >= price2)
2963 price = price2;
2964 best = j;
2968 uint delta = best - cur;
2969 if (delta != 0)
2971 mixin(MOVE_POS1!("p", "delta"));
2974 cur = best;
2975 break;
2978 newLen = ReadMatchDistances(p, &numPairs);
2980 if (newLen >= p.numFastBytes)
2982 p.numPairs = numPairs;
2983 p.longestMatchLen = newLen;
2984 break;
2987 curOpt = &p.opt[cur];
2989 position++;
2991 // we need that check here, if skip_items in p->opt are possible
2993 if (curOpt->price >= kInfinityPrice)
2994 continue;
2997 prev = cur - curOpt.len;
2999 if (curOpt.len == 1)
3001 state = cast(uint)p.opt[prev].state;
3002 if (mixin(IsShortRep!"curOpt"))
3003 state = kShortRepNextStates[state];
3004 else
3005 state = kLiteralNextStates[state];
3007 else
3009 const(COptimal)* prevOpt;
3010 uint b0;
3011 uint dist = curOpt.dist;
3013 if (curOpt.extra)
3015 prev -= cast(uint)curOpt.extra;
3016 state = kState_RepAfterLit;
3017 if (curOpt.extra == 1)
3018 state = (dist < LZMA_NUM_REPS ? kState_RepAfterLit : kState_MatchAfterLit);
3020 else
3022 state = cast(uint)p.opt[prev].state;
3023 if (dist < LZMA_NUM_REPS)
3024 state = kRepNextStates[state];
3025 else
3026 state = kMatchNextStates[state];
3029 prevOpt = &p.opt[prev];
3030 b0 = prevOpt.reps[0];
3032 if (dist < LZMA_NUM_REPS)
3034 if (dist == 0)
3036 reps[0] = b0;
3037 reps[1] = prevOpt.reps[1];
3038 reps[2] = prevOpt.reps[2];
3039 reps[3] = prevOpt.reps[3];
3041 else
3043 reps[1] = b0;
3044 b0 = prevOpt.reps[1];
3045 if (dist == 1)
3047 reps[0] = b0;
3048 reps[2] = prevOpt.reps[2];
3049 reps[3] = prevOpt.reps[3];
3051 else
3053 reps[2] = b0;
3054 reps[0] = prevOpt.reps[dist];
3055 reps[3] = prevOpt.reps[dist ^ 1];
3059 else
3061 reps[0] = (dist - LZMA_NUM_REPS + 1);
3062 reps[1] = b0;
3063 reps[2] = prevOpt.reps[1];
3064 reps[3] = prevOpt.reps[2];
3068 curOpt.state = cast(CState)state;
3069 curOpt.reps[0] = reps[0];
3070 curOpt.reps[1] = reps[1];
3071 curOpt.reps[2] = reps[2];
3072 curOpt.reps[3] = reps[3];
3074 data = p.matchFinder.GetPointerToCurrentPos(p.matchFinderObj) - 1;
3075 curByte = *data;
3076 matchByte = *(data - reps[0]);
3078 posState = (position & p.pbMask);
3081 The order of Price checks:
3082 < LIT
3083 <= SHORT_REP
3084 < LIT : REP_0
3085 < REP [ : LIT : REP_0 ]
3086 < MATCH [ : LIT : REP_0 ]
3090 uint curPrice = curOpt.price;
3091 uint prob = p.isMatch[state][posState];
3092 matchPrice = curPrice + mixin(GET_PRICE_1!"prob");
3093 litPrice = curPrice + mixin(GET_PRICE_0!"prob");
3096 nextOpt = &p.opt[cast(usize)cur + 1];
3097 nextIsLit = 0/*False*/;
3099 // here we can allow skip_items in p->opt, if we don't check (nextOpt->price < kInfinityPrice)
3100 // 18.new.06
3101 if ((nextOpt.price < kInfinityPrice
3102 // && !mixin(IsLitState!"state")
3103 && matchByte == curByte)
3104 || litPrice > nextOpt.price
3106 litPrice = 0;
3107 else
3109 const(CLzmaProb)* probs = mixin(LIT_PROBS!("position", "*(data - 1)"));
3110 litPrice += (!mixin(IsLitState!"state") ?
3111 LitEnc_Matched_GetPrice(probs, curByte, matchByte, p.ProbPrices.ptr) :
3112 LitEnc_GetPrice(probs, curByte, p.ProbPrices.ptr));
3114 if (litPrice < nextOpt.price)
3116 nextOpt.price = litPrice;
3117 nextOpt.len = 1;
3118 mixin(MakeAs_Lit!"nextOpt");
3119 nextIsLit = 1/*True*/;
3123 repMatchPrice = matchPrice + mixin(GET_PRICE_1!"p.isRep[state]");
3125 numAvailFull = p.numAvail;
3127 uint temp = kNumOpts - 1 - cur;
3128 if (numAvailFull > temp)
3129 numAvailFull = cast(uint)temp;
3132 // 18.06
3133 // ---------- SHORT_REP ----------
3134 if (mixin(IsLitState!"state")) // 18.new
3135 if (matchByte == curByte)
3136 if (repMatchPrice < nextOpt.price) // 18.new
3137 // if (numAvailFull < 2 || data[1] != *(data - reps[0] + 1))
3138 if (
3139 // nextOpt->price >= kInfinityPrice ||
3140 nextOpt.len < 2 // we can check nextOpt->len, if skip items are not allowed in p->opt
3141 || (nextOpt.dist != 0
3142 // && nextOpt->extra <= 1 // 17.old
3146 uint shortRepPrice = repMatchPrice + mixin(GetPrice_ShortRep!("p", "state", "posState"));
3147 // if (shortRepPrice <= nextOpt->price) // 17.old
3148 if (shortRepPrice < nextOpt.price) // 18.new
3150 nextOpt.price = shortRepPrice;
3151 nextOpt.len = 1;
3152 mixin(MakeAs_ShortRep!"nextOpt");
3153 nextIsLit = 0/*False*/;
3157 if (numAvailFull < 2)
3158 continue;
3159 numAvail = (numAvailFull <= p.numFastBytes ? numAvailFull : p.numFastBytes);
3161 // numAvail <= p->numFastBytes
3163 // ---------- LIT : REP_0 ----------
3165 if (!nextIsLit
3166 && litPrice != 0 // 18.new
3167 && matchByte != curByte
3168 && numAvailFull > 2)
3170 const ubyte *data2 = data - reps[0];
3171 if (data[1] == data2[1] && data[2] == data2[2])
3173 uint len;
3174 uint limit = p.numFastBytes + 1;
3175 if (limit > numAvailFull)
3176 limit = numAvailFull;
3177 for (len = 3; len < limit && data[len] == data2[len]; len++)
3181 uint state2 = kLiteralNextStates[state];
3182 uint posState2 = (position + 1) & p.pbMask;
3183 uint price = litPrice + mixin(GetPrice_Rep_0!("p", "state2", "posState2"));
3185 uint offset = cur + len;
3187 if (last < offset)
3188 last = offset;
3190 // do
3192 uint price2;
3193 COptimal *opt;
3194 len--;
3195 // price2 = price + GetPrice_Len_Rep_0(p, len, state2, posState2);
3196 price2 = price + mixin(GET_PRICE_LEN!("&p.repLenEnc", "posState2", "len"));
3198 opt = &p.opt[offset];
3199 // offset--;
3200 if (price2 < opt.price)
3202 opt.price = price2;
3203 opt.len = cast(uint)len;
3204 opt.dist = 0;
3205 opt.extra = 1;
3208 // while (len >= 3);
3214 startLen = 2; /* speed optimization */
3217 // ---------- REP ----------
3218 uint repIndex = 0; // 17.old
3219 // uint repIndex = mixin(IsLitState!"state") ? 0 : 1; // 18.notused
3220 for (; repIndex < LZMA_NUM_REPS; repIndex++)
3222 uint len;
3223 uint price;
3224 const ubyte *data2 = data - reps[repIndex];
3225 if (data[0] != data2[0] || data[1] != data2[1])
3226 continue;
3228 for (len = 2; len < numAvail && data[len] == data2[len]; len++)
3231 // if (len < startLen) continue; // 18.new: speed optimization
3234 uint offset = cur + len;
3235 if (last < offset)
3236 last = offset;
3239 uint len2 = len;
3240 price = repMatchPrice + GetPrice_PureRep(p, repIndex, state, posState);
3243 uint price2 = price + mixin(GET_PRICE_LEN!("&p.repLenEnc", "posState", "len2"));
3244 COptimal *opt = &p.opt[cur + len2];
3245 if (price2 < opt.price)
3247 opt.price = price2;
3248 opt.len = cast(uint)len2;
3249 opt.dist = cast(uint)repIndex;
3250 opt.extra = 0;
3253 while (--len2 >= 2);
3256 if (repIndex == 0) startLen = len + 1; // 17.old
3257 // startLen = len + 1; // 18.new
3259 /* if (_maxMode) */
3261 // ---------- REP : LIT : REP_0 ----------
3262 // numFastBytes + 1 + numFastBytes
3264 uint len2 = len + 1;
3265 uint limit = len2 + p.numFastBytes;
3266 if (limit > numAvailFull)
3267 limit = numAvailFull;
3269 len2 += 2;
3270 if (len2 <= limit)
3271 if (data[len2 - 2] == data2[len2 - 2])
3272 if (data[len2 - 1] == data2[len2 - 1])
3274 uint state2 = kRepNextStates[state];
3275 uint posState2 = (position + len) & p.pbMask;
3276 price += mixin(GET_PRICE_LEN!("&p.repLenEnc", "posState", "len"))
3277 + mixin(GET_PRICE_0!"p.isMatch[state2][posState2]")
3278 + LitEnc_Matched_GetPrice(mixin(LIT_PROBS!("position + len", "data[cast(usize)len - 1]")),
3279 data[len], data2[len], p.ProbPrices.ptr);
3281 // state2 = kLiteralNextStates[state2];
3282 state2 = kState_LitAfterRep;
3283 posState2 = (posState2 + 1) & p.pbMask;
3286 price += mixin(GetPrice_Rep_0!("p", "state2", "posState2"));
3288 for (; len2 < limit && data[len2] == data2[len2]; len2++)
3291 len2 -= len;
3292 // if (len2 >= 3)
3295 uint offset = cur + len + len2;
3297 if (last < offset)
3298 last = offset;
3299 // do
3301 uint price2;
3302 COptimal *opt;
3303 len2--;
3304 // price2 = price + GetPrice_Len_Rep_0(p, len2, state2, posState2);
3305 price2 = price + mixin(GET_PRICE_LEN!("&p.repLenEnc", "posState2", "len2"));
3307 opt = &p.opt[offset];
3308 // offset--;
3309 if (price2 < opt.price)
3311 opt.price = price2;
3312 opt.len = cast(uint)len2;
3313 opt.extra = cast(CExtra)(len + 1);
3314 opt.dist = cast(uint)repIndex;
3317 // while (len2 >= 3);
3326 // ---------- MATCH ----------
3327 /* for (uint len = 2; len <= newLen; len++) */
3328 if (newLen > numAvail)
3330 newLen = numAvail;
3331 for (numPairs = 0; newLen > p.matches[numPairs]; numPairs += 2) {}
3332 p.matches[numPairs] = cast(uint)newLen;
3333 numPairs += 2;
3336 // startLen = 2; /* speed optimization */
3338 if (newLen >= startLen)
3340 uint normalMatchPrice = matchPrice + mixin(GET_PRICE_0!"p.isRep[state]");
3341 uint dist;
3342 uint offs, posSlot, len;
3345 uint offset = cur + newLen;
3346 if (last < offset)
3347 last = offset;
3350 offs = 0;
3351 while (startLen > p.matches[offs])
3352 offs += 2;
3353 dist = p.matches[cast(usize)offs + 1];
3355 // if (dist >= kNumFullDistances)
3356 mixin(GetPosSlot2!("dist", "posSlot"));
3358 for (len = /*2*/ startLen; ; len++)
3360 uint price = normalMatchPrice + mixin(GET_PRICE_LEN!("&p.lenEnc", "posState", "len"));
3362 COptimal *opt;
3363 uint lenNorm = len - 2;
3364 lenNorm = mixin(GetLenToPosState2!"lenNorm");
3365 if (dist < kNumFullDistances)
3366 price += p.distancesPrices[lenNorm][dist & (kNumFullDistances - 1)];
3367 else
3368 price += p.posSlotPrices[lenNorm][posSlot] + p.alignPrices[dist & kAlignMask];
3370 opt = &p.opt[cur + len];
3371 if (price < opt.price)
3373 opt.price = price;
3374 opt.len = cast(uint)len;
3375 opt.dist = dist + LZMA_NUM_REPS;
3376 opt.extra = 0;
3380 if (len == p.matches[offs])
3382 // if (p->_maxMode) {
3383 // MATCH : LIT : REP_0
3385 const ubyte *data2 = data - dist - 1;
3386 uint len2 = len + 1;
3387 uint limit = len2 + p.numFastBytes;
3388 if (limit > numAvailFull)
3389 limit = numAvailFull;
3391 len2 += 2;
3392 if (len2 <= limit)
3393 if (data[len2 - 2] == data2[len2 - 2])
3394 if (data[len2 - 1] == data2[len2 - 1])
3396 for (; len2 < limit && data[len2] == data2[len2]; len2++)
3399 len2 -= len;
3401 // if (len2 >= 3)
3403 uint state2 = kMatchNextStates[state];
3404 uint posState2 = (position + len) & p.pbMask;
3405 uint offset;
3406 price += mixin(GET_PRICE_0!"p.isMatch[state2][posState2]");
3407 price += LitEnc_Matched_GetPrice(mixin(LIT_PROBS!("position + len", "data[cast(usize)len - 1]")),
3408 data[len], data2[len], p.ProbPrices.ptr);
3410 // state2 = kLiteralNextStates[state2];
3411 state2 = kState_LitAfterMatch;
3413 posState2 = (posState2 + 1) & p.pbMask;
3414 price += mixin(GetPrice_Rep_0!("p", "state2", "posState2"));
3416 offset = cur + len + len2;
3418 if (last < offset)
3419 last = offset;
3420 // do
3422 uint price2;
3423 COptimal *opt;
3424 len2--;
3425 // price2 = price + GetPrice_Len_Rep_0(p, len2, state2, posState2);
3426 price2 = price + mixin(GET_PRICE_LEN!("&p.repLenEnc", "posState2", "len2"));
3427 opt = &p.opt[offset];
3428 // offset--;
3429 if (price2 < opt.price)
3431 opt.price = price2;
3432 opt.len = cast(uint)len2;
3433 opt.extra = cast(CExtra)(len + 1);
3434 opt.dist = dist + LZMA_NUM_REPS;
3437 // while (len2 >= 3);
3442 offs += 2;
3443 if (offs == numPairs)
3444 break;
3445 dist = p.matches[cast(usize)offs + 1];
3446 // if (dist >= kNumFullDistances) {
3447 mixin(GetPosSlot2!("dist", "posSlot"));
3448 // }
3455 p.opt[last].price = kInfinityPrice;
3456 while (--last);
3458 return Backward(p, cur);
3463 enum ChangePair(string smallDist, string bigDist) = `(((`~bigDist~`) >> 7) > (`~smallDist~`))`;
3467 private uint GetOptimumFast(CLzmaEnc *p)
3469 uint numAvail, mainDist;
3470 uint mainLen, numPairs, repIndex, repLen, i;
3471 const(ubyte)* data;
3473 if (p.additionalOffset == 0)
3474 mainLen = ReadMatchDistances(p, &numPairs);
3475 else
3477 mainLen = p.longestMatchLen;
3478 numPairs = p.numPairs;
3481 numAvail = p.numAvail;
3482 p.backRes = MARK_LIT;
3483 if (numAvail < 2)
3484 return 1;
3485 // if (mainLen < 2 && p->state == 0) return 1; // 18.06.notused
3486 if (numAvail > LZMA_MATCH_LEN_MAX)
3487 numAvail = LZMA_MATCH_LEN_MAX;
3488 data = p.matchFinder.GetPointerToCurrentPos(p.matchFinderObj) - 1;
3489 repLen = repIndex = 0;
3491 for (i = 0; i < LZMA_NUM_REPS; i++)
3493 uint len;
3494 const ubyte *data2 = data - p.reps[i];
3495 if (data[0] != data2[0] || data[1] != data2[1])
3496 continue;
3497 for (len = 2; len < numAvail && data[len] == data2[len]; len++)
3499 if (len >= p.numFastBytes)
3501 p.backRes = cast(uint)i;
3502 mixin(MOVE_POS1!("p", "len - 1"));
3503 return len;
3505 if (len > repLen)
3507 repIndex = i;
3508 repLen = len;
3512 if (mainLen >= p.numFastBytes)
3514 p.backRes = p.matches[cast(usize)numPairs - 1] + LZMA_NUM_REPS;
3515 mixin(MOVE_POS1!("p", "mainLen - 1"));
3516 return mainLen;
3519 mainDist = 0; /* for GCC */
3521 if (mainLen >= 2)
3523 mainDist = p.matches[cast(usize)numPairs - 1];
3524 while (numPairs > 2)
3526 uint dist2;
3527 if (mainLen != p.matches[cast(usize)numPairs - 4] + 1)
3528 break;
3529 dist2 = p.matches[cast(usize)numPairs - 3];
3530 if (!mixin(ChangePair!("dist2", "mainDist")))
3531 break;
3532 numPairs -= 2;
3533 mainLen--;
3534 mainDist = dist2;
3536 if (mainLen == 2 && mainDist >= 0x80)
3537 mainLen = 1;
3540 if (repLen >= 2)
3541 if ( repLen + 1 >= mainLen
3542 || (repLen + 2 >= mainLen && mainDist >= (1 << 9))
3543 || (repLen + 3 >= mainLen && mainDist >= (1 << 15)))
3545 p.backRes = cast(uint)repIndex;
3546 mixin(MOVE_POS1!("p", "repLen - 1"));
3547 return repLen;
3550 if (mainLen < 2 || numAvail <= 2)
3551 return 1;
3554 uint len1 = ReadMatchDistances(p, &p.numPairs);
3555 p.longestMatchLen = len1;
3557 if (len1 >= 2)
3559 uint newDist = p.matches[cast(usize)p.numPairs - 1];
3560 if ( (len1 >= mainLen && newDist < mainDist)
3561 || (len1 == mainLen + 1 && !mixin(ChangePair!("mainDist", "newDist")))
3562 || (len1 > mainLen + 1)
3563 || (len1 + 1 >= mainLen && mainLen >= 3 && mixin(ChangePair!("newDist", "mainDist"))))
3564 return 1;
3568 data = p.matchFinder.GetPointerToCurrentPos(p.matchFinderObj) - 1;
3570 for (i = 0; i < LZMA_NUM_REPS; i++)
3572 uint len, limit;
3573 const ubyte *data2 = data - p.reps[i];
3574 if (data[0] != data2[0] || data[1] != data2[1])
3575 continue;
3576 limit = mainLen - 1;
3577 for (len = 2;; len++)
3579 if (len >= limit)
3580 return 1;
3581 if (data[len] != data2[len])
3582 break;
3586 p.backRes = mainDist + LZMA_NUM_REPS;
3587 if (mainLen != 2)
3589 mixin(MOVE_POS1!("p", "mainLen - 2"));
3591 return mainLen;
3597 private void WriteEndMarker(CLzmaEnc *p, uint posState)
3599 uint range;
3600 range = p.rc.range;
3602 uint ttt, newBound;
3603 CLzmaProb *prob = &p.isMatch[p.state][posState];
3604 mixin(RC_BIT_PRE!("&p.rc", "prob"));
3605 mixin(RC_BIT_1!("&p.rc", "prob"));
3606 prob = &p.isRep[p.state];
3607 mixin(RC_BIT_PRE!("&p.rc", "prob"));
3608 mixin(RC_BIT_0!("&p.rc", "prob"));
3610 p.state = kMatchNextStates[p.state];
3612 p.rc.range = range;
3613 LenEnc_Encode(&p.lenProbs, &p.rc, 0, posState);
3614 range = p.rc.range;
3617 // RcTree_Encode_PosSlot(&p->rc, p->posSlotEncoder[0], (1 << kNumPosSlotBits) - 1);
3618 CLzmaProb *probs = p.posSlotEncoder[0].ptr;
3619 uint m = 1;
3622 uint ttt, newBound;
3623 mixin(RC_BIT_PRE!("p", "probs + m"));
3624 mixin(RC_BIT_1!("&p.rc", "probs + m"));
3625 m = (m << 1) + 1;
3627 while (m < (1 << kNumPosSlotBits));
3630 // RangeEnc_EncodeDirectBits(&p->rc, ((uint)1 << (30 - kNumAlignBits)) - 1, 30 - kNumAlignBits); uint range = p->range;
3631 uint numBits = 30 - kNumAlignBits;
3634 range >>= 1;
3635 p.rc.low += range;
3636 mixin(RC_NORM!"&p.rc");
3638 while (--numBits);
3642 // RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, kAlignMask);
3643 CLzmaProb *probs = p.posAlignEncoder.ptr;
3644 uint m = 1;
3647 uint ttt, newBound;
3648 mixin(RC_BIT_PRE!("p", "probs + m"));
3649 mixin(RC_BIT_1!("&p.rc", "probs + m"));
3650 m = (m << 1) + 1;
3652 while (m < kAlignTableSize);
3654 p.rc.range = range;
3658 private SRes CheckErrors(CLzmaEnc *p)
3660 if (p.result != SZ_OK)
3661 return p.result;
3662 if (p.rc.res != SZ_OK)
3663 p.result = SZ_ERROR_WRITE;
3665 if ((p.matchFinderBase).result != SZ_OK)
3666 p.result = SZ_ERROR_READ;
3668 if (p.result != SZ_OK)
3669 p.finished = 1/*True*/;
3670 return p.result;
3674 //MY_NO_INLINE
3675 private SRes Flush(CLzmaEnc *p, uint nowPos)
3677 /* ReleaseMFStream(); */
3678 p.finished = 1/*True*/;
3679 if (p.writeEndMark)
3680 WriteEndMarker(p, nowPos & p.pbMask);
3681 RangeEnc_FlushData(&p.rc);
3682 RangeEnc_FlushStream(&p.rc);
3683 return CheckErrors(p);
3687 //MY_NO_INLINE
3688 private void FillAlignPrices(CLzmaEnc *p)
3690 uint i;
3691 const CProbPrice *ProbPrices = p.ProbPrices.ptr;
3692 const CLzmaProb *probs = p.posAlignEncoder.ptr;
3693 // p->alignPriceCount = 0;
3694 for (i = 0; i < kAlignTableSize / 2; i++)
3696 uint price = 0;
3697 uint sym = i;
3698 uint m = 1;
3699 uint bit;
3700 uint prob;
3701 bit = sym & 1; sym >>= 1; price += mixin(GET_PRICEa!("probs[m]", "bit")); m = (m << 1) + bit;
3702 bit = sym & 1; sym >>= 1; price += mixin(GET_PRICEa!("probs[m]", "bit")); m = (m << 1) + bit;
3703 bit = sym & 1; sym >>= 1; price += mixin(GET_PRICEa!("probs[m]", "bit")); m = (m << 1) + bit;
3704 prob = probs[m];
3705 p.alignPrices[i ] = price + mixin(GET_PRICEa_0!"prob");
3706 p.alignPrices[i + 8] = price + mixin(GET_PRICEa_1!"prob");
3707 // p->alignPrices[i] = RcTree_ReverseGetPrice(p->posAlignEncoder, kNumAlignBits, i, p->ProbPrices);
3712 //MY_NO_INLINE
3713 private void FillDistancesPrices(CLzmaEnc *p)
3715 // int y; for (y = 0; y < 100; y++) {
3717 uint[kNumFullDistances] tempPrices;
3718 uint i, lps;
3720 const CProbPrice *ProbPrices = p.ProbPrices.ptr;
3721 p.matchPriceCount = 0;
3723 for (i = kStartPosModelIndex / 2; i < kNumFullDistances / 2; i++)
3725 uint posSlot = mixin(GetPosSlot1!"i");
3726 uint footerBits = (posSlot >> 1) - 1;
3727 uint base = ((2 | (posSlot & 1)) << footerBits);
3728 const(CLzmaProb)* probs = p.posEncoders.ptr + cast(usize)base * 2;
3729 // tempPrices[i] = RcTree_ReverseGetPrice(p->posEncoders + base, footerBits, i - base, p->ProbPrices);
3730 uint price = 0;
3731 uint m = 1;
3732 uint sym = i;
3733 uint offset = cast(uint)1 << footerBits;
3734 base += i;
3736 if (footerBits)
3739 uint bit = sym & 1;
3740 sym >>= 1;
3741 price += mixin(GET_PRICEa!("probs[m]", "bit"));
3742 m = (m << 1) + bit;
3744 while (--footerBits);
3747 uint prob = probs[m];
3748 tempPrices[base ] = price + mixin(GET_PRICEa_0!"prob");
3749 tempPrices[base + offset] = price + mixin(GET_PRICEa_1!"prob");
3753 for (lps = 0; lps < kNumLenToPosStates; lps++)
3755 uint slot;
3756 uint distTableSize2 = (p.distTableSize + 1) >> 1;
3757 uint *posSlotPrices = p.posSlotPrices[lps].ptr;
3758 const CLzmaProb *probs = p.posSlotEncoder[lps].ptr;
3760 for (slot = 0; slot < distTableSize2; slot++)
3762 // posSlotPrices[slot] = RcTree_GetPrice(encoder, kNumPosSlotBits, slot, p->ProbPrices);
3763 uint price;
3764 uint bit;
3765 uint sym = slot + (1 << (kNumPosSlotBits - 1));
3766 uint prob;
3767 bit = sym & 1; sym >>= 1; price = mixin(GET_PRICEa!("probs[sym]", "bit"));
3768 bit = sym & 1; sym >>= 1; price += mixin(GET_PRICEa!("probs[sym]", "bit"));
3769 bit = sym & 1; sym >>= 1; price += mixin(GET_PRICEa!("probs[sym]", "bit"));
3770 bit = sym & 1; sym >>= 1; price += mixin(GET_PRICEa!("probs[sym]", "bit"));
3771 bit = sym & 1; sym >>= 1; price += mixin(GET_PRICEa!("probs[sym]", "bit"));
3772 prob = probs[cast(usize)slot + (1 << (kNumPosSlotBits - 1))];
3773 posSlotPrices[cast(usize)slot * 2 ] = price + mixin(GET_PRICEa_0!"prob");
3774 posSlotPrices[cast(usize)slot * 2 + 1] = price + mixin(GET_PRICEa_1!"prob");
3778 uint delta = (cast(uint)((kEndPosModelIndex / 2 - 1) - kNumAlignBits) << kNumBitPriceShiftBits);
3779 for (slot = kEndPosModelIndex / 2; slot < distTableSize2; slot++)
3781 posSlotPrices[cast(usize)slot * 2 ] += delta;
3782 posSlotPrices[cast(usize)slot * 2 + 1] += delta;
3783 delta += (cast(uint)1 << kNumBitPriceShiftBits);
3788 uint *dp = p.distancesPrices[lps].ptr;
3790 dp[0] = posSlotPrices[0];
3791 dp[1] = posSlotPrices[1];
3792 dp[2] = posSlotPrices[2];
3793 dp[3] = posSlotPrices[3];
3795 for (i = 4; i < kNumFullDistances; i += 2)
3797 uint slotPrice = posSlotPrices[mixin(GetPosSlot1!"i")];
3798 dp[i ] = slotPrice + tempPrices[i];
3799 dp[i + 1] = slotPrice + tempPrices[i + 1];
3803 // }
3808 private void LzmaEnc_Construct(CLzmaEnc *p)
3810 RangeEnc_Construct(&p.rc);
3811 MatchFinder_Construct(&(p.matchFinderBase));
3814 CLzmaEncProps props;
3815 LzmaEncProps_Init(&props);
3816 LzmaEnc_SetProps(p, &props);
3819 //#ifndef LZMA_LOG_BSR
3820 LzmaEnc_FastPosInit(p.g_FastPos.ptr);
3821 //#endif
3823 LzmaEnc_InitPriceTables(p.ProbPrices.ptr);
3824 p.litProbs = null;
3825 p.saveState.litProbs = null;
3829 //==========================================================================
3831 // LzmaEnc_Create
3833 //==========================================================================
3834 public CLzmaEncHandle LzmaEnc_Create (ISzAllocPtr alloc) {
3835 void *p = ISzAlloc_Alloc(alloc, CLzmaEnc.sizeof);
3836 if (p) LzmaEnc_Construct(cast(CLzmaEnc *)p);
3837 return p;
3841 private void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAllocPtr alloc)
3843 ISzAlloc_Free(alloc, p.litProbs);
3844 ISzAlloc_Free(alloc, p.saveState.litProbs);
3845 p.litProbs = null;
3846 p.saveState.litProbs = null;
3849 private void LzmaEnc_Destruct(CLzmaEnc *p, ISzAllocPtr alloc, ISzAllocPtr allocBig)
3851 MatchFinder_Free(&(p.matchFinderBase), allocBig);
3852 LzmaEnc_FreeLits(p, alloc);
3853 RangeEnc_Free(&p.rc, alloc);
3857 //==========================================================================
3859 // LzmaEnc_Destroy
3861 //==========================================================================
3862 public void LzmaEnc_Destroy (CLzmaEncHandle p, ISzAllocPtr alloc, ISzAllocPtr allocBig) {
3863 if (p !is null) {
3864 LzmaEnc_Destruct(cast(CLzmaEnc *)p, alloc, allocBig);
3865 ISzAlloc_Free(alloc, p);
3870 //MY_NO_INLINE
3871 private SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, uint maxPackSize, uint maxUnpackSize)
3873 uint nowPos32, startPos32;
3874 if (p.needInit)
3876 p.matchFinder.Init(p.matchFinderObj);
3877 p.needInit = 0;
3880 if (p.finished)
3881 return p.result;
3882 int rinres = CheckErrors(p);
3883 if (rinres != 0) return rinres;
3885 nowPos32 = cast(uint)p.nowPos64;
3886 startPos32 = nowPos32;
3888 if (p.nowPos64 == 0)
3890 uint numPairs;
3891 ubyte curByte;
3892 if (p.matchFinder.GetNumAvailableBytes(p.matchFinderObj) == 0)
3893 return Flush(p, nowPos32);
3894 ReadMatchDistances(p, &numPairs);
3895 RangeEnc_EncodeBit_0(&p.rc, &p.isMatch[kState_Start][0]);
3896 // p->state = kLiteralNextStates[p->state];
3897 curByte = *(p.matchFinder.GetPointerToCurrentPos(p.matchFinderObj) - p.additionalOffset);
3898 LitEnc_Encode(&p.rc, p.litProbs, curByte);
3899 p.additionalOffset--;
3900 nowPos32++;
3903 if (p.matchFinder.GetNumAvailableBytes(p.matchFinderObj) != 0)
3905 for (;;)
3907 uint dist;
3908 uint len, posState;
3909 uint range, ttt, newBound;
3910 CLzmaProb *probs;
3912 if (p.fastMode)
3913 len = GetOptimumFast(p);
3914 else
3916 uint oci = p.optCur;
3917 if (p.optEnd == oci)
3918 len = GetOptimum(p, nowPos32);
3919 else
3921 const COptimal *opt = &p.opt[oci];
3922 len = opt.len;
3923 p.backRes = opt.dist;
3924 p.optCur = oci + 1;
3928 posState = cast(uint)nowPos32 & p.pbMask;
3929 range = p.rc.range;
3930 probs = &p.isMatch[p.state][posState];
3932 mixin(RC_BIT_PRE!("&p.rc", "probs"));
3934 dist = p.backRes;
3937 #ifdef SHOW_STAT2
3938 printf("\n pos = %6X, len = %3u pos = %6u", nowPos32, len, dist);
3939 #endif
3942 if (dist == MARK_LIT)
3944 ubyte curByte;
3945 const(ubyte)* data;
3946 uint state;
3948 mixin(RC_BIT_0!("&p.rc", "probs"));
3949 p.rc.range = range;
3950 data = p.matchFinder.GetPointerToCurrentPos(p.matchFinderObj) - p.additionalOffset;
3951 probs = mixin(LIT_PROBS!("nowPos32", "*(data - 1)"));
3952 curByte = *data;
3953 state = p.state;
3954 p.state = kLiteralNextStates[state];
3955 if (mixin(IsLitState!"state"))
3956 LitEnc_Encode(&p.rc, probs, curByte);
3957 else
3958 LitEnc_EncodeMatched(&p.rc, probs, curByte, *(data - p.reps[0]));
3960 else
3962 mixin(RC_BIT_1!("&p.rc", "probs"));
3963 probs = &p.isRep[p.state];
3964 mixin(RC_BIT_PRE!("&p.rc", "probs"));
3966 if (dist < LZMA_NUM_REPS)
3968 mixin(RC_BIT_1!("&p.rc", "probs"));
3969 probs = &p.isRepG0[p.state];
3970 mixin(RC_BIT_PRE!("&p.rc", "probs"));
3971 if (dist == 0)
3973 mixin(RC_BIT_0!("&p.rc", "probs"));
3974 probs = &p.isRep0Long[p.state][posState];
3975 mixin(RC_BIT_PRE!("&p.rc", "probs"));
3976 if (len != 1)
3978 mixin(RC_BIT_1_BASE!("&p.rc", "probs"));
3980 else
3982 mixin(RC_BIT_0_BASE!("&p.rc", "probs"));
3983 p.state = kShortRepNextStates[p.state];
3986 else
3988 mixin(RC_BIT_1!("&p.rc", "probs"));
3989 probs = &p.isRepG1[p.state];
3990 mixin(RC_BIT_PRE!("&p.rc", "probs"));
3991 if (dist == 1)
3993 mixin(RC_BIT_0_BASE!("&p.rc", "probs"));
3994 dist = p.reps[1];
3996 else
3998 mixin(RC_BIT_1!("&p.rc", "probs"));
3999 probs = &p.isRepG2[p.state];
4000 mixin(RC_BIT_PRE!("&p.rc", "probs"));
4001 if (dist == 2)
4003 mixin(RC_BIT_0_BASE!("&p.rc", "probs"));
4004 dist = p.reps[2];
4006 else
4008 mixin(RC_BIT_1_BASE!("&p.rc", "probs"));
4009 dist = p.reps[3];
4010 p.reps[3] = p.reps[2];
4012 p.reps[2] = p.reps[1];
4014 p.reps[1] = p.reps[0];
4015 p.reps[0] = dist;
4018 mixin(RC_NORM!"&p.rc");
4020 p.rc.range = range;
4022 if (len != 1)
4024 LenEnc_Encode(&p.repLenProbs, &p.rc, len - LZMA_MATCH_LEN_MIN, posState);
4025 --p.repLenEncCounter;
4026 p.state = kRepNextStates[p.state];
4029 else
4031 uint posSlot;
4032 mixin(RC_BIT_0!("&p.rc", "probs"));
4033 p.rc.range = range;
4034 p.state = kMatchNextStates[p.state];
4036 LenEnc_Encode(&p.lenProbs, &p.rc, len - LZMA_MATCH_LEN_MIN, posState);
4037 // --p->lenEnc.counter;
4039 dist -= LZMA_NUM_REPS;
4040 p.reps[3] = p.reps[2];
4041 p.reps[2] = p.reps[1];
4042 p.reps[1] = p.reps[0];
4043 p.reps[0] = dist + 1;
4045 p.matchPriceCount++;
4046 mixin(GetPosSlot!("dist", "posSlot"));
4047 // RcTree_Encode_PosSlot(&p->rc, p->posSlotEncoder[mixin(GetLenToPosState!"len")], posSlot);
4049 uint sym = cast(uint)posSlot + (1 << kNumPosSlotBits);
4050 range = p.rc.range;
4051 probs = p.posSlotEncoder[mixin(GetLenToPosState!"len")].ptr;
4054 CLzmaProb *prob = probs + (sym >> kNumPosSlotBits);
4055 uint bit = (sym >> (kNumPosSlotBits - 1)) & 1;
4056 sym <<= 1;
4057 mixin(RC_BIT!("&p.rc", "prob", "bit"));
4059 while (sym < (1 << kNumPosSlotBits * 2));
4060 p.rc.range = range;
4063 if (dist >= kStartPosModelIndex)
4065 uint footerBits = ((posSlot >> 1) - 1);
4067 if (dist < kNumFullDistances)
4069 uint base = ((2 | (posSlot & 1)) << footerBits);
4070 RcTree_ReverseEncode(&p.rc, p.posEncoders.ptr + base, footerBits, cast(uint)(dist /* - base */));
4072 else
4074 uint pos2 = (dist | 0xF) << (32 - footerBits);
4075 range = p.rc.range;
4076 // RangeEnc_EncodeDirectBits(&p->rc, posReduced >> kNumAlignBits, footerBits - kNumAlignBits);
4080 range >>= 1;
4081 p->rc.low += range & (0 - ((dist >> --footerBits) & 1));
4082 RC_NORM(&p->rc)
4084 while (footerBits > kNumAlignBits);
4088 range >>= 1;
4089 p.rc.low += range & (0 - (pos2 >> 31));
4090 pos2 += pos2;
4091 mixin(RC_NORM!"&p.rc");
4093 while (pos2 != 0xF0000000);
4096 // RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, posReduced & kAlignMask);
4099 uint m = 1;
4100 uint bit;
4101 bit = dist & 1; dist >>= 1; mixin(RC_BIT!("&p.rc", "p.posAlignEncoder.ptr + m", "bit")); m = (m << 1) + bit;
4102 bit = dist & 1; dist >>= 1; mixin(RC_BIT!("&p.rc", "p.posAlignEncoder.ptr + m", "bit")); m = (m << 1) + bit;
4103 bit = dist & 1; dist >>= 1; mixin(RC_BIT!("&p.rc", "p.posAlignEncoder.ptr + m", "bit")); m = (m << 1) + bit;
4104 bit = dist & 1; mixin(RC_BIT!("&p.rc", "p.posAlignEncoder.ptr + m", "bit"));
4105 p.rc.range = range;
4106 // p->alignPriceCount++;
4113 nowPos32 += cast(uint)len;
4114 p.additionalOffset -= len;
4116 if (p.additionalOffset == 0)
4118 uint processed;
4120 if (!p.fastMode)
4123 if (p->alignPriceCount >= 16) // kAlignTableSize
4124 FillAlignPrices(p);
4125 if (p->matchPriceCount >= 128)
4126 FillDistancesPrices(p);
4127 if (p->lenEnc.counter <= 0)
4128 LenPriceEnc_UpdateTables(&p->lenEnc, 1 << p->pb, &p->lenProbs, p->ProbPrices);
4130 if (p.matchPriceCount >= 64)
4132 FillAlignPrices(p);
4133 // { int y; for (y = 0; y < 100; y++) {
4134 FillDistancesPrices(p);
4135 // }}
4136 LenPriceEnc_UpdateTables(&p.lenEnc, cast(uint)1 << p.pb, &p.lenProbs, p.ProbPrices.ptr);
4138 if (p.repLenEncCounter <= 0)
4140 p.repLenEncCounter = REP_LEN_COUNT;
4141 LenPriceEnc_UpdateTables(&p.repLenEnc, cast(uint)1 << p.pb, &p.repLenProbs, p.ProbPrices.ptr);
4145 if (p.matchFinder.GetNumAvailableBytes(p.matchFinderObj) == 0)
4146 break;
4147 processed = nowPos32 - startPos32;
4149 if (maxPackSize)
4151 if (processed + kNumOpts + 300 >= maxUnpackSize
4152 || mixin(RangeEnc_GetProcessed_sizet!"&p.rc") + kPackReserve >= maxPackSize)
4153 break;
4155 else if (processed >= (1 << 17))
4157 p.nowPos64 += nowPos32 - startPos32;
4158 return CheckErrors(p);
4163 p.nowPos64 += nowPos32 - startPos32;
4164 return Flush(p, nowPos32);
4169 enum kBigHashDicLimit = (cast(uint)1 << 24);
4171 private SRes LzmaEnc_Alloc(CLzmaEnc *p, uint keepWindowSize, ISzAllocPtr alloc, ISzAllocPtr allocBig)
4173 uint beforeSize = kNumOpts;
4174 uint dictSize;
4176 if (!RangeEnc_Alloc(&p.rc, alloc))
4177 return SZ_ERROR_MEM;
4180 uint lclp = p.lc + p.lp;
4181 if (!p.litProbs || !p.saveState.litProbs || p.lclp != lclp)
4183 LzmaEnc_FreeLits(p, alloc);
4184 p.litProbs = cast(CLzmaProb *)ISzAlloc_Alloc(alloc, (cast(uint)0x300 << lclp) * CLzmaProb.sizeof);
4185 p.saveState.litProbs = cast(CLzmaProb *)ISzAlloc_Alloc(alloc, (cast(uint)0x300 << lclp) * CLzmaProb.sizeof);
4186 if (!p.litProbs || !p.saveState.litProbs)
4188 LzmaEnc_FreeLits(p, alloc);
4189 return SZ_ERROR_MEM;
4191 p.lclp = lclp;
4195 (p.matchFinderBase).bigHash = cast(ubyte)(p.dictSize > kBigHashDicLimit ? 1 : 0);
4198 dictSize = p.dictSize;
4199 if (dictSize == (cast(uint)2 << 30) ||
4200 dictSize == (cast(uint)3 << 30))
4202 /* 21.03 : here we reduce the dictionary for 2 reasons:
4203 1) we don't want 32-bit back_distance matches in decoder for 2 GB dictionary.
4204 2) we want to elimate useless last MatchFinder_Normalize3() for corner cases,
4205 where data size is aligned for 1 GB: 5/6/8 GB.
4206 That reducing must be >= 1 for such corner cases. */
4207 dictSize -= 1;
4210 if (beforeSize + dictSize < keepWindowSize)
4211 beforeSize = keepWindowSize - dictSize;
4213 /* in worst case we can look ahead for
4214 max(LZMA_MATCH_LEN_MAX, numFastBytes + 1 + numFastBytes) bytes.
4215 we send larger value for (keepAfter) to MantchFinder_Create():
4216 (numFastBytes + LZMA_MATCH_LEN_MAX + 1)
4219 if (!MatchFinder_Create(&(p.matchFinderBase), dictSize, beforeSize,
4220 p.numFastBytes, LZMA_MATCH_LEN_MAX + 1 /* 21.03 */
4221 , allocBig))
4222 return SZ_ERROR_MEM;
4223 p.matchFinderObj = &(p.matchFinderBase);
4224 MatchFinder_CreateVTable(&(p.matchFinderBase), &p.matchFinder);
4226 return SZ_OK;
4229 private void LzmaEnc_Init(CLzmaEnc *p)
4231 uint i;
4232 p.state = 0;
4233 p.reps[0] =
4234 p.reps[1] =
4235 p.reps[2] =
4236 p.reps[3] = 1;
4238 RangeEnc_Init(&p.rc);
4240 for (i = 0; i < (1 << kNumAlignBits); i++)
4241 p.posAlignEncoder[i] = kProbInitValue;
4243 for (i = 0; i < kNumStates; i++)
4245 uint j;
4246 for (j = 0; j < LZMA_NUM_PB_STATES_MAX; j++)
4248 p.isMatch[i][j] = kProbInitValue;
4249 p.isRep0Long[i][j] = kProbInitValue;
4251 p.isRep[i] = kProbInitValue;
4252 p.isRepG0[i] = kProbInitValue;
4253 p.isRepG1[i] = kProbInitValue;
4254 p.isRepG2[i] = kProbInitValue;
4258 for (i = 0; i < kNumLenToPosStates; i++)
4260 CLzmaProb *probs = p.posSlotEncoder[i].ptr;
4261 uint j;
4262 for (j = 0; j < (1 << kNumPosSlotBits); j++)
4263 probs[j] = kProbInitValue;
4267 for (i = 0; i < kNumFullDistances; i++)
4268 p.posEncoders[i] = kProbInitValue;
4272 uint num = cast(uint)0x300 << (p.lp + p.lc);
4273 uint k;
4274 CLzmaProb *probs = p.litProbs;
4275 for (k = 0; k < num; k++)
4276 probs[k] = kProbInitValue;
4280 LenEnc_Init(&p.lenProbs);
4281 LenEnc_Init(&p.repLenProbs);
4283 p.optEnd = 0;
4284 p.optCur = 0;
4287 for (i = 0; i < kNumOpts; i++)
4288 p.opt[i].price = kInfinityPrice;
4291 p.additionalOffset = 0;
4293 p.pbMask = (cast(uint)1 << p.pb) - 1;
4294 p.lpMask = (cast(uint)0x100 << p.lp) - (cast(uint)0x100 >> p.lc);
4296 // p->mf_Failure = False;
4300 private void LzmaEnc_InitPrices(CLzmaEnc *p)
4302 if (!p.fastMode)
4304 FillDistancesPrices(p);
4305 FillAlignPrices(p);
4308 p.lenEnc.tableSize =
4309 p.repLenEnc.tableSize =
4310 p.numFastBytes + 1 - LZMA_MATCH_LEN_MIN;
4312 p.repLenEncCounter = REP_LEN_COUNT;
4314 LenPriceEnc_UpdateTables(&p.lenEnc, cast(uint)1 << p.pb, &p.lenProbs, p.ProbPrices.ptr);
4315 LenPriceEnc_UpdateTables(&p.repLenEnc, cast(uint)1 << p.pb, &p.repLenProbs, p.ProbPrices.ptr);
4318 private SRes LzmaEnc_AllocAndInit(CLzmaEnc *p, uint keepWindowSize, ISzAllocPtr alloc, ISzAllocPtr allocBig)
4320 uint i;
4321 for (i = kEndPosModelIndex / 2; i < kDicLogSizeMax; i++)
4322 if (p.dictSize <= (cast(uint)1 << i))
4323 break;
4324 p.distTableSize = i * 2;
4326 p.finished = 0/*False*/;
4327 p.result = SZ_OK;
4328 int rinres = LzmaEnc_Alloc(p, keepWindowSize, alloc, allocBig);
4329 if (rinres != 0) return rinres;
4330 LzmaEnc_Init(p);
4331 LzmaEnc_InitPrices(p);
4332 p.nowPos64 = 0;
4333 return SZ_OK;
4336 private SRes LzmaEnc_Prepare(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream,
4337 ISzAllocPtr alloc, ISzAllocPtr allocBig)
4339 CLzmaEnc *p = cast(CLzmaEnc *)pp;
4340 (p.matchFinderBase).stream = inStream;
4341 p.needInit = 1;
4342 p.rc.outStream = outStream;
4343 return LzmaEnc_AllocAndInit(p, 0, alloc, allocBig);
4346 private void LzmaEnc_SetInputBuf(CLzmaEnc *p, const ubyte *src, usize srcLen)
4348 (p.matchFinderBase).directInput = 1;
4349 (p.matchFinderBase).bufferBase = cast(ubyte *)src;
4350 (p.matchFinderBase).directInputRem = srcLen;
4353 private SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const ubyte *src, usize srcLen,
4354 uint keepWindowSize, ISzAllocPtr alloc, ISzAllocPtr allocBig)
4356 CLzmaEnc *p = cast(CLzmaEnc *)pp;
4357 LzmaEnc_SetInputBuf(p, src, srcLen);
4358 p.needInit = 1;
4360 LzmaEnc_SetDataSize(pp, srcLen);
4361 return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig);
4364 private void LzmaEnc_Finish(CLzmaEncHandle pp)
4366 //(void)pp;
4370 enum SanityMagic = 0xb0f0debeU;
4372 struct CLzmaEnc_SeqOutStreamBuf {
4373 ISeqOutStream vt;
4374 version(LZMA_SANITY_MAGIC) {
4375 usize magic;
4377 ubyte *data;
4378 usize rem;
4379 BoolInt overflow;
4384 #define MY_offsetof(type, m) ((size_t)&(((type *)0)->m))
4385 #define MY_container_of(ptr, type, m) ((type *)(void *)((char *)(void *)(1 ? (ptr) : &((type *)0)->m) - MY_offsetof(type, m)))
4386 #define CONTAINER_FROM_VTBL(ptr, type, m) MY_container_of(ptr, type, m)
4389 private usize SeqOutStreamBuf_Write(ISeqOutStream* pp, const(void)* data, usize size) nothrow
4391 //CLzmaEnc_SeqOutStreamBuf *p = CONTAINER_FROM_VTBL(pp, CLzmaEnc_SeqOutStreamBuf, vt);
4392 CLzmaEnc_SeqOutStreamBuf* p = cast(CLzmaEnc_SeqOutStreamBuf*)(cast(ubyte*)pp-CLzmaEnc_SeqOutStreamBuf.vt.offsetof);
4393 version(LZMA_SANITY_MAGIC) {
4394 assert(p.magic == SanityMagic);
4396 if (p.overflow) return 0; // ignore all writes
4397 if (p.rem < size) {
4398 size = p.rem;
4399 p.overflow = 1/*True*/;
4400 if (size == 0) return 0;
4402 import core.stdc.string : memcpy;
4403 memcpy(p.data, data, size);
4404 p.rem -= size;
4405 p.data += size;
4406 return size;
4410 //MY_NO_INLINE
4411 private SRes LzmaEnc_Encode2(CLzmaEnc *p, ICompressProgress *progress)
4413 SRes res = SZ_OK;
4415 for (;;)
4417 res = LzmaEnc_CodeOneBlock(p, 0, 0);
4418 if (res != SZ_OK || p.finished)
4419 break;
4420 if (progress)
4422 //res = ICompressProgress_Progress(progress, p.nowPos64, mixin(RangeEnc_GetProcessed!"&p.rc"));
4423 res = progress.Progress(progress, p.nowPos64, mixin(RangeEnc_GetProcessed!"&p.rc"));
4424 if (res != SZ_OK)
4426 res = SZ_ERROR_PROGRESS;
4427 break;
4432 LzmaEnc_Finish(p);
4435 if (res == SZ_OK && !Inline_MatchFinder_IsFinishedOK(&(p.matchFinderBase)))
4436 res = SZ_ERROR_FAIL;
4440 return res;
4444 //==========================================================================
4446 // LzmaEnc_Encode
4448 //==========================================================================
4449 public SRes LzmaEnc_Encode (CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream,
4450 ICompressProgress *progress, ISzAllocPtr alloc, ISzAllocPtr allocBig)
4452 int rinres = LzmaEnc_Prepare(pp, outStream, inStream, alloc, allocBig);
4453 if (rinres != 0) return rinres;
4454 return LzmaEnc_Encode2(cast(CLzmaEnc *)pp, progress);
4458 //==========================================================================
4460 // LzmaEnc_WriteProperties
4462 //==========================================================================
4463 public SRes LzmaEnc_WriteProperties (CLzmaEncHandle pp, ubyte* props, uint* size) @nogc {
4464 if (*size < LZMA_PROPS_SIZE) return SZ_ERROR_PARAM;
4465 *size = LZMA_PROPS_SIZE;
4467 const(CLzmaEnc)* p = cast(const(CLzmaEnc)*)pp;
4468 immutable uint dictSize = p.dictSize;
4469 uint v;
4470 props[0] = cast(ubyte)((p.pb * 5 + p.lp) * 9 + p.lc);
4472 // we write aligned dictionary value to properties for lzma decoder
4473 if (dictSize >= (cast(uint)1 << 21)) {
4474 const uint kDictMask = (cast(uint)1 << 20) - 1;
4475 v = (dictSize + kDictMask) & ~kDictMask;
4476 if (v < dictSize) v = dictSize;
4477 } else {
4478 uint i = 11 * 2;
4479 do {
4480 v = cast(uint)(2 + (i & 1)) << (i >> 1);
4481 i++;
4482 } while (v < dictSize);
4485 SetUi32(props + 1, v);
4486 return SZ_OK;
4490 //==========================================================================
4492 // LzmaEnc_IsWriteEndMark
4494 //==========================================================================
4495 public uint LzmaEnc_IsWriteEndMark (CLzmaEncHandle pp) @nogc {
4496 return cast(uint)(cast(CLzmaEnc *)pp).writeEndMark;
4500 //==========================================================================
4502 // LzmaEnc_MemEncode
4504 //==========================================================================
4505 public SRes LzmaEnc_MemEncode (CLzmaEncHandle pp, ubyte* dest, usize* destLen, const(ubyte)* src, usize srcLen,
4506 int writeEndMark, ICompressProgress *progress, ISzAllocPtr alloc, ISzAllocPtr allocBig)
4508 SRes res;
4509 CLzmaEnc *p = cast(CLzmaEnc *)pp;
4511 CLzmaEnc_SeqOutStreamBuf outStream;
4512 version(LZMA_SANITY_MAGIC) {
4513 outStream.magic = SanityMagic;
4516 //outStream.vt.Write = &SeqOutStreamBuf_Write;
4517 outStream.vt.Write = delegate usize (ISeqOutStream* pp, const(void)* data, usize size) nothrow {
4518 return SeqOutStreamBuf_Write(pp, data, size);
4521 outStream.data = dest;
4522 outStream.rem = *destLen;
4523 outStream.overflow = 0/*False*/;
4525 p.writeEndMark = writeEndMark;
4526 p.rc.outStream = &outStream.vt;
4528 res = LzmaEnc_MemPrepare(pp, src, srcLen, 0, alloc, allocBig);
4530 if (res == SZ_OK)
4532 res = LzmaEnc_Encode2(p, progress);
4533 if (res == SZ_OK && p.nowPos64 != srcLen)
4534 res = SZ_ERROR_FAIL;
4537 *destLen -= outStream.rem;
4538 if (outStream.overflow)
4539 return SZ_ERROR_OUTPUT_EOF;
4540 return res;
4544 //==========================================================================
4546 // LzmaEncode
4548 //==========================================================================
4549 public SRes LzmaEncode (ubyte* dest, usize* destLen, const(ubyte)* src, usize srcLen,
4550 const(CLzmaEncProps)* props, ubyte* propsEncoded, uint* propsSize,
4551 int writeEndMark, ICompressProgress *progress, ISzAllocPtr alloc, ISzAllocPtr allocBig)
4553 CLzmaEnc *p = cast(CLzmaEnc *)LzmaEnc_Create(alloc);
4554 SRes res;
4555 if (!p)
4556 return SZ_ERROR_MEM;
4558 res = LzmaEnc_SetProps(p, props);
4559 if (res == SZ_OK)
4561 res = LzmaEnc_WriteProperties(p, propsEncoded, propsSize);
4562 if (res == SZ_OK)
4563 res = LzmaEnc_MemEncode(p, dest, destLen, src, srcLen,
4564 writeEndMark, progress, alloc, allocBig);
4567 LzmaEnc_Destroy(p, alloc, allocBig);
4568 return res;